Back to work
Live in production2026Solo — Full-Stack (backend, frontend, infra, data migration, product)60% complete

OpCreative

Production fulfillment platform for print-on-demand sellers — a full rebuild of a legacy system with zero-downtime cutover and nightly checksum-verified delta sync.

Summary

OpCreative is a fulfillment platform for print-on-demand sellers, live in production at opcreative.us and replacing a client's legacy system. It's a Turborepo monorepo — a Next.js 16 (App Router) dashboard plus shared libs for database, auth, and types — written in TypeScript: ~80,000 lines of TS/TSX, plus 4,200 lines of SQL and a 1,900-line Prisma 7 schema (45 models, 24 enums, 48 migrations across 9 domain files). It runs on Vercel against Neon PostgreSQL, with Auth.js v5 (Google OAuth, password, and email OTP via Resend), Vercel Blob for files, and an embedded AI assistant on Moonshot's kimi-k3 through the Vercel AI SDK. Nine feature modules cover catalog, orders, fulfillment, inventory, finance, identity, support, platform services, and the assistant, across 38 pages and 14 API routes, fully internationalized into 6 languages (1,878 keys each, enforced by CI). The legacy system's live database delta-syncs into production nightly via cron with checksum verification and email alerting. Built solo in 328 commits since July 2026; the dashboard is live, catalog v2 is mid-flight, and the public storefront and multi-tenancy are planned.

Target user

Print-on-demand fulfillment operations and the sellers they serve. Sellers get a private dashboard for orders, catalog, and billing in their own language (6 locales); the ops team gets warehouse, inventory, procurement, and finance tooling in one system instead of spreadsheets plus an aging legacy app. Unlike off-the-shelf POD platforms, it models the client's actual bill-of-materials and multi-warehouse flow.

§ 01Stack
01Primary
Next.jsTypeScriptPostgreSQLPrismaTurborepo monorepo
02Infrastructure
VercelNeon PostgreSQLVercel BlobLegacy sync boxVercel Analytics + Speed Insights
03Integrations
Auth.jsResendMoonshot kimi-k3 via Vercel AI SDKStripe
04UI / Frontend
Tailwind CSSshadcn/ui on Base UI primitivesGeist design systemRechartsTanStack QuerySonner, cmdk, react-day-picker
§ 02Key features
  1. 01

    Nine domain modules (catalog, orders/fulfillment, inventory/BOM, finance, identity, support, platform, assistant, core) behind a shared guard/scope/audit kernel — every server action passes role-permission checks and writes an audit trail

  2. 02

    Options-as-data catalog v2 with deterministically generated SKUs (e.g. `HW-TRK-GK-LG__P-C`) so variants are data, not schema

  3. 03

    Bulk order upload: Excel intake with fuzzy product matching, validation, and per-row error reporting

  4. 04

    Full i18n in 6 locales (en, zh, vi, ja, ko, fr), 1,878 keys each, single-dictionary server-side loading with a CI gate that fails on untranslated or missing keys

  5. 05

    In-app AI assistant with tool access scoped to the user's permissions, structured output forced via tool calls (the model lacks native JSON mode), and a schema digest auto-generated from the Prisma files

  6. 06

    Database-backed search with pg_trgm indexes (627ms → 30ms) plus client-side fuzzy ranking

  7. 07

    Warehouse operations: stations, shipping labels, tracking, barcode/QR generation, PDF label pipelines

  8. 08

    Nightly checksum-verified delta sync from the client's live legacy database, with escalating email alerts on consecutive failures

§ 03Hardest problems
  1. Built a delta-sync pipeline (SQL diff scripts on a cron box, read-only access into the client's live DB via a jump host) with per-field checksums to detect drift and escalating email alerts on failed ticks. Trade-off accepted: the sync is one-way by convention and alerting catches failures, not silently-wrong data — a drift incident (82 bad rows over 11 days) led to the checksum method.

  2. Built generateStructured() — a forced tool call with toolChoice 'required' whose input schema is the desired output schema — plus a build step that parses the Prisma schema files into a context digest so the assistant knows the data model without hand-maintained docs. Trade-off: one extra round-trip shape versus swapping to a pricier model.

  3. Fixed with pg_trgm GIN indexes, restructured queries, cached dashboard stats, and tuning Neon's suspend timeout — search dropped 627ms → 30ms without adding a search service.

§ 04What I learned
  • L01
    A green build proves nothing about content.

    ~110 translation keys rotted because copied English passed tsc, eslint, and the build; only a CI check comparing values caught it. Anything a human can fake by copy-paste needs a semantic check, not a type check.

  • L02
    Editing the repo is not deploying.

    The sync box ran copies of the repo's scripts; 11 days of drift between them wrote 82 bad rows. Every artifact that runs off-repo needs a checksum comparison against source, or it will silently diverge.

  • L03
    Migrations are the only schema truth.

    Banning `prisma db push` entirely — every change is a reviewed, committed migration — is what made a prod database restored-from-snapshot locally, a legacy cutover, and 48 migrations coexist without a single schema-drift incident.

§ 05By the numbers
total loc
86292
typescript loc
80154
sql loc
4207
prisma schema loc
1931
git commits
328
dev started
2026-07-17
prisma models
45
prisma enums
24
db migrations
48
feature modules
9
dashboard pages
38
api routes
14
locales
6
i18n keys per locale
1878
test files
48
search latency improvement
627ms → 30ms
team size
1