Skip to content

Full-stack edge stack

This page documents the traveler-labs/core operator stack. Cursor rules under .cursor/rules/ mirror this policy for AI-assisted development.

LayerLocationNotes
Admin UIapps/adminVite + React + TanStack Query
Storefrontapps/webNext.js (separate repo slice when present)
Docsapps/docsAstro Starlight (this site)
API Workerworkers/esim-apiHono on Cloudflare Workers
Jobs Workerworkers/esim-jobsQueue consumers
Platform DBpackages/db-kitIdentity / tenant tables
Product DBpackages/db-esimeSIM domain tables + drizzle-zod
Shared schemaspackages/schemasRoute/body Zod for API edges
Admin shellpackages/admin-shellLayout, ProtectedRoute, DataTable
route → handler → service → repository → db
  • Routes wire HTTP paths and middleware only.
  • Handlers validate input (Zod / @hono/zod-validator) and map JSON responses.
  • Services orchestrate use-cases; repositories own Drizzle queries.

Every Worker API exports its RPC type at the entry:

export type AppType = typeof app;

Admin UI consumes it via:

import { createHonoRpcClient } from "@core-labs/api-client-kit/hono-client";
import type { EsimApiType } from "@traveler-labs/esim-api/rpc";
const client = createHonoRpcClient<EsimApiType>(baseUrl, { token });
const res = await client.api.v1.admin.dashboard.$get();

Implementation lives in apps/admin/src/lib/rpc-admin.ts. Auth endpoints (/auth/login, OTP) stay on plain fetch because they run before a session exists.

  • Operator login: email OTP → JWT (/api/v1/auth/login, /auth/otp/verify). Super admins may receive an instant token.
  • Admin gate: adminAuthMiddleware on /admin/* — Bearer JWT or legacy X-Internal-Api-Key.
  • Role checks: requireAdminRoles('super_admin') on sensitive mutations (settings secrets, partner create, market create/update).
  • Client guard: ProtectedRoute validates /admin/me before rendering the shell (no layout flash).
PackageZod export pathScope
@core-labs/db-kit./schema/zodIdentity / users
@traveler-labs/db-esim./schema/zodMarkets, products, orders, partners, campaigns

Derive insert/select schemas with drizzle-zod; extend with .pick() / .extend() for API DTOs in @traveler-labs/schemas when the HTTP shape differs from the table row.

  • Wrap the app in QueryClientProvider (apps/admin/src/main.tsx).
  • Reads: useQuery hooks in apps/admin/src/lib/queries/.
  • Mutations: useMutation hooks in apps/admin/src/lib/mutations/.
  • Prefer RPC helpers over hand-rolled fetch for /admin/*.
BindingResourcePurpose
DBcore-d1D1 SQLite
R2_PRIVATEcore-r2Private uploads (POST/GET /admin/uploads)
KV_CONFIGcore-kv-configOperator settings + email templates
KV_OTPcore-kv-otpAdmin OTP codes
QUEUE_*q-esim-*Async jobs (issue, notify, sync, …)

Production deploy is CI only (path-filtered deploy-*.yml + scripts/preflight-cloudflare.mjs). PR verify is .github/workflows/ci.yml (typecheck / lint / test / db:verify:local / OpenAPI). Local dev: wrangler dev -c wrangler.prod.toml --local.

Admin JWT is Worker secret AUTH_SECRET (not the template name JWT_SECRET).

Admin surfaces use @core-labs/admin-shell shadcn CSS variables (bg-background, text-foreground, bg-primary, …). Do not hardcode Tailwind palette classes or hex values in product pages.

  • 80-fullstack-edge-stack.mdc — stack overview (always applied in core)
  • 21-typescript-vite-react.mdc — Vite admin conventions
  • 25-admin-ui-design-system.mdc — admin-shell component policy
  • 30-api-hono-zod.mdc — Hono + Zod + RPC export