This commit is contained in:
2026-09-28 23:15:47 +05:30
commit 605c6a2e58
41 changed files with 4299 additions and 0 deletions
+329
View File
@@ -0,0 +1,329 @@
export type ColumnType = "uuid" | "string" | "longtext" | "bool" | "double" | "int" | "datetime";
export type Column = {
name: string;
type: ColumnType;
nullable: boolean;
hasDefault: boolean;
max?: number;
};
export type TableSpec = {
name: string;
columns: Column[];
};
function col(
name: string,
type: ColumnType,
extra?: Partial<Pick<Column, "nullable" | "hasDefault" | "max">>,
): Column {
return {
name,
type,
nullable: extra?.nullable ?? false,
hasDefault: extra?.hasDefault ?? false,
max: extra?.max,
};
}
function tail(): Column[] {
return [
col("updated_at", "datetime"),
col("deleted_at", "datetime", { nullable: true, hasDefault: true }),
col("is_dirty", "bool", { hasDefault: true }),
];
}
const id = () => col("id", "uuid");
const text = (name: string, max: number, hasDefault = false) =>
col(name, "string", { max, hasDefault });
const ref = (name: string, nullable = false) => col(name, "uuid", { nullable });
export const SYNC_TABLES: Record<string, TableSpec> = {
staff_members: {
name: "staff_members",
columns: [
id(),
text("name", 255),
text("pin_hash", 255),
text("role", 64),
col("active", "bool", { hasDefault: true }),
...tail(),
],
},
shop_settings: {
name: "shop_settings",
columns: [
id(),
text("name", 255),
text("address", 4000, true),
text("phone", 64, true),
text("gstin", 64, true),
col("tax_percent", "double", { hasDefault: true }),
text("sms_bill_template", 4000),
text("sms_status_template", 4000),
// v1 does not allocate invoice numbers. next_invoice_number is last-write-wins.
// Two tablets incrementing it will clash.
col("next_invoice_number", "int", { hasDefault: true }),
text("expected_open", 16, true),
text("expected_close", 16, true),
col("late_grace_minutes", "int", { hasDefault: true }),
text("public_base_url", 512),
...tail(),
],
},
work_days: {
name: "work_days",
columns: [
id(),
text("day_key", 32),
col("started_at", "datetime"),
col("ended_at", "datetime", { nullable: true }),
ref("started_by_staff_id"),
...tail(),
],
},
attendance_records: {
name: "attendance_records",
columns: [
id(),
ref("work_day_id"),
ref("staff_id"),
col("check_in_at", "datetime", { nullable: true }),
col("check_out_at", "datetime", { nullable: true }),
text("notes", 4000, true),
...tail(),
],
},
short_leaves: {
name: "short_leaves",
columns: [
id(),
ref("work_day_id"),
ref("staff_id"),
col("from_at", "datetime"),
col("to_at", "datetime"),
col("minutes", "int"),
text("reason", 4000, true),
...tail(),
],
},
overtime_logs: {
name: "overtime_logs",
columns: [
id(),
ref("work_day_id"),
ref("staff_id"),
col("from_at", "datetime", { nullable: true }),
col("to_at", "datetime", { nullable: true }),
col("minutes", "int"),
text("reason", 4000, true),
...tail(),
],
},
customers: {
name: "customers",
columns: [
id(),
text("phone", 64),
text("name", 255),
col("created_at", "datetime", { hasDefault: true }),
...tail(),
],
},
vehicles: {
name: "vehicles",
columns: [
id(),
ref("customer_id"),
text("registration", 64),
text("vin", 64, true),
text("make", 255, true),
text("model_name", 255, true),
col("year", "int", { nullable: true }),
col("engine_capacity", "int", { nullable: true }),
ref("bike_model_id", true),
col("created_at", "datetime", { hasDefault: true }),
...tail(),
],
},
job_cards: {
name: "job_cards",
columns: [
id(),
ref("vehicle_id"),
ref("customer_id"),
ref("brought_by_customer_id", true),
text("complaint", 4000),
text("stage", 64),
text("engineer_notes", 4000, true),
col("created_at", "datetime", { hasDefault: true }),
...tail(),
],
},
odo_readings: {
name: "odo_readings",
columns: [id(), col("read_at", "datetime"), ref("vehicle_id"), col("reading_km", "int"), ...tail()],
},
job_card_events: {
name: "job_card_events",
columns: [
id(),
ref("job_card_id"),
text("stage", 64),
text("note", 4000, true),
col("at", "datetime"),
...tail(),
],
},
part_types: {
name: "part_types",
columns: [id(), text("name", 255), ...tail()],
},
bike_models: {
name: "bike_models",
columns: [id(), text("name", 255), text("brand", 255, true), ...tail()],
},
bike_groups: {
name: "bike_groups",
columns: [
id(),
text("name", 255),
ref("part_type_id", true),
text("code", 64, true),
text("notes", 4000, true),
...tail(),
],
},
bike_group_members: {
name: "bike_group_members",
columns: [id(), ref("group_id"), ref("bike_model_id"), ...tail()],
},
catalog_parts: {
name: "catalog_parts",
columns: [
id(),
ref("part_type_id"),
ref("bike_model_id", true),
ref("group_id", true),
col("is_universal", "bool", { hasDefault: true }),
...tail(),
],
},
catalog_part_models: {
name: "catalog_part_models",
columns: [id(), ref("catalog_part_id"), ref("bike_model_id"), ...tail()],
},
part_variants: {
name: "part_variants",
columns: [
id(),
ref("catalog_part_id"),
text("grade", 64),
text("brand", 255, true),
text("sku", 128, true),
col("cost", "double", { hasDefault: true }),
col("sale_price", "double"),
col("qty_on_hand", "double", { hasDefault: true }),
...tail(),
],
},
job_line_items: {
name: "job_line_items",
columns: [
id(),
ref("job_card_id"),
text("kind", 64),
ref("variant_id", true),
text("description", 4000),
col("qty", "double"),
col("unit_price", "double"),
...tail(),
],
},
invoices: {
name: "invoices",
columns: [
id(),
text("number", 64),
ref("public_token"),
ref("job_card_id", true),
ref("customer_id", true),
text("kind", 64),
col("subtotal", "double"),
col("tax_percent", "double"),
col("tax_amount", "double"),
col("total", "double"),
col("snapshot_json", "longtext"),
text("publish_status", 64),
col("created_at", "datetime"),
...tail(),
],
},
invoice_lines: {
name: "invoice_lines",
columns: [
id(),
ref("invoice_id"),
text("description", 4000),
col("qty", "double"),
col("unit_price", "double"),
col("line_total", "double"),
...tail(),
],
},
payments: {
name: "payments",
columns: [
id(),
ref("invoice_id"),
text("method", 64),
col("amount", "double"),
col("at", "datetime"),
...tail(),
],
},
demand_logs: {
name: "demand_logs",
columns: [
id(),
ref("part_type_id"),
ref("bike_model_id"),
ref("variant_id", true),
col("qty", "double"),
text("reason", 4000, true),
col("created_at", "datetime"),
...tail(),
],
},
sms_outbox: {
name: "sms_outbox",
columns: [
id(),
text("to_phone", 64),
text("body", 4000),
text("status", 64),
text("error", 4000, true),
ref("invoice_id", true),
ref("job_card_id", true),
col("created_at", "datetime"),
...tail(),
],
},
publish_outbox: {
name: "publish_outbox",
columns: [
id(),
ref("invoice_id"),
ref("public_token"),
col("payload_json", "longtext"),
text("status", 64),
text("error", 4000, true),
col("created_at", "datetime"),
...tail(),
],
},
};
export const SYNC_TABLE_NAMES = Object.keys(SYNC_TABLES);