Add SQL management UI, maintenance, and trip edit pages for motorcycles

This commit is contained in:
2026-07-27 21:18:28 +02:00
parent 7487a7d588
commit 1218c13660
21 changed files with 1562 additions and 212 deletions
+64
View File
@@ -83,6 +83,28 @@ function ensureSchema() {
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
) STRICT;
CREATE TABLE IF NOT EXISTS maintenance_event_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
maintenance_event_id INTEGER NOT NULL REFERENCES maintenance_events(id) ON DELETE CASCADE,
type TEXT CHECK (
type IS NULL OR type IN ('reparatur', 'tuev_hu', 'inspektion', 'reifenwechsel', 'oelwechsel', 'sonstiges')
),
custom_type TEXT,
custom_type_key TEXT,
cost_cents INTEGER CHECK (cost_cents IS NULL OR cost_cents >= 0),
due_date TEXT,
due_km INTEGER CHECK (due_km IS NULL OR due_km >= 0),
position INTEGER NOT NULL CHECK (position >= 0),
CHECK (
(type IS NOT NULL AND custom_type IS NULL AND custom_type_key IS NULL) OR
(
type IS NULL AND custom_type IS NOT NULL AND custom_type_key IS NOT NULL
AND length(trim(custom_type)) > 0 AND length(custom_type_key) > 0
)
),
UNIQUE (maintenance_event_id, position)
) STRICT;
CREATE TABLE IF NOT EXISTS trips (
id INTEGER PRIMARY KEY AUTOINCREMENT,
motorcycle_id INTEGER NOT NULL REFERENCES motorcycles(id) ON DELETE CASCADE,
@@ -131,6 +153,10 @@ function ensureSchema() {
ON maintenance_events(motorcycle_id, event_date DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_maintenance_due
ON maintenance_events(motorcycle_id, type, event_date DESC);
CREATE INDEX IF NOT EXISTS idx_maintenance_items_event
ON maintenance_event_items(maintenance_event_id, position);
CREATE INDEX IF NOT EXISTS idx_maintenance_items_due
ON maintenance_event_items(type, due_date, due_km);
CREATE INDEX IF NOT EXISTS idx_trips_motorcycle
ON trips(motorcycle_id, trip_date DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_motorcycle_shares_user
@@ -141,6 +167,44 @@ function ensureSchema() {
ON webauthn_challenges(user_id, purpose, expires_at, used_at);
`);
const maintenanceItemColumns = db
.prepare("PRAGMA table_info(maintenance_event_items)")
.all() as { name: string }[];
if (!maintenanceItemColumns.some((column) => column.name === "custom_type_key")) {
db.exec("ALTER TABLE maintenance_event_items ADD COLUMN custom_type_key TEXT");
}
db.exec(`
INSERT INTO maintenance_event_items
(maintenance_event_id, type, custom_type, custom_type_key, cost_cents, due_date, due_km, position)
SELECT e.id, e.type, NULL, NULL, e.cost_cents, e.due_date, e.due_km, 0
FROM maintenance_events e
WHERE NOT EXISTS (
SELECT 1
FROM maintenance_event_items item
WHERE item.maintenance_event_id = e.id
)
`);
const customMaintenanceItems = db
.prepare(
`SELECT id, custom_type
FROM maintenance_event_items
WHERE type IS NULL
AND custom_type IS NOT NULL
AND (custom_type_key IS NULL OR custom_type_key = '')`,
)
.all() as { id: number; custom_type: string }[];
const updateCustomMaintenanceKey = db.prepare(
"UPDATE maintenance_event_items SET custom_type_key = ? WHERE id = ?",
);
for (const item of customMaintenanceItems) {
updateCustomMaintenanceKey.run(item.custom_type.toLocaleLowerCase("de-DE"), item.id);
}
db.exec(
"CREATE INDEX IF NOT EXISTS idx_maintenance_items_custom_due ON maintenance_event_items(custom_type_key, due_date, due_km)",
);
const userColumns = db.prepare("PRAGMA table_info(users)").all() as { name: string }[];
if (!userColumns.some((column) => column.name === "active")) {
db.exec("ALTER TABLE users ADD COLUMN active INTEGER NOT NULL DEFAULT 1 CHECK (active IN (0, 1))");