Path A baseline reconciliation. drizzle-kit pull against tia_prod showed
prod had drifted well past schema.ts because legacy hand-rolled migrations
0003-0015 wrote to the DB but were never reflected back into TypeScript.
Shared-table drift fixed:
- users: + password_hash, + password_updated_at
- families: + tier, + max_children, + max_members
- children: col is 'stage' (kept JS key currentStage -> stage);
'image_url' not 'profile_photo_url'; birth_date is DATE;
sex nullable; dropped phantom stage_overrides
- family_members: dropped phantom display_name
- family_invites: dropped phantom display_name, accepted_at
- audit_log: + resource_id, + resource_type; metadata -> jsonb; +5 indexes
- memories: + vision_tags (text[]), + vision_embedding (vector 1536)
- logs.ts: 'diapers' phantom table renamed to diapersLogs ('diapers_logs')
19 missing tables added across new files:
- admin.ts: admins, admin_sessions, password_resets
- support.ts: support_tickets, support_responses
- ai.ts: chat_sessions, chat_messages, ai_usage
- medical.ts: medicines, medication_doses, allergies, illness_logs, doctor_visits
- affiliate.ts: member_profiles, recommended_products, product_clicks
- logs.ts: + milestone_achievements
- audit.ts: + log_corrections
BUG FIX: schema/index.ts never re-exported ./logs — Drizzle was blind to
feeds/sleeps/vaccinations/growth/medications. Now exported.
Verified: tsc --noEmit has zero non-test errors. Dropped phantom columns
confirmed to have zero references in src/.
89 lines
3.5 KiB
TypeScript
89 lines
3.5 KiB
TypeScript
import {
|
|
pgTable,
|
|
text,
|
|
timestamp,
|
|
uuid,
|
|
varchar,
|
|
date,
|
|
index,
|
|
} from "drizzle-orm/pg-core";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Medical schema — aligned to PRODUCTION as of 2026-05-19 baseline.
|
|
// Tables: medicines, medication_doses, allergies, illness_logs, doctor_visits
|
|
// (legacy migrations 0003_medical_data, 0012_medical_doses).
|
|
//
|
|
// Note: `medicines` here is the per-child medicine list with reminder times.
|
|
// `medications` (in logs.ts) is a separate prescription-record table that
|
|
// predates it. Both exist in prod; keep them distinct.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const medicines = pgTable("medicines", {
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
childId: uuid("child_id").notNull(),
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
dose: varchar("dose", { length: 255 }),
|
|
notes: text("notes"),
|
|
reminderTime: varchar("reminder_time", { length: 10 }),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow(),
|
|
});
|
|
|
|
// Append-only dose administration log. Corrections go via log_corrections.
|
|
export const medicationDoses = pgTable(
|
|
"medication_doses",
|
|
{
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
medicineId: uuid("medicine_id").notNull(),
|
|
familyId: uuid("family_id").notNull(),
|
|
administeredAt: timestamp("administered_at", { withTimezone: true })
|
|
.defaultNow()
|
|
.notNull(),
|
|
administeredBy: uuid("administered_by"),
|
|
amountGiven: text("amount_given"),
|
|
notes: text("notes"),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
},
|
|
(table) => [
|
|
index("medication_doses_family_idx").on(table.familyId),
|
|
index("medication_doses_medicine_idx").on(table.medicineId),
|
|
]
|
|
);
|
|
|
|
export const allergies = pgTable("allergies", {
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
childId: uuid("child_id").notNull(),
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
severity: varchar("severity", { length: 50 }).default("mild"),
|
|
notes: text("notes"),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow(),
|
|
});
|
|
|
|
export const illnessLogs = pgTable("illness_logs", {
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
childId: uuid("child_id").notNull(),
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
startDate: date("start_date").notNull(),
|
|
endDate: date("end_date"),
|
|
notes: text("notes"),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow(),
|
|
});
|
|
|
|
export const doctorVisits = pgTable("doctor_visits", {
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
childId: uuid("child_id").notNull(),
|
|
doctorName: varchar("doctor_name", { length: 255 }).notNull(),
|
|
reason: varchar("reason", { length: 255 }),
|
|
visitDate: date("visit_date").notNull(),
|
|
notes: text("notes"),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow(),
|
|
});
|
|
|
|
export type Medicine = typeof medicines.$inferSelect;
|
|
export type MedicationDose = typeof medicationDoses.$inferSelect;
|
|
export type Allergy = typeof allergies.$inferSelect;
|
|
export type IllnessLog = typeof illnessLogs.$inferSelect;
|
|
export type DoctorVisit = typeof doctorVisits.$inferSelect;
|