landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
This commit is contained in:
@@ -0,0 +1,1006 @@
|
||||
# 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: <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
|
||||
```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_<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
|
||||
```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 (
|
||||
<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
|
||||
```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.
|
||||
Reference in New Issue
Block a user