CREATE TABLE IF NOT EXISTS companies ( id TEXT PRIMARY KEY, name TEXT NOT NULL, code TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS production_lines ( id TEXT PRIMARY KEY, company_id TEXT NOT NULL REFERENCES companies(id), name TEXT NOT NULL, code TEXT NOT NULL, device_id TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_seen_at TIMESTAMPTZ, UNIQUE (company_id, code) ); ALTER TABLE production_lines ADD COLUMN IF NOT EXISTS last_seen_at TIMESTAMPTZ; CREATE INDEX IF NOT EXISTS production_lines_last_seen_at_idx ON production_lines (last_seen_at); CREATE TABLE IF NOT EXISTS licenses ( license_id UUID PRIMARY KEY, company_id TEXT NOT NULL REFERENCES companies(id), production_line_id TEXT NOT NULL REFERENCES production_lines(id), device_id TEXT NOT NULL, customer TEXT NOT NULL, issued_at TIMESTAMPTZ NOT NULL, expiry_at TIMESTAMPTZ NOT NULL, features TEXT NOT NULL, license TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ('active', 'revoked')), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revoked_at TIMESTAMPTZ, revocation_reason TEXT ); CREATE TABLE IF NOT EXISTS file_records ( id TEXT PRIMARY KEY, file_name TEXT NOT NULL, original_file_name TEXT, folder TEXT NOT NULL, cloud_path TEXT NOT NULL UNIQUE, file_id TEXT NOT NULL UNIQUE, upload_time TIMESTAMPTZ NOT NULL, size_bytes BIGINT NOT NULL ); ALTER TABLE file_records ADD COLUMN IF NOT EXISTS original_file_name TEXT; CREATE TABLE IF NOT EXISTS function_configs ( config_type TEXT PRIMARY KEY, parameters JSONB NOT NULL, version BIGINT NOT NULL, update_time TIMESTAMPTZ NOT NULL ); CREATE TABLE IF NOT EXISTS panel_inbox ( file_id TEXT PRIMARY KEY, device_id TEXT NOT NULL, file_name TEXT NOT NULL, media_type TEXT NOT NULL, upload_time TIMESTAMPTZ NOT NULL ); CREATE TABLE IF NOT EXISTS identification_files ( file_id TEXT PRIMARY KEY, device_id TEXT NOT NULL, file_name TEXT NOT NULL, media_type TEXT NOT NULL, upload_time TIMESTAMPTZ NOT NULL, size_bytes BIGINT NOT NULL, status TEXT NOT NULL CHECK (status IN ('pending', 'processed')), processed_at TIMESTAMPTZ, expires_at TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS identification_feedback ( device_id TEXT NOT NULL, run_id TEXT NOT NULL, file_name TEXT NOT NULL, status TEXT NOT NULL, result SMALLINT, update_time TIMESTAMPTZ NOT NULL, PRIMARY KEY (device_id, run_id) ); CREATE TABLE IF NOT EXISTS volume_config_requests ( device_id TEXT NOT NULL, request_id TEXT NOT NULL, status TEXT NOT NULL, created_at_ms BIGINT NOT NULL, expires_at_ms BIGINT NOT NULL, config_file_id TEXT, config_file_name TEXT, uploaded_at_ms BIGINT, update_time TIMESTAMPTZ NOT NULL, PRIMARY KEY (device_id, request_id) ); CREATE INDEX IF NOT EXISTS licenses_status_device_expiry_idx ON licenses (status, device_id, expiry_at); CREATE INDEX IF NOT EXISTS file_records_folder_idx ON file_records (folder); CREATE INDEX IF NOT EXISTS identification_files_device_upload_idx ON identification_files (device_id, upload_time DESC); CREATE INDEX IF NOT EXISTS identification_files_expires_idx ON identification_files (expires_at) WHERE expires_at IS NOT NULL; CREATE INDEX IF NOT EXISTS identification_feedback_device_idx ON identification_feedback (device_id);