System Architecture and Design Decisions
Version: 0.1.0
Last Updated: September 2025
- Overview
- System Architecture
- Component Design
- Data Flow
- Security Model
- Scaling Strategy
- Technology Stack
- Design Decisions
DeeperSensor API is a production-grade Rust backend service that provides a unified HTTP API for interacting with local and remote AI model providers (initially Ollama). The system is designed for:
- High Performance: Async I/O with Tokio runtime
- Type Safety: Leveraging Rust's compile-time guarantees
- Observability: Structured logging, distributed tracing, metrics
- Security: JWT authentication, rate limiting, defense-in-depth
- Scalability: Stateless design, horizontal scaling support
- β Authentication: User signup/login with Argon2id password hashing and JWT tokens
- β Model Abstraction: Provider-agnostic interface for LLM interaction
- β Streaming Support: Server-Sent Events (SSE) for real-time chat responses
- β Rate Limiting: Per-IP and per-user token bucket implementation
- β Persistence: PostgreSQL for users, conversations, and message history
- β Caching: Redis for rate limiting and future session management
- β Reverse Proxy: Nginx with security headers, compression, and request routing
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Internet / Clients β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ
β HTTPS (TLS)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Reverse Proxy (Nginx) β
β β’ TLS Termination β
β β’ Security Headers (CSP, HSTS, X-Frame-Options) β
β β’ Rate Limiting (Nginx layer) β
β β’ Request ID Generation β
β β’ Compression (gzip, brotli) β
β β’ Load Balancing (multi-instance) β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ
β HTTP (internal)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer (Axum) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Middleware Stack β β
β β β’ Request ID Propagation β β
β β β’ Tracing Spans β β
β β β’ CORS β β
β β β’ Security Headers β β
β β β’ Request Size Limits β β
β β β’ Concurrency Limits β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Auth Routes β β Chat Routes β β Model Routes β β
β β β β β β β β
β β β’ Signup β β β’ Chat β β β’ List β β
β β β’ Login β β β’ Stream β β β’ Info β β
β β β’ Refresh β β β β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β βββββββββββββββββββΌββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Business Logic β β
β β β’ Rate Limiting (ds_core) β β
β β β’ JWT Verification (ds_auth) β β
β β β’ Request Validation β β
β β β’ Model Provider Abstraction (ds_model) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββ¬βββββββββββββββββ¬βββββββββββββββββ¬βββββββββββββββββββββββββββββ
β β β
β β β
βΌ βΌ βΌ
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β PostgreSQL β β Redis β β Ollama β
β β β β β β
β β’ Users β β β’ Rate β β β’ Models β
β β’ Sessions β β Limits β β β’ Chat β
β β’ Messages β β β’ Cache β β Inference β
β β’ Audit Log β β β β β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DeeperSensor Workspace β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ β
β β ds-api β β ds-core β β ds-model β β
β β (crate) β β (crate) β β (crate) β β
β β β β β β β β
β β β’ HTTP Server β β β’ Config β β β’ Trait β β
β β β’ Routes β β β’ Error Types β β β’ Ollama Impl β β
β β β’ Middleware β β β’ Rate Limit β β β’ Streaming β β
β β β’ State β β Logic β β β β
β ββββββββββ¬ββββββββ ββββββββββ¬ββββββββ ββββββββββ¬ββββββββ β
β β β β β
β βββββββββββββββββββββΌββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββ β
β β ds-auth (crate) β β
β β β β
β β β’ Password Hashing β β
β β β’ JWT Generation β β
β β β’ Token Validation β β
β ββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Responsibility: HTTP surface layer
- Entry Point:
main.rs- loads config, initializes tracing, builds router, starts server - App Router:
app.rs- constructs the Axum app with middleware layers - Routes:
routes.rs- endpoint definitions for auth, chat, models, health - State:
state.rs- shared application state (DB pool, config, model provider, rate limiters) - Middleware: CORS, security headers, request ID, tracing spans, limits
- Observability:
observability.rs- tracing initialization and formatting
Dependencies: axum, tower, tower-http, tokio, tracing
Responsibility: Core domain types and cross-cutting concerns
- Config:
config.rs- unified configuration loader (env + .env files) - Errors:
error.rs-ApiErrorenum with HTTP status mapping - Rate Limiting: Token bucket algorithm (in-memory with DashMap)
Dependencies: config, dotenvy, thiserror, dashmap
Responsibility: LLM provider abstraction
- Trait:
ModelProvider- defineslist_models(),chat(),chat_stream() - Ollama:
OllamaClient- HTTP client for Ollama API - Types:
ChatRequest,ChatMessage,ChatChunk,ModelInfo
Dependencies: reqwest, async-trait, serde, futures-util
Responsibility: Authentication and authorization
- Password Hashing: Argon2id with configurable parameters
- JWT: HS256 signing, access/refresh token generation
- Token Verification: Claim extraction and validation
Dependencies: argon2, jsonwebtoken, uuid, chrono
Centralized in workspace Cargo.toml:
[workspace.dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"] }
axum = { version = "0.7", features = ["macros", "json"] }
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }
# ... etc1. Client Request
β
βββΆ [Nginx]
β ββ TLS Termination
β ββ Generate Request ID (if missing)
β ββ Rate Limit Check (Nginx layer)
β ββ Security Headers
β ββ Forward to API
β
βββΆ [Axum Middleware Stack]
β ββ Request ID Propagation
β ββ Tracing Span Creation
β ββ CORS Preflight Handling
β ββ Request Size Validation
β ββ Concurrency Limits
β
βββΆ [Route Handler]
β ββ Extract State<AppState>
β ββ Rate Limit Check (application layer)
β ββ JWT Verification (if protected)
β ββ Request Validation
β ββ Business Logic
β
βββΆ [External Services]
β ββ Database Query (sqlx)
β ββ Redis Access (future)
β ββ Ollama API Call
β
βββΆ [Response]
ββ Serialize to JSON / SSE
ββ Add Response Headers
ββ Log Completion (tracing)
ββ Return to Client
ββββββββββββ ββββββββββββ
β Client β β API β
ββββββ¬ββββββ ββββββ¬ββββββ
β β
β POST /v1/auth/signup β
β { email, password } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββΆ
β β
β [Validate Input]
β [Hash Password (Argon2)]
β [Insert User (DB)]
β β
β 201 Created β
β { id, email } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β POST /v1/auth/login β
β { email, password } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββΆ
β β
β [Lookup User (DB)]
β [Verify Password]
β [Generate JWT Access Token]
β [Generate Refresh Token]
β β
β 200 OK β
β { access_token, refresh_token } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β POST /v1/chat β
β Authorization: Bearer <access_token> β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββΆ
β β
β [Verify JWT]
β [Extract Claims]
β [Authorize Request]
β [Process Chat]
β β
β 200 OK β
β { ... chat response ... } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
Layer 1: Network (Nginx)
- TLS 1.3 (or 1.2 minimum)
- Strong cipher suites
- Rate limiting (per IP)
- Request size limits (2MB default)
- Security headers (HSTS, CSP, X-Frame-Options, etc.)
Layer 2: Application (Axum)
- CORS policy enforcement
- JWT verification middleware
- Request validation (email format, length limits)
- Rate limiting (per user + per IP)
- Input sanitization
- SQL injection protection (parameterized queries via sqlx)
Layer 3: Authentication (ds-auth)
- Argon2id password hashing (memory-hard, GPU-resistant)
- JWT with HS256 (future: RS256 for distributed systems)
- Short-lived access tokens (15 minutes default)
- Refresh token rotation
Layer 4: Database
- Least privilege principle (app-specific DB user)
- Connection pooling with limits
- No raw SQL construction
- Prepared statements only
Layer 5: Container (Docker)
- Non-root user (UID 65534)
- Read-only filesystem
- Dropped capabilities (
CAP_DROP: ALL) - No new privileges (
no-new-privileges:true)
- Development:
.envfile (excluded from Git) - Production: Environment variables from secret management systems
- AWS Secrets Manager
- HashiCorp Vault
- Kubernetes Secrets
- Docker Swarm Secrets
All security-relevant events are logged with structured fields:
{
"timestamp": "2025-09-29T12:34:56Z",
"level": "WARN",
"target": "api::routes::auth",
"message": "Failed login attempt",
"email": "user@example.com",
"ip": "192.168.1.100",
"request_id": "abc123"
}The API is stateless (except for in-memory rate limiters, which will migrate to Redis):
βββββββββββββββββββββββββββββββββββββββ
β Load Balancer (Nginx/ALB) β
ββββββββββββ¬βββββββββββ¬ββββββββββββββββ
β β
ββββββββΌββββ ββββΌββββββββ βββββββββββββ
β API-1 β β API-2 β β API-3 β
ββββββββ¬ββββ ββββ¬ββββββββ βββββββ¬ββββββ
β β β
βββββββββββΌβββββββββββββββββ
β
ββββββββββββΌβββββββββββ
β Shared Database β
β (Postgres) β
βββββββββββββββββββββββ
Scaling Considerations:
- Database Connections: Each instance maintains its own connection pool (configurable limit)
- Rate Limiting: Move to Redis-backed token buckets for shared state
- Session Affinity: Not required (stateless JWT)
- Shared Filesystem: Not required (all state in DB)
Resource limits (docker-compose.prod.yml):
api:
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512MTuning Parameters:
- Database connection pool size
- HTTP server concurrency limits
- Request size limits
- Rate limit buckets
Read Replicas: Use sqlx with read/write split (future enhancement)
struct AppState {
write_pool: PgPool,
read_pool: PgPool,
}Connection Pooling: Already implemented via sqlx::PgPool
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Language | Rust | 1.82+ | Systems programming, performance, safety |
| Runtime | Tokio | 1.x | Async I/O, multi-threaded executor |
| HTTP Framework | Axum | 0.7 | Web server, routing, middleware |
| Database | PostgreSQL | 16 | Relational data persistence |
| Cache | Redis | 7 | Rate limiting, sessions (future) |
| ORM | SQLx | 0.7 | Compile-time SQL verification |
| Serialization | Serde | 1.x | JSON encoding/decoding |
| Logging | Tracing | 0.1 | Structured logging, distributed tracing |
| Auth | Argon2, JWT | Latest | Password hashing, token-based auth |
| Component | Technology | Purpose |
|---|---|---|
| Container | Docker | 24.0+ |
| Orchestration | Docker Compose / K8s | Service management |
| Reverse Proxy | Nginx | 1.27 |
| CI/CD | GitHub Actions | Automated testing, builds, deployments |
| Monitoring | Prometheus + Grafana | Metrics, dashboards |
| Logging | Loki (optional) | Log aggregation |
- Performance: Near-C performance with zero-cost abstractions
- Safety: Memory safety without garbage collection
- Concurrency: Fearless concurrency with ownership system
- Tooling: Cargo, rustfmt, clippy, excellent ecosystem
- Ecosystem Alignment: Built on top of Tokio and Tower (industry standard)
- Type Safety: Leverages Rust's type system for compile-time correctness
- Extractors: Ergonomic request handling
- Middleware: Tower middleware ecosystem
- Async Support: Native async/await (Diesel is sync)
- Compile-Time Verification: SQL queries checked at compile time
- Flexibility: Raw SQL with type safety, less ORM magic
- Stateless: No server-side session storage (easier to scale)
- Distributed: Works across multiple API instances
- Standard: Industry-standard token format (RFC 7519)
- Tradeoff: Cannot revoke tokens before expiry (mitigated with short TTL + refresh tokens)
- Simplicity: HTTP-based, easier to implement and debug
- Proxying: Works through standard HTTP proxies/load balancers
- Reconnection: Browser handles auto-reconnect
- Tradeoff: Unidirectional (serverβclient only)
- Redis Integration: Move rate limiting to Redis for shared state
- OpenTelemetry: Distributed tracing across services
- Read Replicas: Database scaling with read/write split
- GraphQL API: Alternative to REST for complex queries
- gRPC: Internal service-to-service communication
- Message Queue: Async job processing (Kafka, RabbitMQ)
Document Version: 1.0.0
Last Review: September 2025
Next Review: December 2025