System Architecture
Full-stack Cloudflare edge architecture: Workers + D1 + KV + R2 + DO + Queues + AI + Vectorize. Zero cold starts, globally distributed.
Deployment Topology
┌─────────────────────────────────────┐
│ societee.pages.dev │
│ (React 19 SPA — Cloudflare Pages) │
└──────────┬──────────────┬────────────┘
│ │
┌──────────▼──────┐ ┌─────▼──────────────────┐
│ societee. │ │ auth.societee. │
│ workers.dev │ │ workers.dev │
│ (Hono API) │ │ (OpenAuth Server) │
└──────────┬──────┘ └─────┬──────────────────┘
│ │
┌────────────────┼──────────────┼────────────────┐
│ │ │ │
┌─────────▼──┐ ┌─────────▼──┐ ┌────────▼──┐ ┌─────────▼──┐
│ D1: │ │ D1: │ │ KV: │ │ R2: │
│ societee-db│ │ auth-db │ │ KV_CACHE │ │ societee- │
│ (113 tbls) │ │ (users) │ │ AUTH_STORE│ │ vault │
└────────────┘ └────────────┘ └───────────┘ └────────────┘
│ │ │ │
┌─────────▼────────────────▼──────────────▼────────────────▼──┐
│ Cloudflare Edge │
│ Queues (async tasks) · Workers AI (7 agents) │
│ Vectorize (RAG index) · DO (GateSync + SOS broadcast) │
└────────────────────────────────────────────────────────────┘
Cloudflare Resources
| Resource | Name | Purpose |
|---|---|---|
| D1 Database | societee-db | 113 tables — all app data (societies, users, billing, accounting, complaints, etc.) |
| D1 Database | societee-auth-db | OpenAuth user records, sessions, refresh tokens |
| KV Namespace | KV_CACHE | Rate limiting, session store, feature flag cache (5-min TTL), RBAC permission cache |
| KV Namespace | AUTH_STORAGE | OpenAuth token storage, authorization codes |
| R2 Bucket | societee-vault | Invoices, receipts, documents, profile photos, feed media |
| Queue | societee-events-queue | Async billing runs, notification dispatch, audit log writes |
| Vectorize | societee-rag-index | RAG embedding index for bylaws, policies, legal documents |
| Workers AI | (built-in) | 7 AI agents: accountant, secretary, compliance, communication, analytics, gatekeeper, emergency |
| Durable Object | GateSyncDO | Real-time WebSocket hub for guard terminal sync (368 lines) |
| Durable Object | EmergencySosDO | Emergency SOS broadcast hub (377 lines) |
Middleware Pipeline
Applied globally in order (from src/index.ts):
1. Security Headers — CSP nonce, HSTS, X-Frame-Options DENY
2. Output Sanitization — Auto-strip PII from responses
3. Audit Logger — Immutable hash-chain audit trail for all mutations
4. Request Logger — Request ID, timing, correlation
5. Multi-Tenant Isolation— X-Tenant-ID / X-Society-ID header extraction
6. JWT Auth + ABAC — Applied per-route-group
7. Request Signing — HMAC-SHA256 nonce + timestamp
8. Anomaly Detection — 6-signal behavioral analysis
9. Global Error Handler — Catch-all with error sanitization
Request Flow
Client Request (Authorization: Bearer <jwt>, X-Tenant-ID: <society_id>)
│
├─→ Security Headers middleware
├─→ Output Sanitization middleware
├─→ Audit Logger middleware
├─→ Request Logger middleware
├─→ Multi-Tenant Isolation (extracts society_id)
│
├─→ authMiddleware() — verifies JWT, loads user + roles + permissions
├─→ abacMiddleware() — checks ABAC conditions
│
├─→ enhancedRateLimit('READ'|'WRITE') — per-user + per-IP
├─→ requireFeature('feature.key') — checks society_features table (KV-cached)
│
├─→ Route Handler (Hono)
│ ├─→ Zod schema validation
│ ├─→ D1 query (all queries bound to society_id)
│ └─→ Response with PII sanitized
│
└─→ Response (Access-Control-Allow-Origin: *, security headers)
Multi-Tenancy
Every single D1 table includes a society_id TEXT NOT NULL foreign key. Every query is scoped by this. The tenant ID is extracted from the X-Tenant-ID or X-Society-ID request header by the Multi-Tenant Isolation middleware.
-- Every query is automatically scoped
SELECT * FROM invoices WHERE society_id = ? AND status = 'OVERDUE'
-- Middleware extracts tenant from header
const societyId = c.get('tenantId') || c.get('user')?.activeContext?.tenantId
Real-Time Architecture
Authentication Flow
┌─────────────────────────────────────────────────────────────┐
│ AUTHENTICATION OPTIONS │
├─────────────────────────────────────────────────────────────┤
│ │
│ Option A: OpenAuth (primary) │
│ ───────────────────────── │
│ 1. Frontend redirects to auth.societee.workers.dev │
│ 2. User logs in via email + verification code │
│ 3. OpenAuth looks up/creates user in societee-db │
│ 4. Returns JWT: { id, email, name } │
│ 5. Frontend stores access_token + refresh_token │
│ 6. Backend verifies via OpenAuth JWKS endpoint │
│ │
│ Option B: PBKDF2 (legacy/fallback) │
│ ───────────────────────────────── │
│ 1. POST /v1/auth/login with email + password │
│ 2. PBKDF2 (SHA-256, 100K iterations) password verify │
│ 3. HMAC-SHA256 JWT signed (15min access, 7d refresh) │
│ 4. Refresh token rotation on /v1/auth/refresh │
│ │
│ Both paths populate: roles, permissions, persona, context │
└─────────────────────────────────────────────────────────────┘
Persona System
JWT contains active_context (persona_id, tenant_id, role, unit_id, permissions) + available_contexts array. Persona switching via X-Societee-Persona-ID header or /v1/auth/switch-persona endpoint. Frontend stores mode in localStorage('societee_mode') as 'resident' | 'official'.
AI Agent Architecture
7 specialized AI agents dispatched via Cloudflare Workers AI. Each agent has a dedicated prompt template, access to specific tools, and can request human approval before executing actions.
POST /v1/ai/copilot/swarm
Body: { "query": "Summarize all overdue invoices above ₹5000" }
Response: {
"agent": "accountant",
"response": "Found 12 overdue invoices totaling ₹1,24,500...",
"sources": ["invoices table", "payment history"]
}
Edge Latency Profile
| Operation | Location | Expected Latency |
|---|---|---|
| JWT verification | Edge Worker | < 5ms |
| D1 read query | Edge (nearest replica) | 5-15ms |
| KV cache hit | Edge (global) | < 5ms |
| R2 presigned URL | Edge Worker | < 10ms |
| Workers AI inference | Edge | 100-500ms |
| Full API request (auth + query + response) | Edge | 15-50ms |
| WebSocket DO message | Edge | < 10ms |