@ -98,6 +98,47 @@ export class SqliteDb implements DB {
async close ( ) : Promise < void > { this . raw . close ( ) }
}
/ * *
* D24 ( red - team ) : indexes for the queries that run over the real data ( 300 clients ,
* thousands of documents / tickets / interactions ) . Without these every list , report and
* join full - scans — tolerable on dev SQLite , a real problem on production Postgres .
* ` CREATE INDEX IF NOT EXISTS ` is valid on both engines , so this same DDL is applied by
* the SQLite SCHEMA below and by the Postgres migration set . Columns chosen : foreign keys
* used in joins / filters , and the status / date / renewal columns the scans and boards read .
* /
export const INDEX_DDL = `
CREATE INDEX IF NOT EXISTS ix_document_client ON document ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_document_type_status ON document ( doc_type , status ) ;
CREATE INDEX IF NOT EXISTS ix_document_ref ON document ( ref_doc_id ) ;
CREATE INDEX IF NOT EXISTS ix_document_created_by ON document ( created_by ) ;
CREATE INDEX IF NOT EXISTS ix_document_event_doc ON document_event ( document_id ) ;
CREATE INDEX IF NOT EXISTS ix_document_share_doc ON document_share ( document_id ) ;
CREATE INDEX IF NOT EXISTS ix_payment_client ON payment ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_alloc_doc ON payment_allocation ( document_id ) ;
CREATE INDEX IF NOT EXISTS ix_alloc_payment ON payment_allocation ( payment_id ) ;
CREATE INDEX IF NOT EXISTS ix_client_module_client ON client_module ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_client_module_module ON client_module ( module _id , active ) ;
CREATE INDEX IF NOT EXISTS ix_client_module_renewal ON client_module ( next_renewal ) ;
CREATE INDEX IF NOT EXISTS ix_client_owner ON client ( owner_id ) ;
CREATE INDEX IF NOT EXISTS ix_client_branch_client ON client_branch ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_ticket_client ON ticket ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_ticket_status ON ticket ( status ) ;
CREATE INDEX IF NOT EXISTS ix_ticket_assigned ON ticket ( assigned_to ) ;
CREATE INDEX IF NOT EXISTS ix_interaction_client ON interaction ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_interaction_followup ON interaction ( follow_up_on ) ;
CREATE INDEX IF NOT EXISTS ix_reminder_status ON reminder ( status ) ;
CREATE INDEX IF NOT EXISTS ix_reminder_client ON reminder ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_reminder_doc ON reminder ( doc_id ) ;
CREATE INDEX IF NOT EXISTS ix_price_book_module ON module _price_book ( module _id ) ;
CREATE INDEX IF NOT EXISTS ix_rate_band_module ON usage_rate_band ( module _id , effective_from ) ;
CREATE INDEX IF NOT EXISTS ix_recurring_active_run ON recurring_plan ( active , next_run ) ;
CREATE INDEX IF NOT EXISTS ix_amc_client ON amc_contract ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_aws_client ON aws_usage ( client_id ) ;
CREATE INDEX IF NOT EXISTS ix_session_staff ON session ( staff_id ) ;
CREATE INDEX IF NOT EXISTS ix_audit_entity ON audit_log ( entity , entity_id ) ;
CREATE INDEX IF NOT EXISTS ix_milestone_cm ON project_milestone ( client_module_id ) ;
`
const SCHEMA = `
CREATE TABLE IF NOT EXISTS staff_user (
id TEXT PRIMARY KEY , email TEXT NOT NULL UNIQUE , display_name TEXT NOT NULL ,
@ -313,7 +354,7 @@ CREATE TABLE IF NOT EXISTS aws_usage (
updated_at TEXT NOT NULL ,
UNIQUE ( client_id , month ) -- one row per client per month ; the pull upserts on this key
) ;
`
$ { INDEX_DDL } `
/ * * O p e n t h e S Q L i t e e n g i n e ( d e v / t e s t s ) . D e l i b e r a t e l y s y n c — s c h e m a + m i g r a t e r u n
* on the raw handle before it is wrapped , so test fixtures stay one - liners . * /