syntaxis/docs/surrealdb-quick-start.md
Jesús Pérez 9cef9b8d57 refactor: consolidate configuration directories
Merge _configs/ into config/ for single configuration directory.
Update all path references.

Changes:
- Move _configs/* to config/
- Update .gitignore for new patterns
- No code references to _configs/ found

Impact: -1 root directory (layout_conventions.md compliance)
2025-12-26 18:36:23 +00:00

14 KiB

SurrealDB 2.3 Quick Start Guide

Status: Production Ready Version: SurrealDB 2.3 Updated: November 15, 2025

This guide shows how to quickly get started with SurrealDB 2.3 in syntaxis with different deployment contexts.


Quick Install & Run

Option 1: Embedded In-Memory (Fastest, No Server)

# No installation needed - uses embedded library
# Update configs/database.toml:

[surrealdb]
url = "mem://"  # In-memory database
namespace = "syntaxis"
database = "projects"
use workspace_core::SurrealDatabase;

#[tokio::main]
async fn main() -> Result<()> {
    // Create in-memory database
    let db = SurrealDatabase::new_memory().await?;

    // Start using database immediately
    let projects = db.list_projects().await?;
    println!("Projects: {}", projects.len());

    Ok(())
}

Option 2: Embedded File-Based (Persistent, No Server)

# Update configs/database.toml:

[surrealdb]
url = "file:///tmp/surrealdb.db"  # RocksDB persistent storage
namespace = "syntaxis"
database = "projects"
let db = SurrealDatabase::new_file("/tmp/surrealdb.db").await?;

Option 3: Server Mode (Full Features, Requires Setup)

Install SurrealDB

# macOS
brew install surrealdb

# Linux/WSL
cargo install surreal

# Windows
choco install surrealdb

# Verify
surreal version

Start Server

# Simple in-memory server
surreal start --bind 127.0.0.1:8000 memory

# File-based with persistence
surreal start --bind 127.0.0.1:8000 file:///tmp/surrealdb.db

# With authentication
surreal start \
  --bind 127.0.0.1:8000 \
  --username admin \
  --password your_password \
  file:///tmp/surrealdb.db

Connect from Application

// Update configs/database.toml:
// [surrealdb]
// url = "ws://localhost:8000"
// username = "admin"
// password = "your_password"

use workspace_core::SurrealDatabase;

#[tokio::main]
async fn main() -> Result<()> {
    let db = SurrealDatabase::new_server(
        "ws://localhost:8000",
        "syntaxis",
        "projects",
        Some("admin"),
        Some("your_password"),
    ).await?;

    Ok(())
}

Core Operations

1. Create a Project

use workspace_core::{SurrealDatabase, DbProject};
use chrono::Utc;
use uuid::Uuid;

let db = SurrealDatabase::new_memory().await?;

let project = DbProject {
    id: Uuid::new_v4().to_string(),
    name: "My Project".to_string(),
    version: "0.1.0".to_string(),
    description: "A SurrealDB project".to_string(),
    project_type: "MultiLang".to_string(),
    current_phase: "Creation".to_string(),
    created_at: Utc::now().to_rfc3339(),
    updated_at: Utc::now().to_rfc3339(),
};

db.create_project(&project).await?;
println!("✓ Project created: {}", project.id);

2. Retrieve Projects

// Get all projects
let projects = db.list_projects().await?;
println!("Total projects: {}", projects.len());

// Get specific project
if let Some(project) = db.get_project(&project_id).await? {
    println!("Project: {} (Phase: {})", project.name, project.current_phase);
} else {
    println!("Project not found");
}

// Get projects by phase
for project in &projects {
    if project.current_phase == "Development" {
        println!("  - {} (in Development)", project.name);
    }
}

3. Add Checklist Items

use workspace_core::DbChecklistItem;

let item = DbChecklistItem {
    id: Uuid::new_v4().to_string(),
    project_id: project.id.clone(),
    phase: "Creation".to_string(),
    task_id: "setup-1".to_string(),
    description: "Initialize project structure".to_string(),
    completed: false,
    completed_at: None,
    created_at: Utc::now().to_rfc3339(),
    task_type: "Setup".to_string(),
    task_priority: "High".to_string(),
    task_due: Some("2025-12-31".to_string()),
    task_estimation: Some("2d".to_string()),
    task_deps: "[]".to_string(),  // Comma-separated IDs
    task_note: Some("Remember to test thoroughly".to_string()),
    task_name: Some("Setup".to_string()),
};

db.create_checklist_item(&item).await?;
println!("✓ Added checklist item");

4. Track Progress

// Get checklist items for a phase
let items = db.get_checklist_items_by_phase(&project_id, "Creation").await?;
let completed = items.iter().filter(|i| i.completed).count();

println!("Progress: {}/{}", completed, items.len());

// Get completion percentage
let percentage = db.get_completion_percentage(&project_id, "Creation").await?;
println!("Phase completion: {:.1}%", percentage);

5. Record Phase Transition

use workspace_core::DbPhaseTransition;

let transition = DbPhaseTransition {
    id: Uuid::new_v4().to_string(),
    project_id: project.id.clone(),
    from_phase: "Creation".to_string(),
    to_phase: "Development".to_string(),
    timestamp: Utc::now().to_rfc3339(),
    reason: Some("Initial setup complete".to_string()),
};

db.record_phase_transition(&transition).await?;
println!("✓ Phase transitioned: Creation → Development");

6. Security Assessment

use workspace_core::DbSecurityAssessment;

let assessment = DbSecurityAssessment {
    id: Uuid::new_v4().to_string(),
    project_id: project.id.clone(),
    profile: "OWASP".to_string(),
    risk_level: "Medium".to_string(),
    passed_rules: 45,
    failed_rules: 5,
    critical_issues: 0,
    assessment_date: Utc::now().to_rfc3339(),
};

db.create_security_assessment(&assessment).await?;
println!("✓ Security assessment recorded");

Deployment Modes

Mode 1: Development (In-Memory)

# Perfect for: Testing, CI/CD, development without server

# In Rust:
let db = SurrealDatabase::new_memory().await?;

# No setup needed!

Pros:

  • No server setup
  • Very fast
  • Perfect for testing

Cons:

  • Data lost on restart
  • Single process only

Mode 2: Local Development (File-Based)

# For local development with persistence

# Start server
surreal start --bind 127.0.0.1:8000 file://~/.local/share/surrealdb.db

# In configuration
[surrealdb]
url = "ws://localhost:8000"

Pros:

  • Persistent data
  • Can run alongside multiple processes
  • Full server features

Cons:

  • Requires server running
  • Single machine only

Mode 3: Docker (Development/Testing)

# Start with Docker Compose
docker-compose -f docker-compose.surrealdb.yml up -d

# Check if running
docker-compose logs surrealdb

# Configuration
[surrealdb]
url = "ws://surrealdb:8000"  # Container hostname
username = "admin"
password = "workspace_password_123"

Pros:

  • Isolated environment
  • Reproducible setup
  • Matches production

Cons:

  • Requires Docker
  • Slightly more overhead

Mode 4: Kubernetes (Production)

# Deploy to Kubernetes cluster
cd k8s && ./deploy.sh

# Configuration
[surrealdb]
url = "ws://surrealdb.workspace:8000"  # K8s service DNS
username = "admin"
password = "${SURREALDB_PASSWORD}"  # From k8s secret
tls_enabled = true

Pros:

  • Production-grade
  • Scalable
  • Managed infrastructure

Cons:

  • Complex setup
  • Requires K8s knowledge

Configuration Examples

Example 1: Local Development

File: configs/database.toml

[database]
engine = "surrealdb"

[surrealdb]
url = "mem://"  # In-memory, no server needed
namespace = "syntaxis"
database = "projects"
max_connections = 5

Example 2: Docker Development

File: configs/database.toml

[database]
engine = "surrealdb"

[surrealdb]
url = "ws://surrealdb:8000"
username = "admin"
password = "dev_password"
namespace = "syntaxis"
database = "projects"
max_connections = 10

Example 3: Production (Kubernetes)

File: configs/database.toml

[database]
engine = "surrealdb"

[surrealdb]
url = "ws://surrealdb.workspace:8000"
username = "admin"
password = "${SURREALDB_PASSWORD}"  # Environment variable
namespace = "syntaxis"
database = "projects"
max_connections = 20
timeout_secs = 60
tls_enabled = true
tls_ca_cert = "/etc/surrealdb/ca.pem"

Testing with SurrealDB

In-Memory Tests

#[tokio::test]
async fn test_project_lifecycle() {
    // No setup needed - in-memory database
    let db = SurrealDatabase::new_memory().await.unwrap();

    // Create project
    let project = DbProject {
        id: "test-1".to_string(),
        name: "Test Project".to_string(),
        // ... other fields ...
    };

    let created = db.create_project(&project).await.unwrap();
    assert_eq!(created.name, "Test Project");

    // Verify retrieval
    let retrieved = db.get_project("test-1").await.unwrap();
    assert!(retrieved.is_some());
}

Server-Mode Tests

#[tokio::test]
async fn test_with_server() {
    // Requires: surreal start --bind 127.0.0.1:8000 memory
    let db = SurrealDatabase::new_server(
        "ws://localhost:8000",
        "syntaxis",
        "projects",
        None,
        None,
    ).await.unwrap();

    // Run your tests...
}

File-Based Tests

#[tokio::test]
async fn test_persistence() {
    let db_path = "/tmp/test_surrealdb.db";

    let db = SurrealDatabase::new_file(db_path).await.unwrap();

    // Create data
    let project = DbProject { /* ... */ };
    db.create_project(&project).await.unwrap();

    // Reload and verify persistence
    let db2 = SurrealDatabase::new_file(db_path).await.unwrap();
    let retrieved = db2.get_project(&project.id).await.unwrap();
    assert!(retrieved.is_some());
}

