# ADR-004: SurrealDB como Database Único **Status**: Accepted | Implemented **Date**: 2024-11-01 **Deciders**: Backend Architecture Team **Technical Story**: Selecting unified multi-model database for relational, graph, and document workloads --- ## Decision Usar **SurrealDB 2.3** como base de datos única (no PostgreSQL + Neo4j, no MongoDB puro). --- ## Rationale 1. **Multi-Model en una sola DB**: Relational (SQL), graph (queries), document (JSON) sin múltiples conexiones 2. **Multi-Tenancy Nativa**: SurrealDB scopes permiten aislamiento a nivel de database sin lógica en aplicación 3. **WebSocket Connection**: Soporte nativo de conexiones bidireccionales (vs REST) 4. **SurrealQL**: Sintaxis SQL-like + graph traversal en una sola query language 5. **VAPORA Requirements**: Almacena projects (relational), agent relationships (graph), execution history (document) --- ## Alternatives Considered ### ❌ PostgreSQL + Neo4j (Two Database Approach) - **Pros**: Maduro, comunidad grande, especializados - **Cons**: Sincronización entre dos DBs, dos conexiones, transacciones distribuidas complejas ### ❌ MongoDB Puro (Document Only) - **Pros**: Flexible, escalable - **Cons**: Sin soporte graph nativo, requiere aplicación para traversal, sin SQL ### ✅ SurrealDB (CHOSEN) - Unifica relational + graph + document - Multi-tenancy built-in - WebSocket para real-time --- ## Trade-offs **Pros**: - ✅ Una sola DB para todos los modelos de datos - ✅ Scopes para isolamiento de tenants (no en aplicación) - ✅ Transactions ACID - ✅ SurrealQL es SQL + graph en una query - ✅ WebSocket bidireccional **Cons**: - ⚠️ Ecosistema más pequeño que PostgreSQL - ⚠️ Drivers/herramientas menos maduras - ⚠️ Soporte de clusters más limitado (vs Postgres) --- ## Implementation **Database Connection**: ```rust // crates/vapora-backend/src/main.rs:48-59 let db = surrealdb::Surreal::new::( &config.database.url ).await?; db.signin(surrealdb::opt::auth::Root { username: "root", password: "root", }).await?; db.use_ns("vapora").use_db("main").await?; ``` **Scope-Based Multi-Tenancy**: ```rust // All queries use scope for tenant isolation db.query("SELECT * FROM projects WHERE tenant_id = $tenant_id") .bind(("tenant_id", tenant_id)) .await? ``` **Key Files**: - `/crates/vapora-backend/src/main.rs:45-59` (connection setup) - `/crates/vapora-backend/src/services/` (query implementations) - `/crates/vapora-shared/src/models.rs` (Project, Task, Agent models with tenant_id) --- ## Verification ```bash # Connect to SurrealDB surreal sql --conn ws://localhost:8000 --user root --pass root # Verify namespace and database exist USE ns vapora db main; INFO FOR DATABASE; # Test multi-tenant query SELECT * FROM projects WHERE tenant_id = 'workspace:123'; # Test graph traversal SELECT *, ->assigned_to->agents AS assigned_agents FROM tasks WHERE project_id = 'project:123'; # Run backend tests with SurrealDB cargo test -p vapora-backend -- --nocapture ``` **Expected Output**: - SurrealDB connects via WebSocket - Projects table exists and is queryable - Graph relationships (->assigned_to) resolve - Multi-tenant queries filter correctly - 79+ backend tests pass --- ## Consequences ### Data Model Changes - All tables must include `tenant_id` field for scoping - Relations use SurrealDB's `->` edge syntax for graph queries - No foreign key constraints (SurrealDB uses references instead) ### Query Patterns - Services layer queries must include tenant_id filter (defense-in-depth) - SurrealQL instead of raw SQL learning curve for team - Graph traversal enables efficient knowledge graph queries ### Scaling Considerations - Horizontal scaling requires clustering (vs Postgres replication) - Backup/recovery different from traditional databases (see ADR-020) --- ## References - [SurrealDB Documentation](https://surrealdb.com/docs/surrealql/queries) - `/crates/vapora-backend/src/services/` (query patterns) - `/crates/vapora-shared/src/models.rs` (model definitions with tenant_id) - ADR-025 (Multi-Tenancy with Scopes) --- **Related ADRs**: ADR-001 (Workspace), ADR-025 (Multi-Tenancy)