SolveMY
A trilingual local-services marketplace for Malaysia on Android, iOS and web. Customers post requests; verified providers and merchants quote and chat.
- Role
- CTO and hands-on engineering lead
- Type
- My own product
- Period
- Jan 2026 to Present
- Status
- Live on web and Google Play · submitted to the App Store
SolveMY connects customers with verified service providers and merchants (repairs, cleaning, transport, beauty, tuition and more) in English, Malay and Chinese. I built and run the whole stack: a layered Go REST API on PostgreSQL with PostGIS for location search, a Next.js 16 website with server-rendered SEO pages, and a Flutter app for Android and iOS. Production runs on a self-managed Hetzner server with Docker, nginx and Let's Encrypt, Cloudflare R2 for storage and CDN, and Vercel for the web, with isolated staging and production, encrypted nightly backups, CI quality gates and monitoring.
The problem
Finding a reliable local service provider in Malaysia means asking around in three languages. SolveMY is a marketplace where customers post a request and verified providers and merchants quote and chat. It needed a website, Android and iOS apps, an admin side and the operations behind them, and there was no engineering team. There was me.
Why it was hard
- Three client surfaces (web, Android, iOS) against one API, in English, Malay and Chinese.
- Location search: radius and nearest-first across providers, merchants and requests.
- Sessions that can be revoked per device, and chat that still behaves on old app versions.
- Two app stores with different rules on pricing and payments, served from one codebase.
- Running production alone: deployments, backups, monitoring and incident response.
Architecture
One layered Go service (domain, services, repositories, HTTP) on PostgreSQL with PostGIS. A Next.js website with server-rendered pages. A Flutter app for Android and iOS. Production runs on a self-managed server with Docker, nginx and Let's Encrypt, with Cloudflare R2 for storage and backups and Vercel for the website. Staging and production are isolated.
- Go
- chi
- pgx
- PostgreSQL 16
- PostGIS
- Next.js 16
- TanStack Query
- NextAuth
- Flutter
- Riverpod
- Docker
- nginx
- Cloudflare R2
- Vercel
- Firebase (FCM / APNs)
- Twilio
- Google Maps Platform
- Claude API
- GitHub Actions
- Sentry
What I built
CTO and hands-on engineering lead
- 01Designed a layered Go API (domain, services, repositories, HTTP) with chi and pgx: 235 endpoints across 31 domain services, 1,006 test functions, golangci-lint and gofmt gates in CI.
- 02PostGIS radius and nearest-first search for providers, merchants and requests, plus a merchant map with clustered pins on the app and the website.
- 03Session security: short access tokens with rotating opaque refresh tokens, reuse detection that revokes the whole token family, per-device sessions and a 90-day sliding lifetime.
- 04AI search on the Claude API: free text in English, Malay or Chinese, or a photo, mapped to a category and sub-area.
- 05Shipped the 48-screen Flutter app to Google Play and submitted it to the App Store, with one codebase made compliant with both stores' pricing rules.
- 06Run production on Hetzner with Docker, nginx and Let's Encrypt; staging as a true canary; nightly AES-256 encrypted backups to Cloudflare R2; Sentry, uptime and TLS-expiry alerts.
Decisions and challenges
One deployable, clean layers
235 endpoints across 31 domain services live in one Go service. One engineer can reason about it, and the boundaries are clean enough to split later if a team ever needs to.
PostgreSQL with PostGIS for search
Radius and nearest-first queries run in the database that already holds the data, instead of adding a separate search system to operate.
Rotating refresh tokens with reuse detection
Short access tokens and opaque refresh tokens that rotate. If an old token is ever reused, the whole token family is revoked.
Staging as a true canary, backups encrypted nightly
Every release goes through an isolated staging environment first. Backups are encrypted with AES-256 and shipped off the server every night.
Quality gates in CI
1,006 test functions, with lint and format checks that block a merge.
Stories worth telling
Push notifications silently failed on every device for ten days. I traced the FCM error codes to an APNs block attached to every message, made it iOS-only, removed duplicate pushes and added an admin endpoint that proves delivery per user.
The API went "down" when a TLS certificate expired on a domain that had moved hosts. I re-issued it, restored auto-renew with an nginx reload hook, and added a daily expiry alert so it can't happen silently again.
Race-safe "once per person per day" analytics: a day-table insert with ON CONFLICT DO NOTHING inside a CTE, so repeat taps never double count.
Delete-for-everyone in chat that still works on old app versions: soft delete, with deleted messages served as plain text plus a flag.
Verified outcomes
- Live on the web and Google Play, and submitted to the App Store.
- 235 REST endpoints, 31 domain services, 1,006 Go test functions and 116 SQL migrations.
- 48 app screens and 75 web routes in three languages.
- Production run by one engineer, with monitoring, alerts and nightly encrypted backups.
Numbers
- 235 REST endpoints
- 1,006 Go test functions
- 116 SQL migrations
- 48 app screens · 75 web routes
- 3 languages
- 834 commits in 8 months
What this shows a client
This is the closest thing in my history to a founder engagement: one engineer taking a product from an empty repository to live apps, including the unglamorous parts. It is what I mean by technical ownership.
Tell me what you are building.
A few lines are enough: what it is, where it stands today, and what you need from an engineer. The form is just below, or email me if you prefer. I reply within two working days.