aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
45 KiB
45 KiB
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
-- 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-Keyheader) for service-to-service
Common Headers
X-Tenant-ID: <tenant-uuid> # 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
{
"success": true,
"data": {},
"meta": {
"page": 1,
"per_page": 20,
"total": 100,
"total_pages": 5
}
}
Error Format
{
"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)
# 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
# Key format: lv_<prefix>_<random>
# 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
# 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)
# 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
// Using React 19 features
// Server Components for data fetching
async function TenantListPage() {
const tenants = await api.tenants.list(); // Server-side fetch
return (
<DataTable
data={tenants}
columns={tenantColumns}
// React 19: actions for mutations
onDelete={deleteTenantAction}
/>
);
}
// Client Components for interactivity
'use client';
function TenantActions({ tenantId }: { tenantId: string }) {
const { hasPermission } = usePermissions();
return (
<div>
{hasPermission('tenants.update') && (
<Button onClick={() => editTenant(tenantId)}>Edit</Button>
)}
{hasPermission('tenants.delete') && (
<Button variant="danger" onClick={() => deleteTenant(tenantId)}>
Delete
</Button>
)}
</div>
);
}
Audit Log Middleware
# 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.