Switching Between Backends

SQLite to SurrealDB

# Step 1: Update configuration
# configs/database.toml - change engine from "sqlite" to "surrealdb"

# Step 2: Start SurrealDB server
surreal start --bind 127.0.0.1:8000 file:///data/surrealdb.db

# Step 3: Run application with new config
RUST_LOG=info cargo run

# Step 4: Migration (if needed)
# See: SURREALDB_2_3_MIGRATION.md

Quick Switching Script

#!/bin/bash
# Switch between database backends

case "$1" in
  sqlite)
    echo "Switching to SQLite..."
    cp configs/database.toml configs/database.toml.backup
    cp configs/database-default.toml configs/database.toml
    echo "✓ Using SQLite"
    ;;
  surrealdb)
    echo "Switching to SurrealDB..."
    cp configs/database.toml configs/database.toml.backup
    cp configs/database-surrealdb.toml configs/database.toml
    echo "Starting SurrealDB server..."
    surreal start --bind 127.0.0.1:8000 memory &
    echo "✓ Using SurrealDB"
    ;;
  *)
    echo "Usage: $0 {sqlite|surrealdb}"
    ;;
esac

Troubleshooting

"Connection refused" Error

# Check if SurrealDB is running
ps aux | grep surreal

# If not, start it
surreal start --bind 127.0.0.1:8000 memory

