Client · 2026 · Design and engineering
UKEX Global
A crypto and gift card trading business rebuilt around one idea: let people see the rate before asking them to trust you.
The problem
UKEX buys and sells crypto and gift cards in Ghana. Customers send money or an asset first and trust the business to send the other side back. There is no escrow and nothing standing behind it.
The client wanted polished and premium. What they had was a bought Elementor theme, and it looked like one.
It also did not show its rates. For a trading business that is a strange omission. The featured trades section displayed 100 percent for every asset, Bitcoin through to Steam gift cards.
So every customer conversation started with what is your rate. The client could not change a price without editing the site. Nothing on the page targeted the searches bringing people in.
What I decided
The first decision was to cut public accounts. The budget was tight and accounts were the most expensive thing nobody had asked for: no user model, no sessions, no password reset to build and support. Nobody creating a login to check a rate wanted one.
That settled the shape of the system. One writer, the client in the admin area. Everyone else reads.
Polished and premium needed translating into something I could apply. No gradients. No top accent lines. No stock iconography. No decorative arrows implying a link that is not there. Restrained shadows. No component that exists because the template had one.
Dark mode was in scope from the start, so every surface got designed twice.
What changed
Before
The old hero. A photograph, an eight years of experience badge, and three ways to start a conversation.
After
The rebuild. What the business does, then an offer to show you its prices.
The new flow
None of this existed before. The old site had no rates page and no trade flow.
- 01
See a rate
A rate preview on the homepage, so the question people arrive with is answered on the first screen.
- 02
Compare it
The full table, filtered by category and sortable either way. Crypto and gift cards render different columns, because a gift card needs region, format and reference and Bitcoin does not.
- 03
Build a trade and send it
Trade type, asset, amount, payout method. Submitting composes the order into a prefilled WhatsApp message and opens it. The desk gets a complete request instead of an opening question.
Improvements after QA
The public hero was linking to the admin portal. Removed.
The gift cards tab was showing crypto assets, because the filter was not defaulting to the gift card type. Fixed.
The crypto table was rendering region, format and reference columns. Those are gift card fields. The table now detects a crypto-only view and drops them.
Switching tabs made the page jump, because a form or table changing height pushed everything below it. Reserved heights in the quick preview, the live rates block, the trade page and the admin form.
Switching from a buy order to a sell order wiped the form, and so did switching between two gift cards with the same fields. Both now keep any selection still valid.
In dark mode the buttons regressed to pure black, then the fix leaked into the tabs and needed its own class. The hero video also showed a faded band across its top quarter, dark mode only, which took isolating the video and overlay into their own compositing layer.
Floating thumbnails in the hero and a still background image were both tried and reverted.
Architecture
Next.js 16 on the App Router, Vercel, PostgreSQL through Prisma. With no public accounts the customer-facing surface is cacheable pages with no session handling anywhere.
Rates are set by the client, not pulled from a market feed. The spread is a commercial decision that moves with conditions and it belongs to the person whose business it is. Each rate carries a buy figure, a sell figure, a source and an active flag, and public pages read only what is live and active.
One writer, many readers, so public rate reads are cached and tagged and every admin write invalidates the tag. The site serves at static speed and goes stale when the client changes a number rather than on a timer.
The crypto ticker is separate. An internal API route fetches upstream prices on its own window and the client polls that route. If upstream fails the route answers with an error and shorter cache headers, and the interface keeps the last good numbers rather than blanking.
Admin is email and password with bcrypt, sessions in the database with hashed tokens, and an http-only cookie. The pages render per request and check the session server-side. Disallowing the path in robots.txt is a crawling instruction, not access control.
Automatic database migrations during the production build were added, retried, then taken back out. A build step that mutates a production database is a bad place to find out you were wrong.
Search was built the same way as the rest: five routes with their own metadata, two of them landing pages for where to buy crypto in Ghana and where to buy gift cards in Ghana. Structured data marks UKEX as a financial service, the guides carry FAQ and breadcrumb data, and admin and API paths are disallowed.
Thank you for reading all the way through. I appreciate the time. If this sounds like the kind of work you need, do get in touch. I’d love to hear what you’re building.