# LandveX Enterprise Platform — Admin Backend Design ## Overview A multi-tenant admin backend for LandveX Enterprise Platform serving municipalities (kommuner) and enterprises. Built with FastAPI (Python), PostgreSQL, and React 19. --- ## 1. Data Model (PostgreSQL) ### Core Tables ```sql -- Tenants (top-level isolation) CREATE TABLE tenants ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, slug VARCHAR(100) UNIQUE NOT NULL, type VARCHAR(20) NOT NULL CHECK (type IN ('municipality', 'enterprise', 'partner')), org_number VARCHAR(20) UNIQUE, billing_email VARCHAR(255) NOT NULL, plan_id UUID REFERENCES subscription_plans(id), status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'cancelled', 'trial')), settings JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Subscription Plans CREATE TABLE subscription_plans ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(100) NOT NULL, slug VARCHAR(50) UNIQUE NOT NULL, description TEXT, price_monthly DECIMAL(10,2) NOT NULL, price_yearly DECIMAL(10,2), features JSONB NOT NULL DEFAULT '{}', limits JSONB NOT NULL DEFAULT '{}', -- {"users": 10, "api_calls": 100000} is_public BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Users (tenant-scoped) CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, email VARCHAR(255) NOT NULL, password_hash VARCHAR(255) NOT NULL, first_name VARCHAR(100), last_name VARCHAR(100), phone VARCHAR(50), avatar_url TEXT, status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'pending', 'locked')), last_login_at TIMESTAMPTZ, failed_login_attempts INT DEFAULT 0, locked_until TIMESTAMPTZ, mfa_enabled BOOLEAN DEFAULT false, mfa_secret VARCHAR(255), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(tenant_id, email) ); -- Roles CREATE TABLE roles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE, -- NULL = global role name VARCHAR(100) NOT NULL, slug VARCHAR(100) NOT NULL, description TEXT, permissions JSONB NOT NULL DEFAULT '[]', is_system BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(tenant_id, slug) ); -- User Roles (many-to-many) CREATE TABLE user_roles ( user_id UUID REFERENCES users(id) ON DELETE CASCADE, role_id UUID REFERENCES roles(id) ON DELETE CASCADE, assigned_by UUID REFERENCES users(id), assigned_at TIMESTAMPTZ DEFAULT NOW(), PRIMARY KEY (user_id, role_id) ); -- API Keys CREATE TABLE api_keys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, key_hash VARCHAR(255) NOT NULL, key_prefix VARCHAR(8) NOT NULL, scopes JSONB NOT NULL DEFAULT '[]', rate_limit INT DEFAULT 1000, expires_at TIMESTAMPTZ, last_used_at TIMESTAMPTZ, created_by UUID REFERENCES users(id), status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'revoked', 'expired')), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Audit Log CREATE TABLE audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID REFERENCES tenants(id), user_id UUID REFERENCES users(id), action VARCHAR(50) NOT NULL, resource_type VARCHAR(50) NOT NULL, resource_id UUID, details JSONB DEFAULT '{}', ip_address INET, user_agent TEXT, severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('info', 'warning', 'critical')), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Invoices CREATE TABLE invoices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id), invoice_number VARCHAR(50) UNIQUE NOT NULL, period_start DATE NOT NULL, period_end DATE NOT NULL, amount DECIMAL(10,2) NOT NULL, tax_amount DECIMAL(10,2) NOT NULL, total_amount DECIMAL(10,2) NOT NULL, currency VARCHAR(3) DEFAULT 'SEK', status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft', 'sent', 'paid', 'overdue', 'cancelled')), paid_at TIMESTAMPTZ, stripe_invoice_id VARCHAR(100), pdf_url TEXT, due_date DATE NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Invoice Line Items CREATE TABLE invoice_items ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), invoice_id UUID NOT NULL REFERENCES invoices(id) ON DELETE CASCADE, description VARCHAR(255) NOT NULL, quantity DECIMAL(10,2) NOT NULL, unit_price DECIMAL(10,2) NOT NULL, amount DECIMAL(10,2) NOT NULL, metadata JSONB DEFAULT '{}' ); -- Plugins CREATE TABLE plugins ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(100) NOT NULL, slug VARCHAR(100) UNIQUE NOT NULL, description TEXT, version VARCHAR(20) NOT NULL, author VARCHAR(100), config_schema JSONB DEFAULT '{}', is_system BOOLEAN DEFAULT false, status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'deprecated')), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tenant Plugins (installed plugins) CREATE TABLE tenant_plugins ( tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE, plugin_id UUID REFERENCES plugins(id) ON DELETE CASCADE, config JSONB DEFAULT '{}', installed_by UUID REFERENCES users(id), installed_at TIMESTAMPTZ DEFAULT NOW(), status VARCHAR(20) DEFAULT 'active', PRIMARY KEY (tenant_id, plugin_id) ); -- Reports CREATE TABLE reports ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL, config JSONB NOT NULL DEFAULT '{}', schedule VARCHAR(50), -- cron expression or null for one-time last_run_at TIMESTAMPTZ, next_run_at TIMESTAMPTZ, created_by UUID REFERENCES users(id), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Report Runs CREATE TABLE report_runs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_id UUID NOT NULL REFERENCES reports(id) ON DELETE CASCADE, status VARCHAR(20) DEFAULT 'running' CHECK (status IN ('running', 'completed', 'failed')), result_url TEXT, error_message TEXT, started_at TIMESTAMPTZ DEFAULT NOW(), completed_at TIMESTAMPTZ ); -- Indexes for performance CREATE INDEX idx_users_tenant_email ON users(tenant_id, email); CREATE INDEX idx_audit_logs_tenant_created ON audit_logs(tenant_id, created_at DESC); CREATE INDEX idx_audit_logs_user ON audit_logs(user_id, created_at DESC); CREATE INDEX idx_invoices_tenant_status ON invoices(tenant_id, status); CREATE INDEX idx_api_keys_tenant ON api_keys(tenant_id, status); ``` --- ## 2. API Specification (FastAPI + OpenAPI) ### Base URL ``` https://api.landvex.com/v1 ``` ### Authentication - **JWT Bearer** for user sessions - **API Key** (`X-API-Key` header) for service-to-service ### Common Headers ``` X-Tenant-ID: # Required for all tenant-scoped endpoints ``` ### Endpoints #### Authentication ``` POST /auth/login POST /auth/logout POST /auth/refresh POST /auth/mfa/setup POST /auth/mfa/verify POST /auth/forgot-password POST /auth/reset-password ``` #### Tenants ``` GET /tenants # List (superadmin) POST /tenants # Create (superadmin) GET /tenants/{id} PATCH /tenants/{id} DELETE /tenants/{id} # Soft delete GET /tenants/{id}/stats # Usage statistics GET /tenants/{id}/billing # Billing summary ``` #### Users ``` GET /users POST /users GET /users/{id} PATCH /users/{id} DELETE /users/{id} PATCH /users/{id}/status # Activate/deactivate/lock POST /users/{id}/roles # Assign roles DELETE /users/{id}/roles/{role_id} GET /users/me # Current user profile PATCH /users/me ``` #### Roles & Permissions ``` GET /roles POST /roles GET /roles/{id} PATCH /roles/{id} DELETE /roles/{id} GET /permissions # List all available permissions ``` #### API Keys ``` GET /api-keys POST /api-keys # Returns key once (not stored plaintext) GET /api-keys/{id} PATCH /api-keys/{id} DELETE /api-keys/{id} POST /api-keys/{id}/revoke ``` #### Billing & Subscriptions ``` GET /billing/plans GET /billing/subscription POST /billing/subscribe POST /billing/cancel POST /billing/upgrade GET /billing/invoices GET /billing/invoices/{id} GET /billing/invoices/{id}/pdf POST /billing/payment-method ``` #### Audit Logs ``` GET /audit-logs GET /audit-logs/export # CSV/JSON export GET /audit-logs/stats # Summary statistics ``` #### Reports ``` GET /reports POST /reports GET /reports/{id} PATCH /reports/{id} DELETE /reports/{id} POST /reports/{id}/run GET /reports/{id}/runs GET /reports/{id}/runs/{run_id}/download ``` #### Plugins ``` GET /plugins # Available plugins GET /plugins/installed POST /plugins/{id}/install PATCH /plugins/{id}/config DELETE /plugins/{id}/uninstall POST /plugins/{id}/enable POST /plugins/{id}/disable ``` #### Dashboard & Analytics ``` GET /dashboard/summary GET /dashboard/activity GET /dashboard/usage GET /analytics/users GET /analytics/api-usage GET /analytics/revenue ``` ### Response Format ```json { "success": true, "data": {}, "meta": { "page": 1, "per_page": 20, "total": 100, "total_pages": 5 } } ``` ### Error Format ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Invalid input data", "details": [ {"field": "email", "message": "Invalid email format"} ] } } ``` --- ## 3. UI Sketches (React 19) ### Layout Structure ``` ┌─────────────────────────────────────────────────────────┐ │ 🏠 LandveX 🔍 Search 🔔 👤 Profile ▼ │ ← TopBar ├──────────┬──────────────────────────────────────────────┤ │ │ │ │ Dashboard│ Main Content Area │ │ ├── Overview │ │ ├── Analytics │ │ Tenants │ │ │ ├── All Tenants │ │ ├── Pending │ │ Users │ │ │ ├── All Users │ │ ├── Roles │ │ API Keys │ │ │ Billing │ │ │ ├── Invoices │ │ ├── Plans │ │ ├── Subscriptions │ │ Audit Logs│ │ │ Reports │ │ │ Plugins │ │ │ Settings │ │ │ │ │ └──────────┴──────────────────────────────────────────────┘ Sidebar Content ``` ### Key Screens #### Dashboard Overview ``` ┌─────────────────────────────────────────────────────────┐ │ Dashboard [Refresh] │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Active │ │ Total │ │ API Calls│ │ Revenue │ │ │ │ Tenants │ │ Users │ │ Today │ │ (MTD) │ │ │ │ 42 │ │ 156 │ │ 1.2M │ │ 45,000 │ │ │ │ ↑ 12% │ │ ↑ 8% │ │ ↑ 23% │ │ ↑ 15% │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────────────────────┤ │ Recent Activity API Usage (7d) │ │ ───────────────── ────────────── │ │ • New tenant: Stockholm Kommun ┌──────────────┐ │ │ • User locked: admin@example.com │ 📈 │ │ │ • Invoice paid: #INV-2024-001 │ Chart │ │ │ • API key revoked: prod-key │ │ │ │ └──────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ Recent Invoices Recent Audit Logs │ │ ─────────────── ───────────────── │ │ #INV-001 5,000 SEK admin@x DELETE user 2m │ │ #INV-002 2,500 SEK api@x CREATE key 5m │ │ #INV-003 12,000 SEK sys UPDATE tenant 1h │ └─────────────────────────────────────────────────────────┘ ``` #### Tenant Management ``` ┌─────────────────────────────────────────────────────────┐ │ Tenants [+ New Tenant] │ ├─────────────────────────────────────────────────────────┤ │ [🔍 Search...] [Type ▼] [Status ▼] [Plan ▼] [Export] │ ├─────────────────────────────────────────────────────────┤ │ Name Type Plan Users Status │ │ ─────────────────────────────────────────────────────── │ │ Stockholm Kommun Municipality Enterprise 12 🟢 Active│ │ Volvo Group Enterprise Business 45 🟢 Active│ │ Malmö Stad Municipality Starter 8 🟡 Trial │ │ Ericsson Enterprise Enterprise 89 🟢 Active│ │ ... │ │ │ │ [← Prev] Page 1 of 5 [Next →] Showing 1-10 of 42 │ └─────────────────────────────────────────────────────────┘ ``` #### User Management with Roles ``` ┌─────────────────────────────────────────────────────────┐ │ Users [+ Invite User] │ ├─────────────────────────────────────────────────────────┤ │ [🔍 Search...] [Role ▼] [Status ▼] │ ├─────────────────────────────────────────────────────────┤ │ Name Email Role Status │ │ ─────────────────────────────────────────────────────── │ │ Anna Svensson anna@x.com Admin 🟢 Active │ │ Erik Johansson erik@x.com Editor 🟢 Active │ │ Maria Lind maria@x.com Viewer 🟡 Pending│ │ [Locked] Johan johan@x.com Editor 🔴 Locked │ │ │ │ Actions: [Edit] [Reset PW] [Lock] [Delete] [Assign Role]│ └─────────────────────────────────────────────────────────┘ ``` #### Role Editor ``` ┌─────────────────────────────────────────────────────────┐ │ Edit Role: Admin [Save] │ ├─────────────────────────────────────────────────────────┤ │ Name: [Admin ] │ │ Description: [Full system access... ] │ │ │ │ Permissions │ │ ─────────────────────────────────────────────────────── │ │ ☑ Users ☑ Create ☑ Read ☑ Update ☑ Delete │ │ ☑ Tenants ☐ Create ☑ Read ☑ Update ☐ Delete │ │ ☑ Billing ☑ Read ☑ Manage Invoices │ │ ☑ API Keys ☑ Create ☑ Read ☑ Revoke │ │ ☑ Reports ☑ Create ☑ Run ☑ Export │ │ ☐ Plugins ☐ Install ☐ Configure ☐ Uninstall │ │ │ │ Members (12) │ │ ─────────────────────────────────────────────────────── │ │ Anna Svensson, Erik Johansson, ... [+ Add Member] │ └─────────────────────────────────────────────────────────┘ ``` #### API Key Management ``` ┌─────────────────────────────────────────────────────────┐ │ API Keys [+ Generate Key] │ ├─────────────────────────────────────────────────────────┤ │ ⚠️ Only show key once on creation! │ ├─────────────────────────────────────────────────────────┤ │ Name Prefix Scopes Last Used │ │ ─────────────────────────────────────────────────────── │ │ Production prod_*** read,write 2 min ago │ │ Integration int_*** read 1 hour ago │ │ Backup Script back_*** read 3 days ago │ │ │ │ [Revoke] [Regenerate] [Edit Scopes] │ └─────────────────────────────────────────────────────────┘ ``` #### Billing & Invoices ``` ┌─────────────────────────────────────────────────────────┐ │ Billing │ ├─────────────────────────────────────────────────────────┤ │ Current Plan: Enterprise │ │ Next billing: 2024-08-01 (15 days) │ │ Amount: 12,000 SEK/month │ │ [Upgrade] [Cancel Subscription] │ ├─────────────────────────────────────────────────────────┤ │ Payment Methods [+ Add Card] │ │ 💳 •••• 4242 Exp: 12/25 [Default] [Remove] │ ├─────────────────────────────────────────────────────────┤ │ Invoices │ │ ─────────────────────────────────────────────────────── │ │ #INV-2024-007 12,000 SEK Paid Jul 1 [PDF] │ │ #INV-2024-006 12,000 SEK Paid Jun 1 [PDF] │ │ #INV-2024-005 12,000 SEK Paid May 1 [PDF] │ └─────────────────────────────────────────────────────────┘ ``` #### Audit Log Viewer ``` ┌─────────────────────────────────────────────────────────┐ │ Audit Logs [Export CSV] │ ├─────────────────────────────────────────────────────────┤ │ [🔍 Search] [Action ▼] [User ▼] [Date Range] [Severity]│ ├─────────────────────────────────────────────────────────┤ │ Time User Action Resource IP │ │ ─────────────────────────────────────────────────────── │ │ 14:32:05 admin@x DELETE user/abc 10.0.0.1 │ │ 14:30:22 api@x CREATE api_key/xyz 10.0.0.2 │ │ 14:15:00 system UPDATE tenant/123 internal │ │ 13:45:10 erik@x LOGIN session/xxx 192.168.1 │ │ │ │ [View Details] for each row │ └─────────────────────────────────────────────────────────┘ ``` #### Report Builder ``` ┌─────────────────────────────────────────────────────────┐ │ Reports [+ New Report] │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Report: Monthly API Usage │ │ │ │ Type: Bar Chart Schedule: Monthly (1st) │ │ │ │ │ │ │ │ Filters: │ │ │ │ Date Range: [2024-01-01] to [2024-06-30] │ │ │ │ Tenant: [All ▼] Endpoint: [/api/v1/users ▼] │ │ │ │ │ │ │ │ [Run Now] [Schedule] [Export PDF] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ Recent Runs │ │ ─────────────────────────────────────────────────────── │ │ Jul 1, 2024 Completed [Download PDF] [Download CSV] │ │ Jun 1, 2024 Completed [Download PDF] │ │ May 1, 2024 Failed [View Error] │ └─────────────────────────────────────────────────────────┘ ``` #### Plugin Marketplace ``` ┌─────────────────────────────────────────────────────────┐ │ Plugins │ ├─────────────────────────────────────────────────────────┤ │ [🔍 Search...] [Installed] [Available] [Updates] │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 📊 Analytics│ │ 🗺️ GIS │ │ 📄 PDF Gen │ │ │ │ v2.1.0 │ │ v1.5.2 │ │ v3.0.0 │ │ │ │ By LandveX │ │ By LandveX │ │ By LandveX │ │ │ │ │ │ │ │ │ │ │ │ [Installed] │ │ [Install] │ │ [Update] │ │ │ │ [Configure] │ │ [Details] │ │ [Details] │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 🔗 Webhook │ │ 📧 Email │ │ 🤖 AI Assist│ │ │ │ v1.0.0 │ │ v2.0.1 │ │ v0.9.0 │ │ │ │ By Acme │ │ By LandveX │ │ By OpenAI │ │ │ │ │ │ │ │ │ │ │ │ [Install] │ │ [Installed] │ │ [Install] │ │ │ │ [Details] │ │ [Configure] │ │ [Details] │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` --- ## 4. Security Architecture ### Authentication Flow ``` ┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ Client │────▶│ FastAPI │────▶│ PostgreSQL │────▶│ Redis │ │ │◄────│ Backend │◄────│ (users) │◄────│ (sessions) └─────────┘ └─────────────┘ └─────────────┘ └─────────┘ │ ▼ ┌─────────────┐ │ Argon2id │ ← Password hashing │ (pwd) │ └─────────────┘ ``` ### Multi-Tenant Isolation ``` ┌─────────────────────────────────────────┐ │ API Gateway / WAF │ │ (Rate limiting, DDoS protection) │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ Authentication Layer │ │ (JWT validation, API key check) │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ Tenant Resolution │ │ • Header: X-Tenant-ID │ │ • JWT claim: tenant_id │ │ • API key → lookup tenant │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ Row-Level Security (RLS) │ │ All queries filtered by tenant_id │ │ Users can only access their tenant │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ PostgreSQL Database │ │ • RLS policies on all tenant tables │ │ • Separate schemas optional │ │ • Encrypted at rest (AES-256) │ └─────────────────────────────────────────┘ ``` ### Authorization (RBAC) ```python # Permission hierarchy permissions = { "users": ["create", "read", "update", "delete", "impersonate"], "tenants": ["create", "read", "update", "delete", "manage"], "roles": ["create", "read", "update", "delete", "assign"], "api_keys": ["create", "read", "revoke", "rotate"], "billing": ["read", "manage", "invoices", "subscribe"], "audit_logs": ["read", "export"], "reports": ["create", "read", "run", "export", "delete"], "plugins": ["install", "configure", "uninstall", "enable"], "settings": ["read", "update"] } # Role examples roles = { "superadmin": "*", # All permissions "admin": ["users.*", "roles.read", "billing.read", "settings.*"], "editor": ["users.read", "users.update", "reports.*"], "viewer": ["*.read"], "api": ["api_keys.read", "api_keys.create"] # Service account } ``` ### API Key Security ```python # Key format: lv__ # Example: lv_prod_abc123def456 # Storage: Only hash is stored key_hash = argon2.hash(full_key) key_prefix = full_key[:8] # For identification # Scopes restrict access scopes = ["read:users", "write:reports"] # Rate limiting per key rate_limit = 1000 # requests per hour ``` ### Audit Logging ```python # All actions logged automatically @audit_log(action="user.update", resource_type="user") async def update_user(user_id: UUID, data: UserUpdate): # ... update logic # Automatically logged with: # - who (user_id) # - what (action) # - when (timestamp) # - where (IP, user_agent) # - changes (before/after diff) ``` ### Data Protection ``` 1. Encryption at Rest - PostgreSQL: AES-256 (AWS RDS encryption / LUKS) - Backups: Encrypted with tenant-specific keys 2. Encryption in Transit - TLS 1.3 for all API communications - mTLS for service-to-service 3. Secrets Management - AWS Secrets Manager / HashiCorp Vault - API keys: Hashed with Argon2id - JWT: RS256 with key rotation 4. PII Handling - Email encryption for sensitive tenants - GDPR-compliant data export/deletion - Automatic PII redaction in logs ``` ### Security Headers ``` Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-Frame-Options: DENY Content-Security-Policy: default-src 'self' X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), microphone=(), camera=() ``` --- ## 5. Project Structure ``` landvex-admin/ ├── backend/ │ ├── app/ │ │ ├── __init__.py │ │ ├── main.py # FastAPI app entry │ │ ├── config.py # Settings & env vars │ │ ├── database.py # DB connection & session │ │ ├── models/ # SQLAlchemy models │ │ │ ├── __init__.py │ │ │ ├── tenant.py │ │ │ ├── user.py │ │ │ ├── role.py │ │ │ ├── api_key.py │ │ │ ├── billing.py │ │ │ ├── audit.py │ │ │ ├── report.py │ │ │ └── plugin.py │ │ ├── schemas/ # Pydantic models │ │ │ ├── __init__.py │ │ │ ├── tenant.py │ │ │ ├── user.py │ │ │ └── ... │ │ ├── api/ │ │ │ ├── __init__.py │ │ │ ├── deps.py # Dependencies (auth, tenant) │ │ │ ├── v1/ │ │ │ │ ├── __init__.py │ │ │ │ ├── auth.py │ │ │ │ ├── tenants.py │ │ │ │ ├── users.py │ │ │ │ ├── roles.py │ │ │ │ ├── api_keys.py │ │ │ │ ├── billing.py │ │ │ │ ├── audit.py │ │ │ │ ├── reports.py │ │ │ │ ├── plugins.py │ │ │ │ └── dashboard.py │ │ ├── services/ # Business logic │ │ │ ├── __init__.py │ │ │ ├── auth_service.py │ │ │ ├── tenant_service.py │ │ │ ├── user_service.py │ │ │ ├── billing_service.py │ │ │ └── audit_service.py │ │ ├── core/ │ │ │ ├── __init__.py │ │ │ ├── security.py # Password, JWT, crypto │ │ │ ├── permissions.py # RBAC logic │ │ │ ├── tenant_resolver.py # Tenant isolation │ │ │ └── exceptions.py # Custom exceptions │ │ └── utils/ │ │ ├── __init__.py │ │ ├── pagination.py │ │ └── validators.py │ ├── alembic/ # Database migrations │ ├── tests/ │ ├── Dockerfile │ ├── requirements.txt │ └── pyproject.toml │ ├── frontend/ │ ├── src/ │ │ ├── main.tsx # Entry point │ │ ├── App.tsx │ │ ├── components/ │ │ │ ├── layout/ │ │ │ │ ├── Sidebar.tsx │ │ │ │ ├── TopBar.tsx │ │ │ │ └── Layout.tsx │ │ │ ├── ui/ # Reusable UI components │ │ │ │ ├── DataTable.tsx │ │ │ │ ├── Modal.tsx │ │ │ │ ├── Form.tsx │ │ │ │ └── Charts.tsx │ │ │ └── features/ │ │ │ ├── tenants/ │ │ │ ├── users/ │ │ │ ├── billing/ │ │ │ └── reports/ │ │ ├── pages/ │ │ │ ├── Dashboard.tsx │ │ │ ├── Tenants/ │ │ │ │ ├── List.tsx │ │ │ │ └── Detail.tsx │ │ │ ├── Users/ │ │ │ ├── Billing/ │ │ │ └── Settings/ │ │ ├── hooks/ │ │ │ ├── useAuth.ts │ │ │ ├── useTenant.ts │ │ │ ├── useApi.ts │ │ │ └── usePermissions.ts │ │ ├── stores/ │ │ │ ├── authStore.ts # Zustand/Jotai │ │ │ ├── tenantStore.ts │ │ │ └── uiStore.ts │ │ ├── lib/ │ │ │ ├── api.ts # API client (axios/fetch) │ │ │ ├── utils.ts │ │ │ └── constants.ts │ │ └── types/ │ │ └── index.ts │ ├── public/ │ ├── index.html │ ├── package.json │ ├── tsconfig.json │ ├── vite.config.ts │ └── tailwind.config.js │ ├── docker-compose.yml ├── Makefile └── README.md ``` --- ## 6. Key Implementation Details ### FastAPI Dependencies (Tenant Isolation) ```python # app/api/deps.py from fastapi import Depends, HTTPException, Header from fastapi.security import HTTPBearer security = HTTPBearer() async def get_current_user(token: str = Depends(security)): """Validate JWT and return user""" pass async def get_current_tenant( x_tenant_id: UUID = Header(...), user: User = Depends(get_current_user) ): """Validate user belongs to tenant""" if not user.has_access_to(x_tenant_id): raise HTTPException(403, "Access denied to tenant") return x_tenant_id async def require_permission(permission: str): """Dependency factory for permission checking""" async def checker(user: User = Depends(get_current_user)): if not user.has_permission(permission): raise HTTPException(403, f"Missing permission: {permission}") return checker # Usage: @router.get("/users", dependencies=[Depends(require_permission("users.read"))]) async def list_users(tenant_id: UUID = Depends(get_current_tenant)): pass ``` ### React 19 + Server Components Pattern ```tsx // Using React 19 features // Server Components for data fetching async function TenantListPage() { const tenants = await api.tenants.list(); // Server-side fetch return ( ); } // Client Components for interactivity 'use client'; function TenantActions({ tenantId }: { tenantId: string }) { const { hasPermission } = usePermissions(); return (
{hasPermission('tenants.update') && ( )} {hasPermission('tenants.delete') && ( )}
); } ``` ### Audit Log Middleware ```python # Automatically log all state-changing operations @app.middleware("http") async def audit_middleware(request: Request, call_next): response = await call_next(request) if request.method in ["POST", "PUT", "PATCH", "DELETE"]: await audit_service.log( action=f"{request.method.lower()}.{request.url.path}", user=get_current_user_from_request(request), tenant=get_tenant_from_request(request), ip=request.client.host, user_agent=request.headers.get("user-agent"), details={"path": str(request.url), "status": response.status_code} ) return response ``` --- ## 7. Deployment Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ CDN (CloudFront) │ │ Static assets, DDoS protection │ └─────────────────────────────────────────────────────────┘ │ ┌─────────────────────────────────────────────────────────┐ │ Load Balancer (ALB) │ │ SSL termination, health checks │ └─────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ Frontend │ │ Backend │ │ Backend │ │ (React) │ │ (FastAPI) │ │ (FastAPI) │ │ Container │ │ Container │ │ Container │ └────────────┘ └────────────┘ └────────────┘ │ │ │ └───────────────┼───────────────┘ ▼ ┌─────────────────────────────────────────────────┐ │ PostgreSQL (RDS/Aurora) │ │ Primary → Replica (Multi-AZ) │ │ Automated backups │ └─────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ Redis │ │ S3 │ │ Stripe │ │ (ElastiCache)│ (Backups) │ │ (Billing) │ │ Sessions │ │ Reports │ │ │ │ Cache │ │ Exports │ │ │ └────────────┘ └────────────┘ └────────────┘ ``` --- ## 8. Summary | Component | Technology | Purpose | |-----------|-----------|---------| | Backend API | FastAPI (Python) | REST API, async request handling | | Database | PostgreSQL 15+ | Primary data store with RLS | | Cache | Redis | Sessions, rate limiting, cache | | Frontend | React 19 + TypeScript | Admin UI with modern patterns | | Styling | Tailwind CSS | Utility-first CSS | | State | Zustand/Jotai | Client state management | | Auth | JWT + Argon2id | Token-based authentication | | Payments | Stripe | Subscription billing | | Monitoring | Prometheus + Grafana | Metrics and alerting | | Logs | ELK Stack / CloudWatch | Centralized logging | This design provides a secure, scalable, and maintainable admin backend for the LandveX Enterprise Platform with full multi-tenant isolation, comprehensive audit logging, and flexible plugin architecture.