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.
This commit is contained in:
AgendaPro Dev
2026-07-26 15:59:02 -06:00
parent e8d2435cc2
commit 9d78663cfe
2 changed files with 49 additions and 0 deletions
+35
View File
@@ -222,11 +222,46 @@ function migrateV1ToV2() {
setMeta("schema_version", "2"); 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() { export function runMigrations() {
// Ensure base schema exists (no-op on existing tables) // Ensure base schema exists (no-op on existing tables)
db.exec(SCHEMA); db.exec(SCHEMA);
migrateV1ToV2(); migrateV1ToV2();
migrateV2ToV3(); migrateV2ToV3();
migrateV3ToV4();
} }
/** v3: cancellation policy, commissions, cash register, notifications/reminders, booking slug. */ /** v3: cancellation policy, commissions, cash register, notifications/reminders, booking slug. */
+14
View File
@@ -14,9 +14,20 @@ export interface Business {
status?: string; status?: string;
template?: string | null; template?: string | null;
trial_ends_at?: 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; created_at?: string;
} }
export type WorkingDay = { start: string; end: string };
export type WorkingHoursMap = Record<number, WorkingDay | null>; // 1=Lun … 7=Dom
export interface User { export interface User {
id: number; id: number;
business_id: number | null; business_id: number | null;
@@ -39,6 +50,9 @@ export interface Employee {
rating: number; rating: number;
hire_date: string | null; hire_date: string | null;
service_ids?: number[]; service_ids?: number[];
specialties?: string[];
working_hours?: WorkingHoursMap | string | null;
efficiency_score?: number;
stats?: EmployeeStats; stats?: EmployeeStats;
} }