tia/drizzle
Mannu 38bb5af01c feat: collect optional user phone number (onboarding + profile)
Google OAuth cannot provide phone numbers (no scope returns them reliably),
so we collect it ourselves. Optional, stored unverified.

- Migration 0011: users.phone text column (+ debug-migration hot-apply step)
- schema/auth.ts: add phone field
- onboarding: optional phone input on step 1; saved to users.phone via the
  onboarding API (normalised: leading + then digits, 8-15 digit validation)
- profile page: editable Phone field; loaded from + saved to /api/auth/profile
- /api/auth/profile: GET returns phone; POST accepts & normalises it
  (empty string clears, undefined leaves untouched)

Capture point covers both Google and email/password signups since both land
on onboarding. Verification (OTP) and marketing-consent flag intentionally
deferred per product decision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 21:25:00 +05:30
..
manual feat(wardrobe): add complete wardrobe feature (W0–W9) 2026-05-23 18:09:22 +05:30
meta feat: collect optional user phone number (onboarding + profile) 2026-05-31 21:25:00 +05:30
0000_baseline_prod_2026_05_19.sql chore(db): regenerate baseline migration from corrected schema 2026-05-23 12:25:20 +05:30
0001_wardrobe_tables.sql feat(wardrobe): add complete wardrobe feature (W0–W9) 2026-05-23 18:09:22 +05:30
0002_outfits_table.sql feat(wardrobe): add complete wardrobe feature (W0–W9) 2026-05-23 18:09:22 +05:30
0003_circles.sql Fix migration: add statement-breakpoints + use superuser URL 2026-05-24 01:23:06 +05:30
0004_circle_invite_email.sql feat: email-based circle invites with in-app notifications 2026-05-24 02:05:10 +05:30
0005_email_verification.sql feat: email verification + Google OAuth 2026-05-24 12:56:02 +05:30
0006_family_invites_missing_cols.sql fix(db): add missing display_name and accepted_at columns to family_invites 2026-05-24 14:21:57 +05:30
0007_subscription_status.sql feat(quota): storage quota + family-member limits for free tier 2026-05-27 23:21:11 +05:30
0008_pediatrician_name.sql feat(settings): add Pediatrician Name field alongside phone 2026-05-28 00:49:05 +05:30
0009_notifications.sql feat: DB-backed notification system with vaccine + activity nudges 2026-05-29 09:33:51 +05:30
0010_error_events.sql Add admin observability: error tracking, audit viewer, AI metrics, health 2026-05-30 00:27:07 +05:30
0011_user_phone.sql feat: collect optional user phone number (onboarding + profile) 2026-05-31 21:25:00 +05:30
README.md chore(db): regenerate baseline migration from corrected schema 2026-05-23 12:25:20 +05:30

Tia — Database Migrations

This folder is source code and is committed to git. It is consumed by the deploy pipeline (pnpm db:migrate, run on container start — see Dockerfile).

Baseline reset — 2026-05-19

The project's first 16 migrations (00000015) plus a manual/ folder were hand-rolled SQL applied directly via the Dokploy database terminal. They were never run through Drizzle's migrator, so:

  • prod had no __drizzle_migrations tracking table;
  • the drizzle/ folder was gitignored, so migration SQL never reached the server;
  • schema.ts had drifted well behind the real production schema.

To fix this we performed a Path A baseline reset:

  1. pg_dump backup of prod taken and stored off-server.
  2. drizzle-kit pull introspected the live prod schema (35 tables).
  3. src/db/schema/*.ts was rewritten to match prod exactly.
  4. Legacy migrations were archived to _archived_pre_baseline_2026-05-19/ (also retained in git history).
  5. A single fresh baseline — 0000_baseline_prod_2026_05_19.sql — was generated and verified column-for-column against the introspected prod schema.
  6. Prod's drizzle.__drizzle_migrations table was created and seeded with one row marking 0000_baseline_prod_2026_05_19 as already applied, so the migrator treats prod as up-to-date and runs nothing on the next deploy.

Normal workflow from here

# 1. Edit src/db/schema/*.ts
# 2. Generate a migration from the diff:
pnpm db:generate            # writes drizzle/000N_<name>.sql
# 3. Review the generated SQL by eye.
# 4. Apply locally against the dev DB:
pnpm db:migrate
# 5. Commit schema + migration together, then push.
#    Dokploy redeploys; the migrator applies it in prod on container start.

Hard rules

  • Never edit a migration file after it has been pushed. Fix-forward with a new migration instead.
  • Never run schema-changing SQL directly against prod. It becomes drift.
  • The drizzle/ folder must stay out of .gitignore.

RLS policies

Five log tables (feeds, diapers_logs, sleeps, vaccinations, growth) plus children / family_members carry row-level-security policies in prod. These are not modelled in the pgTable definitions and are managed separately in the database. Drizzle migrations will not recreate them — keep that in mind if you ever rebuild the DB from scratch.