Obsidian_vault/30 - Projects/Tia/Tia - Architecture.md
2026-06-07 14:00:01 +00:00

2 KiB

type parent status tags
project-doc Tia verified
tia
architecture
engineering

🏗️ Tia — Architecture

Verified from CLAUDE.md + memory files.

Stack

Next.js 16 (App Router, Turbopack) · PostgreSQL 16 + pgvector (pgvector/pgvector:pg18 on prod) · Drizzle ORM · LiteLLM gateway → MiniMax (minimax-2.7) · Cloudflare R2 · Resend · Tailwind v4 · Dokploy (auto-migrate on deploy).

Route groups (Decision Log#TD-005)

  • (marketing)//, /pricing, /privacy, /termsstatic, no DB/auth imports
  • (app)/ → authenticated app with ThemeProvider + FamilyProvider + BottomNav; dashboard at /home

Auth

  • User: /loginPOST /api/auth/signin (bcrypt) → session row → httpOnly tia_session; routes use requireFamily()
  • Admin: /admin-logintia_admin_session; admin layout is a server component calling verifyAdminSession()

Data & context

  • FamilyProvider resolves family/child from session: { familyId, child, children, tier, memberCount, updateChildImage }
  • Quota logic in src/lib/quota.ts (pure fns + queries); usage always derived via SUM (Decision Log#TD-001)

Migrations (the big gotcha) (Decision Log#TD-003)

  • migrate.mjs runs before server.js; reads all SQL in drizzle/, applies any not in __drizzle_migrations
  • when must be Date.now() (> 1779539431897) or Drizzle silently skips it
  • Hot-apply via POST /api/debug-migration (header x-run-migration: yes), idempotent steps

Media (R2) (Decision Log#TD-004)

  • 3-step upload: init → server-proxied PUT /api/upload → save URL
  • Never direct cross-origin PUT; never raw *.r2.dev in <img> — use /api/img?key= proxy

Observability (admin)

error_events table + logError() + POST /api/errors; /admin/{health,errors,audit,ai} over audit_log, ai_usage (p95 via percentile_cont).

Tia · Tia - Decisions · Self-Hosting · Engineering Overview