Octopus Handover Wiki
Single source of truth for taking over the Octopus voucher/topup/eSIM platform — architecture, infrastructure, Cloudflare, vendors, and operations.
Welcome. This wiki is the handover pack for the Octopus platform. It was written to get a new maintainer productive without prior context — how the system is built, where every piece runs, how to deploy it, and the hard-won gotchas that are not obvious from the code.
Read the safety rules first
Two absolute rules were followed while building this system and must continue to be:
- Never run ad-hoc
INSERT/UPDATE/DELETEagainst the production database. All data changes go through the app or migrations. UseSELECTfor investigation only. - Migrations are applied by a human operator, never auto-applied on app start. Same for D1 migrations on the Cloudflare side.
What Octopus is
Octopus is a high-performance, multi-tenant B2B commerce & fulfilment platform written in Go. Clients (tenants) buy digital products through one API:
- Vouchers / gift cards — the original line (the "Octopus Cards" brand).
- Direct top-ups — mobile & gaming recharge.
- eSIM — data plans.
- Payouts — outbound money to beneficiaries.
Each vertical is toggled by a feature flag, so a deployment can ship any subset. The platform sits between clients (who consume the /api/v1 API or the client portal) and a fleet of vendor adapters (upstream suppliers: DT One, SEAGM, Runa, NeoCurrency, EpinForce, etc.).
The cardinal product rule
To the customer, Octopus does everything itself. Vendor topology (brand names, the words "vendor/upstream/supplier") is never exposed in any client-facing surface — API responses, docs, emails, the client panel, or the claim page. This is a hard rule enforced throughout the code and data model. See the Memory Appendix.
System context
The 60-second mental model
One Go binary, many roles
A single compiled binary runs the HTTP API, admin UI, background workers, and cron scheduler — selected by subcommand. run-all runs them together in production.
Two live environments on shared data
PROD and SANDBOX run side-by-side on two Hetzner servers, sharing Postgres/Valkey/RabbitMQ containers but namespaced by DB name, cache prefix, and queue exchange.
Cloudflare fronts everything
DNS, edge caching, the claim Worker (Grasshopper), and the marketing/docs sites all live in one Cloudflare account. The origin servers sit behind it.
Vendors are pluggable adapters
Every supplier is a Go adapter behind a factory, keyed by a short vendor.code. Credentials live in the DB, not env files.
Where things run (at a glance)
| Surface | Runs on | Domain |
|---|---|---|
| Go API + Admin (PROD) | Hetzner 65.109.119.112, systemd | api.octopuscards.io, warden.octopuscards.io |
| Go API + Admin (SANDBOX) | Hetzner 94.130.137.222, systemd | sandbox-api.*, sandbox-warden.* |
| Client portal (Next.js) | same servers, systemd Node | app.octopuscards.io, sandbox-app.* |
| Claim page (Grasshopper) | Cloudflare Workers | claim.octopuscards.io, sandbox-claim.* |
| Marketing site | Cloudflare Pages | octopuscards.io, www.* |
| Developer docs | Cloudflare Pages | developer.octopuscards.io |
| Observability (SigNoz) | 94.130.137.222 | telemetry.octopuscards.io (UI), otel.* (ingest) |
How to use this wiki
Read Start Here first. It's the map and compass — how the 11 sections are organized, reading paths by goal (onboarding, firefighting, tracing an order, following the money, touching a vendor, changing the API, deploying), and the conventions (file:line citations, Callouts, the 🔴🟠🟢 index, the memory appendix). This wiki is exhaustive by design; read it by goal, not front-to-back.
Quick jumps:
- New to the codebase? Start Here → Onboarding → Architecture.
- What's broken / what to fix first? Known Issues — the ranked triage index of every finding.
- Operating the system? Operations & Runbooks and Infrastructure.
- Integrating a vendor? Vendors.
- Everything the previous maintainer learned is preserved verbatim in the Memory Appendix — decisions, spec-drift notes, and house rules that aren't in the code.
This wiki itself is a Fumadocs (Next.js) app in frontend/handover-wiki/. Run it with bun run dev from that directory. It has no deploy pipeline yet — see Frontend Apps.