152 lines
4.1 KiB
Markdown
152 lines
4.1 KiB
Markdown
|
|
# 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::<surrealdb::engine::remote::ws::Ws>(
|
||
|
|
&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)
|