https://). All database access goes through the Repository Pattern: domain-layer interfaces define the contract; infrastructure-layer classes provide the implementation using the @libsql/client SDK.
Database Schema
Table Descriptions
Repository Pattern
The repository pattern cleanly separates the persistence contract from its implementation. Domain contracts (src/domain/):
src/infrastructure/repositories/):
Use cases in the Application layer receive these implementations through constructor injection. Because they only depend on the domain interface, the in-memory variants let the full test suite run without a live database connection.
Vector Embeddings in SQLite
Turso (SQLite) has no native vector similarity extension in the version used by this project, so embeddings are stored as BLOBs and similarity is computed in JavaScript byVectorSearchService.
Serialisation round-trip:
TursoTenderRepository loads a tender’s requirements, it reads the embedding column as a Buffer and passes it to deserializeEmbedding() to reconstruct the Float32Array. VectorSearchService.findSimilar() then iterates over all requirement vectors, computes pairwise cosine similarity, and returns up to TOP_K_SIMILAR = 5 results above SIMILARITY_THRESHOLD = 0.3.
The embedding column is added via a runtime ALTER TABLE migration inside TursoDatabase.initializeSchema(), so existing databases without the column are upgraded automatically on the next server start.
Connection Management
TursoDatabase is a singleton that creates the LibSQL client once and reuses it for the lifetime of the server process instance.
The
libsql:// → https:// conversion is applied automatically at runtime to ensure HTTP transport is used in all production environments, avoiding WebSocket instability.
Schema Initialization
TursoDatabase.initializeSchema() runs automatically during server startup (called from server.ts before Express starts listening). It reads schema.sql, splits on ;, and executes each statement individually.
All CREATE TABLE statements use IF NOT EXISTS, making the initialisation fully idempotent — safe to run on every cold start without risk of data loss or duplicate-table errors.
After the core schema is applied, two additional bootstrap steps run:
- Embedding column migration —
ALTER TABLE requirements ADD COLUMN embedding BLOB(silently skipped if the column already exists). - Industry presets seeding — inserts default rows for “Digital Services” and “Construction” if
industry_presetsis empty.