Fixed:
- Price: €800K-€1.5M, Sunseeker added
- Agent 1: Joe Trader persona + actual sale ads research
- Ignored meilisearch binary + data/ (too large for GitHub)
- SESSION_DEBUG_BLOCKERS.md created
Ready for Session 1 launch.
🤖 Generated with Claude Code
745 lines
53 KiB
Markdown
745 lines
53 KiB
Markdown
# NaviDocs Multi-Tenancy Architecture
|
|
## Visual System Design
|
|
|
|
---
|
|
|
|
## High-Level Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ CLIENT APPLICATION │
|
|
│ (React Frontend - Port 3000) │
|
|
│ │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ Login/ │ │ Entity │ │ Document │ │
|
|
│ │ Register │ │ Management │ │ Viewer │ │
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
│ │
|
|
│ Sends: Authorization: Bearer <JWT> │
|
|
└───────────────────────────────┬─────────────────────────────────────────┘
|
|
│
|
|
│ HTTPS
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ API GATEWAY LAYER │
|
|
│ (Express.js - Port 8001) │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ MIDDLEWARE CHAIN │ │
|
|
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
|
|
│ │ │ Helmet │→│ CORS │→│ Rate │→│ Request │ │ │
|
|
│ │ │ (CSP) │ │ │ │ Limiter │ │ Logger │ │ │
|
|
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────────────────┐ ┌──────────────────────────────┐ │ │
|
|
│ │ │ authenticateToken │→│ requireEntityAccess │ │ │
|
|
│ │ │ - Verify JWT │ │ - Check entity permissions │ │ │
|
|
│ │ │ - Load user │ │ - Enforce access control │ │ │
|
|
│ │ │ - Attach to req.user │ │ │ │ │
|
|
│ │ └──────────────────────┘ └──────────────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ ROUTES │ │
|
|
│ │ │ │
|
|
│ │ /api/auth/* /api/entities/* /api/documents/* │ │
|
|
│ │ ├─ register ├─ GET / ├─ GET /:id │ │
|
|
│ │ ├─ login ├─ POST / ├─ GET / │ │
|
|
│ │ ├─ logout ├─ GET /:id ├─ DELETE /:id │ │
|
|
│ │ ├─ refresh ├─ PATCH /:id └─ GET /:id/pdf │ │
|
|
│ │ ├─ forgot-password ├─ DELETE /:id │ │
|
|
│ │ ├─ reset-password └─ /:id/permissions │ │
|
|
│ │ └─ verify-email/:token │ │
|
|
│ │ │ │
|
|
│ │ /api/organizations/* /api/users/* /api/search/* │ │
|
|
│ │ ├─ GET / ├─ GET /:id ├─ POST / │ │
|
|
│ │ ├─ POST / ├─ PATCH /:id └─ GET /suggest │ │
|
|
│ │ ├─ GET /:id └─ DELETE /:id │ │
|
|
│ │ ├─ PATCH /:id │ │
|
|
│ │ ├─ DELETE /:id │ │
|
|
│ │ ├─ GET /:id/members │ │
|
|
│ │ ├─ POST /:id/members │ │
|
|
│ │ ├─ PATCH /:id/members/:userId │ │
|
|
│ │ └─ DELETE /:id/members/:userId │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
└───────────────────────────────┬─────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICE LAYER │
|
|
│ (Business Logic Modules) │
|
|
│ │
|
|
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
|
|
│ │ AuthService │ │ AuthzService │ │ UserService │ │
|
|
│ │ ──────────────── │ │ ──────────────── │ │ ──────────────── │ │
|
|
│ │ • register() │ │ • checkEntity │ │ • getUser() │ │
|
|
│ │ • login() │ │ Permission() │ │ • updateUser() │ │
|
|
│ │ • logout() │ │ • checkOrg │ │ • deleteUser() │ │
|
|
│ │ • refresh() │ │ Permission() │ │ • suspendUser() │ │
|
|
│ │ • forgotPwd() │ │ • grantEntity │ │ │ │
|
|
│ │ • resetPwd() │ │ Permission() │ │ │ │
|
|
│ │ • verifyEmail() │ │ • revokeEntity │ │ │ │
|
|
│ │ │ │ Permission() │ │ │ │
|
|
│ │ │ │ • getEntityUsers │ │ │ │
|
|
│ │ │ │ • getUserEntities│ │ │ │
|
|
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
|
|
│ │ OrgService │ │ AuditService │ │ SearchService │ │
|
|
│ │ ──────────────── │ │ ──────────────── │ │ ──────────────── │ │
|
|
│ │ • createOrg() │ │ • logEvent() │ │ • indexDoc() │ │
|
|
│ │ • updateOrg() │ │ • queryLogs() │ │ • search() │ │
|
|
│ │ • deleteOrg() │ │ • getUserEvents()│ │ │ │
|
|
│ │ • addMember() │ │ • cleanupLogs() │ │ │ │
|
|
│ │ • removeMember() │ │ │ │ │ │
|
|
│ │ • updateRole() │ │ │ │ │ │
|
|
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
|
|
│ │
|
|
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
│ │ LRU CACHE (Permission Resolution) │ │
|
|
│ │ Key: "entity:{userId}:{entityId}:{permission}" │ │
|
|
│ │ TTL: 5 minutes │ │
|
|
│ │ Max Entries: 10,000 │ │
|
|
│ └────────────────────────────────────────────────────────────────┘ │
|
|
└───────────────────────────────┬─────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ DATA ACCESS LAYER │
|
|
│ │
|
|
│ ┌───────────────────────────────────────────────────────────────┐ │
|
|
│ │ SQLite Database │ │
|
|
│ │ (WAL mode, Foreign Keys enabled) │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │ │
|
|
│ │ │ users │ │ organizations │ │ entities │ │ │
|
|
│ │ │ ─────────────── │ │ ─────────────── │ │ ────────────│ │ │
|
|
│ │ │ id │ │ id │ │ id │ │ │
|
|
│ │ │ email (UNIQUE) │ │ name │ │ name │ │ │
|
|
│ │ │ password_hash │ │ type │ │ entity_type │ │ │
|
|
│ │ │ status │ │ │ │ org_id (FK) │ │ │
|
|
│ │ │ email_verified │ │ │ │ │ │ │
|
|
│ │ └─────────────────┘ └─────────────────┘ └──────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────────────────┐ ┌──────────────────────────────┐ │ │
|
|
│ │ │ user_organizations │ │ entity_permissions │ │ │
|
|
│ │ │ ──────────────────── │ │ ──────────────────────────── │ │ │
|
|
│ │ │ user_id (FK) │ │ user_id (FK) │ │ │
|
|
│ │ │ organization_id (FK) │ │ entity_id (FK) │ │ │
|
|
│ │ │ role (admin/...) │ │ permission_level (viewer/...)│ │ │
|
|
│ │ │ joined_at │ │ granted_by (FK) │ │ │
|
|
│ │ │ │ │ expires_at │ │ │
|
|
│ │ └──────────────────────┘ └──────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────────────────┐ ┌──────────────────────────────┐ │ │
|
|
│ │ │ refresh_tokens │ │ password_reset_tokens │ │ │
|
|
│ │ │ ──────────────────── │ │ ──────────────────────────── │ │ │
|
|
│ │ │ user_id (FK) │ │ user_id (FK) │ │ │
|
|
│ │ │ token_hash │ │ token_hash │ │ │
|
|
│ │ │ device_info │ │ expires_at │ │ │
|
|
│ │ │ revoked │ │ used │ │ │
|
|
│ │ └──────────────────────┘ └──────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────────────────┐ ┌──────────────────────────────┐ │ │
|
|
│ │ │ audit_log │ │ documents │ │ │
|
|
│ │ │ ──────────────────── │ │ ──────────────────────────── │ │ │
|
|
│ │ │ user_id (FK) │ │ organization_id (FK) │ │ │
|
|
│ │ │ event_type │ │ entity_id (FK) │ │ │
|
|
│ │ │ resource_type │ │ uploaded_by (FK) │ │ │
|
|
│ │ │ status │ │ title │ │ │
|
|
│ │ │ ip_address │ │ file_path │ │ │
|
|
│ │ └──────────────────────┘ └──────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ Indexes: │ │
|
|
│ │ • idx_entity_perms_user, idx_entity_perms_entity │ │
|
|
│ │ • idx_audit_user, idx_audit_event, idx_audit_created │ │
|
|
│ │ • idx_documents_org, idx_documents_entity │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Meilisearch (Full-Text Search) │ │
|
|
│ │ Index: navidocs-pages │ │
|
|
│ │ Documents: { docId, pageNumber, ocrText, ... } │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Redis (BullMQ Job Queue) │ │
|
|
│ │ Queue: ocr-jobs │ │
|
|
│ │ Workers: PDF extraction, OCR processing │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Authentication Flow
|
|
|
|
```
|
|
┌─────────┐ ┌─────────┐
|
|
│ Client │ │ Server │
|
|
└────┬────┘ └────┬────┘
|
|
│ │
|
|
│ 1. POST /api/auth/register │
|
|
│ { email, password, name } │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 2. Validate input │
|
|
│ 3. Hash password │
|
|
│ 4. Create user record │
|
|
│ 5. Create personal org │
|
|
│ 6. Generate verify token│
|
|
│ │
|
|
│ { user, message: "Verify email" } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 7. POST /api/auth/login │
|
|
│ { email, password } │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 8. Validate credentials│
|
|
│ 9. Check account status│
|
|
│ 10. Generate JWT (15min)│
|
|
│ 11. Generate refresh token│
|
|
│ 12. Store refresh hash │
|
|
│ 13. Log audit event │
|
|
│ │
|
|
│ { accessToken, refreshToken, user } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 14. GET /api/documents │
|
|
│ Authorization: Bearer <JWT> │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 15. Verify JWT signature│
|
|
│ 16. Check expiry │
|
|
│ 17. Load user │
|
|
│ 18. Check permissions │
|
|
│ 19. Return documents │
|
|
│ │
|
|
│ { documents: [...] } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ [15 minutes later] │
|
|
│ │
|
|
│ 20. GET /api/documents │
|
|
│ Authorization: Bearer <expired JWT> │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 21. Verify JWT → EXPIRED│
|
|
│ │
|
|
│ { error: "Token expired" } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 22. POST /api/auth/refresh │
|
|
│ { refreshToken } │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 23. Validate refresh token│
|
|
│ 24. Check revoked status│
|
|
│ 25. Generate new JWT │
|
|
│ │
|
|
│ { accessToken } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 26. POST /api/auth/logout │
|
|
│ { refreshToken } │
|
|
├────────────────────────────────────────────────────────────>│
|
|
│ │
|
|
│ 27. Revoke refresh token│
|
|
│ 28. Log audit event │
|
|
│ │
|
|
│ { success: true } │
|
|
│<────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
```
|
|
|
|
---
|
|
|
|
## Authorization Resolution Flow
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|
│ User requests access to Entity (e.g., GET /api/entities/boat-123) │
|
|
└────────────────────────────────┬─────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────┐
|
|
│ Check LRU Cache │
|
|
│ Key: entity:userId:entityId:permission │
|
|
└────────────┬────────────────────────────┘
|
|
│
|
|
┌──────────┴──────────┐
|
|
│ │
|
|
Cache Cache
|
|
Hit Miss
|
|
│ │
|
|
▼ ▼
|
|
┌──────────────┐ ┌──────────────────────────────────────┐
|
|
│ Return │ │ STEP 1: Check Organization Role │
|
|
│ Cached │ │ ──────────────────────────────────── │
|
|
│ Result │ │ SELECT uo.role │
|
|
└──────────────┘ │ FROM user_organizations uo │
|
|
│ INNER JOIN entities e │
|
|
│ ON e.organization_id = uo.org_id │
|
|
│ WHERE uo.user_id = ? AND e.id = ? │
|
|
└────────────┬─────────────────────────┘
|
|
│
|
|
┌──────────────────┼──────────────────┐
|
|
│ │ │
|
|
Org Admin Org Manager Org Member/Viewer
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌────────────┐ ┌────────────┐ ┌─────────────────┐
|
|
│ ALLOW ALL │ │ Check perm │ │ STEP 2: Check │
|
|
│ PERMISSIONS│ │ in manager │ │ Entity Permission│
|
|
└────────────┘ │ scope │ │ ─────────────────│
|
|
└────────────┘ │ SELECT perm_level│
|
|
│ │ FROM entity_perms│
|
|
│ │ WHERE user_id=? │
|
|
│ │ AND entity_id=?│
|
|
│ └─────────┬────────┘
|
|
│ │
|
|
│ ┌─────────┴────────┐
|
|
│ │ │
|
|
│ Found Perm Not Found
|
|
│ │ │
|
|
│ ▼ ▼
|
|
│ ┌──────────────┐ ┌──────────────┐
|
|
│ │ Check if │ │ STEP 3: Check│
|
|
│ │ permission │ │ Legacy Perms │
|
|
│ │ in hierarchy │ │ (backward │
|
|
│ │ (viewer→ │ │ compat) │
|
|
│ │ editor→ │ │ │
|
|
│ │ manager→ │ └──────┬───────┘
|
|
│ │ admin) │ │
|
|
│ └──────┬───────┘ │
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌───────────────────────────────────────┐
|
|
│ Permission Resolution │
|
|
│ ────────────────────────────────────│
|
|
│ • Admin: All permissions │
|
|
│ • Manager: view, edit, create, │
|
|
│ delete, share │
|
|
│ • Editor: view, edit, create │
|
|
│ • Viewer: view only │
|
|
└─────────────┬─────────────────────────┘
|
|
│
|
|
┌────────────┴────────────┐
|
|
│ │
|
|
ALLOW DENY
|
|
│ │
|
|
▼ ▼
|
|
┌──────────────────┐ ┌──────────────────┐
|
|
│ Cache result │ │ Cache result │
|
|
│ Return true │ │ Return false │
|
|
│ Proceed to │ │ Return 403 │
|
|
│ business logic │ │ Forbidden │
|
|
└──────────────────┘ └──────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Permission Hierarchy
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ PERMISSION LEVELS │
|
|
│ (Higher includes all lower) │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌───────────────┐
|
|
│ ADMIN │ Full control: view, edit, create, delete,
|
|
│ ──────────────│ share, manage_users, manage_permissions
|
|
└───────┬───────┘
|
|
│ Includes ↓
|
|
┌───────┴───────┐
|
|
│ MANAGER │ Management: view, edit, create, delete, share
|
|
│ ──────────────│
|
|
└───────┬───────┘
|
|
│ Includes ↓
|
|
┌───────┴───────┐
|
|
│ EDITOR │ Content: view, edit, create
|
|
│ ──────────────│
|
|
└───────┬───────┘
|
|
│ Includes ↓
|
|
┌───────┴───────┐
|
|
│ VIEWER │ Read-only: view
|
|
│ ──────────────│
|
|
└───────────────┘
|
|
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ ORGANIZATION ROLES vs ENTITY PERMISSIONS │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
Organization Level Entity Level (Override)
|
|
(Broad Access) (Granular Access)
|
|
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
|
│ Org Admin │ ───────────> │ Full access to │
|
|
│ • All entities │ │ ALL entities │
|
|
│ • User management │ │ (Cannot be limited) │
|
|
└─────────────────────┘ └─────────────────────┘
|
|
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
|
│ Org Manager │ ───────────> │ View/Edit all │
|
|
│ • All entities │ │ entities by default │
|
|
│ • Limited user mgmt │ │ (Can be extended to │
|
|
└─────────────────────┘ │ admin on specific) │
|
|
└─────────────────────┘
|
|
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
|
│ Org Member │ ───────────> │ Access based on │
|
|
│ • No default access │ │ entity_permissions │
|
|
│ • Requires explicit │ │ table (explicit │
|
|
│ entity grants │ │ grants required) │
|
|
└─────────────────────┘ └─────────────────────┘
|
|
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
|
│ Org Viewer │ ───────────> │ Read-only access to │
|
|
│ • View all entities │ │ all entities │
|
|
│ • No modifications │ │ (Cannot be elevated │
|
|
└─────────────────────┘ │ without org role) │
|
|
└─────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Multi-Tenancy Model
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────────────────┐
|
|
│ MULTI-VERTICAL STRUCTURE │
|
|
│ (Organization → Entities → Documents) │
|
|
└────────────────────────────────────────────────────────────────────┘
|
|
|
|
Organization: "Coastal Marine Services"
|
|
│
|
|
├─ User Memberships:
|
|
│ ├─ Alice (admin)
|
|
│ ├─ Bob (manager)
|
|
│ ├─ Carol (member)
|
|
│ └─ Dave (viewer)
|
|
│
|
|
└─ Entities (Cross-Vertical):
|
|
│
|
|
├─ Entity: Boat "Sea Breeze" (id: boat-001)
|
|
│ │ Type: boat
|
|
│ │ Organization: Coastal Marine Services
|
|
│ │
|
|
│ ├─ Entity Permissions:
|
|
│ │ ├─ Alice: admin (from org role)
|
|
│ │ ├─ Bob: manager (from org role)
|
|
│ │ ├─ Carol: editor (explicit grant)
|
|
│ │ └─ Dave: viewer (from org role)
|
|
│ │
|
|
│ └─ Documents:
|
|
│ ├─ Owner's Manual.pdf
|
|
│ ├─ Engine Service Record.pdf
|
|
│ └─ Safety Certificate.pdf
|
|
│
|
|
├─ Entity: Boat "Ocean Rider" (id: boat-002)
|
|
│ │ Type: boat
|
|
│ │
|
|
│ ├─ Entity Permissions:
|
|
│ │ ├─ Alice: admin (from org role)
|
|
│ │ ├─ Bob: manager (from org role)
|
|
│ │ ├─ Carol: NO ACCESS (not granted)
|
|
│ │ └─ Dave: viewer (from org role)
|
|
│ │
|
|
│ └─ Documents:
|
|
│ └─ Charter Contract.pdf
|
|
│
|
|
├─ Entity: Marina "Harbor Bay" (id: marina-001)
|
|
│ │ Type: marina (different vertical!)
|
|
│ │
|
|
│ ├─ Entity Permissions:
|
|
│ │ ├─ Alice: admin
|
|
│ │ ├─ Bob: admin (explicit grant)
|
|
│ │ └─ Carol, Dave: NO ACCESS
|
|
│ │
|
|
│ └─ Documents:
|
|
│ ├─ Dock Layout.pdf
|
|
│ └─ Safety Procedures.pdf
|
|
│
|
|
└─ Entity: Aircraft "Cessna N12345" (id: aircraft-001)
|
|
│ Type: aircraft (another vertical!)
|
|
│
|
|
├─ Entity Permissions:
|
|
│ └─ Alice: admin (only Alice has access)
|
|
│
|
|
└─ Documents:
|
|
└─ Pilot Operating Handbook.pdf
|
|
|
|
|
|
VERTICAL AGNOSTIC DESIGN:
|
|
──────────────────────────
|
|
All verticals (boat, aircraft, marina, condo, etc) use the SAME:
|
|
• Database schema
|
|
• Permission model
|
|
• Authorization logic
|
|
• API endpoints
|
|
|
|
The "entity_type" field differentiates verticals, but logic is identical.
|
|
```
|
|
|
|
---
|
|
|
|
## Security Layers
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ DEFENSE IN DEPTH │
|
|
│ (Multiple layers of security) │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
|
|
Layer 1: Network Security
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • HTTPS/TLS encryption │
|
|
│ • CORS policy (restrict origins) │
|
|
│ • Rate limiting (prevent DDoS) │
|
|
│ • IP-based blocking (optional) │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
Layer 2: Application Security
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • Helmet.js (CSP, XSS protection) │
|
|
│ • Input validation (sanitize all inputs) │
|
|
│ • SQL injection prevention (prepared statements) │
|
|
│ • Error handling (don't leak system info) │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
Layer 3: Authentication
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • JWT signature verification │
|
|
│ • Token expiry enforcement │
|
|
│ • Refresh token rotation │
|
|
│ • Account status checks (active/suspended) │
|
|
│ • Brute force protection (rate limiting) │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
Layer 4: Authorization
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • Organization membership validation │
|
|
│ • Entity-level permission checks │
|
|
│ • Resource ownership verification │
|
|
│ • Permission hierarchy enforcement │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
Layer 5: Data Security
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • Password hashing (bcrypt, cost=12) │
|
|
│ • Token hashing (refresh tokens, reset tokens) │
|
|
│ • Sensitive data encryption (at rest) │
|
|
│ • Foreign key constraints (data integrity) │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
Layer 6: Audit & Monitoring
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ • Security event logging (all auth events) │
|
|
│ • Failed login tracking │
|
|
│ • Permission change logging │
|
|
│ • Anomaly detection (future: ML-based) │
|
|
│ • Compliance reporting (GDPR, SOC2) │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Scalability Considerations
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────────────┐
|
|
│ HORIZONTAL SCALING STRATEGY │
|
|
└────────────────────────────────────────────────────────────────┘
|
|
|
|
Current (Single Server):
|
|
┌─────────────────┐
|
|
│ Express API │
|
|
│ + SQLite DB │ ──> Max: ~1000 concurrent users
|
|
└─────────────────┘
|
|
|
|
Phase 2 (Load Balanced):
|
|
┌─────────────────┐
|
|
│ Load Balancer │
|
|
└────────┬────────┘
|
|
│
|
|
┌────┼────┐
|
|
│ │ │
|
|
┌───▼┐ ┌─▼──┐ ┌▼───┐
|
|
│API │ │API │ │API │ (Stateless JWT = easy to scale)
|
|
└───┬┘ └─┬──┘ └┬───┘
|
|
│ │ │
|
|
└────┼────┘
|
|
│
|
|
┌────────▼────────┐
|
|
│ PostgreSQL │ ──> Max: ~10,000 concurrent users
|
|
│ (Master-Slave) │
|
|
└─────────────────┘
|
|
|
|
Phase 3 (Multi-Region):
|
|
┌──────────────────────────────────────────────────────────────┐
|
|
│ CDN / Global Load Balancer │
|
|
└───────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌───────────┼───────────┐
|
|
│ │
|
|
┌───────▼────────┐ ┌────────▼───────┐
|
|
│ Region: US │ │ Region: EU │
|
|
│ ──────────── │ │ ──────────── │
|
|
│ API Servers │ │ API Servers │
|
|
│ Read Replicas │ │ Read Replicas │
|
|
└───────┬────────┘ └────────┬───────┘
|
|
│ │
|
|
└───────────┬───────────┘
|
|
│
|
|
┌───────▼───────┐
|
|
│ PostgreSQL │ ──> Max: 100,000+ users
|
|
│ Multi-Master │
|
|
│ Replication │
|
|
└───────────────┘
|
|
|
|
|
|
Permission Cache Strategy:
|
|
──────────────────────────
|
|
• LRU cache per API server (in-memory)
|
|
• TTL: 5 minutes
|
|
• Invalidation: On permission change
|
|
• Reduces DB queries by 80-90%
|
|
• Scales linearly with server count
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
```
|
|
navidocs/server/
|
|
│
|
|
├── config/
|
|
│ ├── db.js # Database connection config
|
|
│ └── meilisearch.js # Search client config
|
|
│
|
|
├── db/
|
|
│ ├── db.js # Database instance (singleton)
|
|
│ ├── init.js # Database initialization
|
|
│ ├── schema.sql # Base schema
|
|
│ └── navidocs.db # SQLite database file
|
|
│
|
|
├── migrations/
|
|
│ ├── 001_initial.sql
|
|
│ ├── 002_entities.sql
|
|
│ └── 003_auth_tables.sql # NEW: Auth tables migration
|
|
│
|
|
├── middleware/
|
|
│ ├── auth.js # JWT authentication middleware
|
|
│ └── permissions.js # NEW: Permission enforcement middleware
|
|
│
|
|
├── routes/
|
|
│ ├── auth.js # NEW: Auth endpoints
|
|
│ ├── users.js # NEW: User management
|
|
│ ├── organizations.js # NEW: Org management
|
|
│ ├── entities.js # Entity CRUD (add permission checks)
|
|
│ ├── documents.js # Document CRUD (add permission checks)
|
|
│ ├── upload.js # File upload
|
|
│ └── search.js # Search endpoints
|
|
│
|
|
├── services/
|
|
│ ├── auth.js # NEW: Authentication service
|
|
│ ├── authorization.js # NEW: Authorization service
|
|
│ ├── audit.js # NEW: Audit logging service
|
|
│ ├── users.js # NEW: User management service
|
|
│ ├── organizations.js # NEW: Organization service
|
|
│ ├── ocr.js # OCR processing
|
|
│ ├── search.js # Search indexing
|
|
│ └── queue.js # Job queue
|
|
│
|
|
├── test/
|
|
│ ├── services/
|
|
│ │ ├── auth.test.js # NEW
|
|
│ │ ├── authorization.test.js # NEW
|
|
│ │ └── audit.test.js # NEW
|
|
│ ├── routes/
|
|
│ │ ├── auth.test.js # NEW
|
|
│ │ └── organizations.test.js # NEW
|
|
│ └── migrations/
|
|
│ └── 003_auth_tables.test.js # NEW
|
|
│
|
|
├── utils/
|
|
│ └── logger.js # Logging utility
|
|
│
|
|
├── index.js # Express app entry point
|
|
├── package.json
|
|
├── .env
|
|
├── DESIGN_AUTH_MULTITENANCY.md # This design doc
|
|
├── IMPLEMENTATION_TASKS.md # Task breakdown
|
|
└── ARCHITECTURE_DIAGRAM.md # Architecture diagrams
|
|
```
|
|
|
|
---
|
|
|
|
## Technology Stack Summary
|
|
|
|
| Layer | Technology | Purpose |
|
|
|-------|------------|---------|
|
|
| **Backend** | Node.js 20+ | Runtime environment |
|
|
| **Framework** | Express 5.0 | Web framework |
|
|
| **Database** | SQLite (→ PostgreSQL) | Relational data storage |
|
|
| **Authentication** | JWT (jsonwebtoken) | Stateless auth tokens |
|
|
| **Password Hashing** | bcrypt | Secure password storage |
|
|
| **Search** | Meilisearch | Full-text search |
|
|
| **Job Queue** | BullMQ + Redis | Background OCR jobs |
|
|
| **Caching** | lru-cache | In-memory permission cache |
|
|
| **Security** | Helmet.js | HTTP security headers |
|
|
| **Rate Limiting** | express-rate-limit | DDoS protection |
|
|
| **Testing** | Mocha/Jest | Unit & integration tests |
|
|
| **Documentation** | OpenAPI/Swagger | API documentation |
|
|
|
|
---
|
|
|
|
## Key Design Decisions
|
|
|
|
1. **JWT over Sessions:** Stateless tokens enable horizontal scaling without shared session store.
|
|
|
|
2. **3-Tier Permissions:** Organization → Entity → Resource hierarchy provides flexibility without complexity.
|
|
|
|
3. **LRU Cache:** Dramatically improves performance (5ms vs 50ms per permission check) with acceptable staleness (5min TTL).
|
|
|
|
4. **Refresh Token Rotation:** Security best practice - short-lived access tokens + revocable refresh tokens.
|
|
|
|
5. **Audit-First Design:** All security events logged for compliance and forensics.
|
|
|
|
6. **Vertical Agnostic:** Entity type is a field, not a table - same code handles boats, aircraft, condos.
|
|
|
|
7. **SQLite → PostgreSQL:** Start simple, migrate when needed - schema designed for easy transition.
|
|
|
|
8. **bcrypt over SHA:** Industry standard for password hashing with adjustable cost factor.
|
|
|
|
9. **Explicit Grants:** Members don't inherit entity access - must be explicitly granted (more secure).
|
|
|
|
10. **Soft Deletes:** Users marked as 'deleted' status rather than removed (preserves audit trail).
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Review & Approve** this design document
|
|
2. **Create GitHub Issues** for each PR in IMPLEMENTATION_TASKS.md
|
|
3. **Set up CI/CD** pipeline for automated testing
|
|
4. **Begin Phase 1** implementation (database migration)
|
|
5. **Schedule Code Reviews** for each PR
|
|
6. **Plan Frontend Integration** after backend completion
|
|
|
|
---
|
|
|
|
**Document Metadata:**
|
|
- Version: 1.0
|
|
- Date: 2025-10-21
|
|
- Author: Tech Lead
|
|
- Status: Ready for Review
|