From 9d78663cfe9bdedc2c9fe973b21ddb858d1af8e1 Mon Sep 17 00:00:00 2001 From: AgendaPro Dev Date: Sun, 26 Jul 2026 15:59:02 -0600 Subject: [PATCH] feat(db): v4 migration + shared types for specialist auto-assignment Adds auto_assign_specialist + working_hours to businesses, and specialties + working_hours + efficiency_score to employees, with idempotent migrateV3ToV4 (backfills default Lun-Vie 09:00-20:00 working hours). Updates Business/Employee types and adds WorkingHoursMap. --- server/db.ts | 35 +++++++++++++++++++++++++++++++++++ shared/types.ts | 14 ++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/server/db.ts b/server/db.ts index 7029fcc..478105c 100644 --- a/server/db.ts +++ b/server/db.ts @@ -222,11 +222,46 @@ function migrateV1ToV2() { setMeta("schema_version", "2"); } +/** v4: auto-assign specialist, business & employee working hours, employee specialties/efficiency. */ +function migrateV3ToV4() { + if (getMeta("schema_version") >= "4") return; + + const bizCols: [string, string][] = [ + ["auto_assign_specialist", "INTEGER NOT NULL DEFAULT 0"], + ["working_hours", "TEXT"], + ]; + for (const [col, def] of bizCols) { + if (!columnExists("businesses", col)) db.exec(`ALTER TABLE businesses ADD COLUMN ${col} ${def};`); + } + + const empCols: [string, string][] = [ + ["specialties", "TEXT"], + ["working_hours", "TEXT"], + ["efficiency_score", "REAL NOT NULL DEFAULT 50"], + ]; + for (const [col, def] of empCols) { + if (!columnExists("employees", col)) db.exec(`ALTER TABLE employees ADD COLUMN ${col} ${def};`); + } + + // Backfill business working_hours: Lun-Vie 09:00-20:00 (replica del hardcodeado anterior) + const DEFAULT_WH = JSON.stringify({ + 1: { start: "09:00", end: "20:00" }, 2: { start: "09:00", end: "20:00" }, + 3: { start: "09:00", end: "20:00" }, 4: { start: "09:00", end: "20:00" }, + 5: { start: "09:00", end: "20:00" }, 6: null, 7: null, + }); + const noWh = db.prepare(`SELECT id FROM businesses WHERE working_hours IS NULL`).all() as { id: number }[]; + const upd = db.prepare(`UPDATE businesses SET working_hours = ? WHERE id = ?`); + for (const b of noWh) upd.run(DEFAULT_WH, b.id); + + setMeta("schema_version", "4"); +} + export function runMigrations() { // Ensure base schema exists (no-op on existing tables) db.exec(SCHEMA); migrateV1ToV2(); migrateV2ToV3(); + migrateV3ToV4(); } /** v3: cancellation policy, commissions, cash register, notifications/reminders, booking slug. */ diff --git a/shared/types.ts b/shared/types.ts index 7998658..67ec739 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -14,9 +14,20 @@ export interface Business { status?: string; template?: string | null; trial_ends_at?: string | null; + booking_enabled?: number | boolean; + cancel_window_hours?: number; + cancel_penalty_pct?: number; + require_deposit?: number | boolean; + deposit_pct?: number; + timezone?: string; + auto_assign_specialist?: number | boolean; + working_hours?: WorkingHoursMap | string | null; created_at?: string; } +export type WorkingDay = { start: string; end: string }; +export type WorkingHoursMap = Record; // 1=Lun … 7=Dom + export interface User { id: number; business_id: number | null; @@ -39,6 +50,9 @@ export interface Employee { rating: number; hire_date: string | null; service_ids?: number[]; + specialties?: string[]; + working_hours?: WorkingHoursMap | string | null; + efficiency_score?: number; stats?: EmployeeStats; }