# Test connection
curl http://localhost:8000/health
# Should return: {"status":"ok"}

"Authentication failed" Error

// Make sure credentials match server startup
let db = SurrealDatabase::new_server(
    "ws://localhost:8000",
    "syntaxis",
    "projects",
    Some("admin"),           // Must match --username
    Some("your_password"),   // Must match --password
).await?;

"Database already in use" Error

# Port 8000 is already in use
# Use a different port
surreal start --bind 127.0.0.1:8001 memory

# Update configuration
[surrealdb]
url = "ws://localhost:8001"  # New port

Slow Queries

# Enable query logging
surreal start --log debug --bind 127.0.0.1:8000 memory

# Check output for slow queries in logs

Common Patterns

Pattern 1: Batch Operations

async fn create_multiple_items(
    db: &dyn Database,
    items: Vec<DbChecklistItem>,
) -> Result<()> {
    for item in items {
        db.create_checklist_item(&item).await?;
    }
    Ok(())
}

Pattern 2: Error Handling

use workspace_core::error::LifecycleError;

match db.get_project(&id).await {
    Ok(Some(project)) => println!("Found: {}", project.name),
    Ok(None) => println!("Project not found"),
    Err(LifecycleError::Database(msg)) => eprintln!("DB error: {}", msg),
    Err(e) => eprintln!("Other error: {}", e),
}

Pattern 3: Configuration-Driven

use workspace_core::DatabaseConfig;

let config = DatabaseConfig::load_from_file("configs/database.toml")?;

let db = match config.engine.as_str() {
    "surrealdb" => {
        let surreal_config = config.surrealdb.ok_or("No SurrealDB config")?;
        SurrealDatabase::new_server(
            &surreal_config.url,
            &surreal_config.namespace,
            &surreal_config.database,
            surreal_config.username,
            surreal_config.password,
        ).await?
    }
    "sqlite" => {
        // ... SQLite setup ...
    }
    _ => return Err("Unknown database engine".into()),
};

Performance Tips

1. Use Connection Pooling

[surrealdb]
max_connections = 20  # Tune based on load
timeout_secs = 60     # Increase for slow networks

2. Batch Operations

// Good: Multiple operations
for item in items {
    db.create_checklist_item(&item).await?;
}

// Could be optimized with batch API (if available)

3. Index Critical Fields

-- In SurrealDB SQL
DEFINE INDEX idx_project_phase ON TABLE projects COLUMNS current_phase;
DEFINE INDEX idx_item_project ON TABLE checklist_items COLUMNS project_id;

Next Steps

  1. Choose Deployment Mode

    • Development: mem:// (in-memory, fastest)
    • Testing: file:// (persistent, local)
    • Production: Server mode with Docker/K8s
  2. Configure Application

    • Copy appropriate config template
    • Update configs/database.toml
    • Set environment variables if needed
  3. Test Connection

    • Run: cargo run -p syntaxis-cli
    • Execute: syntaxis-cli checklist show
    • Verify: Data is being stored
  4. Learn More


References


Status: Production Ready Last Updated: November 15, 2025 SurrealDB Version: 2.3