Victor Ohiri
Corda
A connection service I’m building: a marketing site and an app with a dashboard for each role.
- Role
- Founder, design and development
- My part
- Every design and technical decision was mine.
- Stack
- HTML, CSS, JavaScript, Canvas 2D, Next.js, TypeScript, Supabase
- Elsewhere
- Visit the live site
01 / 08
The idea
Say what you need and get introduced to a real person who can help.
02 / 08
The problem
My own venture, so I wrote the brief. A client sends a request, an admin assigns a professional, the professional works the lead.
Two questions shaped most of it: how to take payment on a site with no backend, and how to keep each person’s requests private once there are accounts.

03 / 08
The approach
Two parts that feel like one: eight static pages that explain the idea and collect requests, and an app that holds the accounts.
04 / 08
The decisions
I kept the marketing site static: plain HTML, CSS and JavaScript with no build step and no backend, every page sharing one stylesheet and one script.
Payments are Flutterwave’s hosted payment links, so card details never touch the site and no extra script or security-policy exception is needed: each payment button is just a link.
Until a real payment link exists, a button stays clickable but says the service is launching soon and points to WhatsApp, and a leftover test link counts as unset, so nothing broken can go live by mistake.
A client’s first two requests are free. Flutterwave’s hosted plans have no free trial and the site has no accounts to count against, so the count is kept in the visitor’s own browser. It resets if they clear their data or change device, and every request still reaches my inbox, so I can honour or adjust the offer myself.
Professionals join free for good; Pro is ₦7,500 a month; after the first two, a client pays a flat ₦1,500 a request.
In the app the database is the security boundary, not the page: access rules are Row Level Security policies, so a client can’t read another client’s request even if a query in the page were wrong.
The role chosen at sign-up is copied into a profile by a trigger, and the form offers only client and professional. An admin option would let anyone claim it, because the form’s data comes from a browser nobody has checked, so I make admins by hand.
A client can change their own request only while it is pending, to cancel it; the policy stops them marking it completed or giving it to someone else.
Role redirects look the role up on every dashboard request. That is fine at this size; if it slows down, the next step is to carry the role in the sign-in token.
05 / 08
The design
A black ground, white ink and quiet glows. The marketing site is greyscale, and its imagery is a globe of white dots.

06 / 08
The build
Plain HTML, CSS and JavaScript for the site; Next.js and Supabase for the app.
The globe is a 2D canvas with no libraries. In the app, access rules live in the database, not the interface.
The marketing site took 44 commits over eleven days, 4 to 15 September 2026; the app is a first slice of seven commits on 14 and 15 September.
The app has sign-up with a role, password or magic-link sign-in (Google when it’s switched on), password reset, and a request dashboard for clients, professionals and admins.
- Site
- 8 static pages, plain HTML, CSS, JavaScript
- Globe
- 2D canvas, no libraries
- App
- Next.js 14, TypeScript, Supabase
- Sign-in
- Password, magic link; Google when enabled
- Roles
- Client, professional, admin
- Source
- Private repositories



07 / 08
The details
The three steps light up under the pointer. The FAQ opens one answer at a time.
08 / 08
Current state
The marketing site is built. Payments aren’t switched on yet. The app is a first slice: sign-up and a dashboard for each role.
The dashboards show mock data for now. What it needs to go live is mine to do: create the two payment links and the form endpoints, and put real data behind the dashboards.

Next project Portfolio, earlier version, 2026

Z3N





