queue-med/docs_ref/schema.ts

127 lines
5.9 KiB
TypeScript

import {
int,
mysqlEnum,
mysqlTable,
text,
timestamp,
varchar,
boolean,
bigint,
float,
json,
} from "drizzle-orm/mysql-core";
// ─── Users (médecins) ────────────────────────────────────────────────────────
export const users = mysqlTable("users", {
id: int("id").autoincrement().primaryKey(),
openId: varchar("openId", { length: 64 }).notNull().unique(),
name: text("name"),
email: varchar("email", { length: 320 }),
loginMethod: varchar("loginMethod", { length: 64 }),
role: mysqlEnum("role", ["user", "admin"]).default("user").notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
lastSignedIn: timestamp("lastSignedIn").defaultNow().notNull(),
});
export type User = typeof users.$inferSelect;
export type InsertUser = typeof users.$inferInsert;
// ─── Subscriptions ───────────────────────────────────────────────────────────
export const subscriptions = mysqlTable("subscriptions", {
id: int("id").autoincrement().primaryKey(),
userId: int("userId").notNull(),
stripeCustomerId: varchar("stripeCustomerId", { length: 128 }),
stripeSubscriptionId: varchar("stripeSubscriptionId", { length: 128 }),
stripePriceId: varchar("stripePriceId", { length: 128 }),
plan: mysqlEnum("plan", ["trial", "basic", "pro"]).default("trial").notNull(),
status: mysqlEnum("status", ["trialing", "active", "past_due", "canceled", "expired"]).default("trialing").notNull(),
trialStartedAt: timestamp("trialStartedAt").defaultNow().notNull(),
trialEndsAt: timestamp("trialEndsAt").notNull(),
currentPeriodStart: timestamp("currentPeriodStart"),
currentPeriodEnd: timestamp("currentPeriodEnd"),
canceledAt: timestamp("canceledAt"),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type Subscription = typeof subscriptions.$inferSelect;
export type InsertSubscription = typeof subscriptions.$inferInsert;
// ─── Clinics (cabinets médicaux) ─────────────────────────────────────────────
export const clinics = mysqlTable("clinics", {
id: int("id").autoincrement().primaryKey(),
userId: int("userId").notNull(),
name: varchar("name", { length: 255 }).notNull(),
address: text("address"),
phone: varchar("phone", { length: 32 }),
color: varchar("color", { length: 16 }).default("#0d9488"),
isActive: boolean("isActive").default(true).notNull(),
// QR code token rotatif anti-triche
qrToken: varchar("qrToken", { length: 64 }).notNull(),
qrTokenExpiresAt: timestamp("qrTokenExpiresAt"),
qrRotationMinutes: int("qrRotationMinutes").default(30),
// Paramètres file d'attente
avgConsultationMinutes: int("avgConsultationMinutes").default(15),
maxQueueSize: int("maxQueueSize").default(50),
isQueueOpen: boolean("isQueueOpen").default(false).notNull(),
currentTicketNumber: int("currentTicketNumber").default(0).notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type Clinic = typeof clinics.$inferSelect;
export type InsertClinic = typeof clinics.$inferInsert;
// ─── Queue Entries (patients en file) ────────────────────────────────────────
export const queueEntries = mysqlTable("queue_entries", {
id: int("id").autoincrement().primaryKey(),
clinicId: int("clinicId").notNull(),
ticketNumber: int("ticketNumber").notNull(),
// Identifiant de session anonyme du patient
patientToken: varchar("patientToken", { length: 64 }).notNull(),
patientName: varchar("patientName", { length: 128 }),
patientPhone: varchar("patientPhone", { length: 32 }),
status: mysqlEnum("status", ["waiting", "called", "in_consultation", "done", "absent", "canceled"])
.default("waiting")
.notNull(),
position: int("position").notNull(),
joinedAt: timestamp("joinedAt").defaultNow().notNull(),
calledAt: timestamp("calledAt"),
consultationStartAt: timestamp("consultationStartAt"),
consultationEndAt: timestamp("consultationEndAt"),
estimatedWaitMinutes: int("estimatedWaitMinutes"),
notificationSent: boolean("notificationSent").default(false).notNull(),
// Pour l'impression de ticket
isPrinted: boolean("isPrinted").default(false).notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type QueueEntry = typeof queueEntries.$inferSelect;
export type InsertQueueEntry = typeof queueEntries.$inferInsert;
// ─── Analytics Events ─────────────────────────────────────────────────────────
export const analyticsEvents = mysqlTable("analytics_events", {
id: int("id").autoincrement().primaryKey(),
clinicId: int("clinicId").notNull(),
eventType: mysqlEnum("eventType", [
"patient_joined",
"patient_called",
"patient_done",
"patient_absent",
"queue_opened",
"queue_closed",
]).notNull(),
ticketNumber: int("ticketNumber"),
waitMinutes: int("waitMinutes"),
consultationMinutes: int("consultationMinutes"),
queueSizeAtEvent: int("queueSizeAtEvent"),
hourOfDay: int("hourOfDay"),
dayOfWeek: int("dayOfWeek"),
metadata: json("metadata"),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export type AnalyticsEvent = typeof analyticsEvents.$inferSelect;
export type InsertAnalyticsEvent = typeof analyticsEvents.$inferInsert;