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;