# MASTER SYSTEM ARCHITECTURE PLAN & EXECUTION PROMPT ## E-Governance Cryptographic Licensing Engine & Multi-Tenant CA System > **Target Workspace:** `E:\nextgen\next-gen` > **SuperAdmin Instance:** `E:\nextgen\next-gen\superadmin` (`server/` and `client/`) > **First Tenant Instance:** `E:\nextgen\next-gen\client` (React Vite PWA) and `E:\nextgen\next-gen\server` (Node/Express API Engine) > **Document Purpose:** Complete, step-by-step technical architectural prompt for an execution agent to implement asymmetric Ed25519 licensing, hybrid dual-driver caching, global access middleware, and anti-tampering clock protection. --- ## EXECUTIVE ARCHITECTURE OVERVIEW ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ SUPERADMIN ENGINE (CA PORTAL) │ │ E:\nextgen\next-gen\superadmin │ │ - Holds Ed25519 PRIVATE KEY (SUPERADMIN_PRIVATE_KEY) │ │ - Signs License Tokens: Ed25519 (EdDSA) │ │ - Exposes JWKS Endpoint: /api/v1/auth/jwks │ │ - Stores Tenant Registry in Supabase Cloud (`tenants`, `tenant_licenses`)│ └───────────────────────────────────┬─────────────────────────────────────┘ │ Cryptographic License Token │ (Ed25519 Signed JWT) ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ FIRST TENANT INSTANCE & DEPLOYMENTS │ │ Client: E:\nextgen\next-gen\client (React Vite PWA + Web Crypto) │ │ Server: E:\nextgen\next-gen\server (Node Express Backend API) │ │ │ │ - Holds Ed25519 PUBLIC KEY (SUPERADMIN_PUBLIC_KEY / VITE_...) │ │ - Storage: Local SQLite/Postgres `tenant_licenses` │ │ - Hybrid Dual-Driver Cache: Memory LRU (`lru-cache`) + Redis (`ioredis`)│ │ - AccessMiddleware: Enforces Read-Only on Expired Licenses (HTTP 402) │ │ - Clock Anti-Tamper: Heartbeat sync with SuperAdmin + NTP drift check │ └─────────────────────────────────────────────────────────────────────────┘ ``` --- ## 1. DATABASE SCHEMA & DATA MODELS ### 1.1 SuperAdmin Cloud Database (Postgres / Supabase) Target Schema File: `E:\nextgen\supabase\supabase_full_schema.sql` Service Integration: `E:\nextgen\next-gen\superadmin\server\src\services\SupabaseSuperAdminService.js` ```sql -- Full Supabase Schema Updates for Asymmetric Ed25519 Licensing Engine -- Located in: E:\nextgen\supabase\supabase_full_schema.sql CREATE TABLE IF NOT EXISTS tenant_licenses ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, license_key TEXT UNIQUE NOT NULL, term_name TEXT NOT NULL, academic_year TEXT NOT NULL, start_date DATE NOT NULL, end_date DATE NOT NULL, grace_period_days INTEGER DEFAULT 7, max_students INTEGER DEFAULT 1000, max_staff INTEGER DEFAULT 200, signed_license_token TEXT, algorithm TEXT DEFAULT 'EdDSA', status TEXT DEFAULT 'active', override_reason TEXT, issued_by TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); -- Idempotent Column Additions & Performance Indexing ALTER TABLE tenant_licenses ADD COLUMN IF NOT EXISTS signed_license_token TEXT; ALTER TABLE tenant_licenses ADD COLUMN IF NOT EXISTS algorithm TEXT DEFAULT 'EdDSA'; CREATE INDEX IF NOT EXISTS idx_tenant_licenses_active ON tenant_licenses(tenant_id) WHERE status = 'active'; ``` CREATE INDEX IF NOT EXISTS idx_tenant_licenses_active ON tenant_licenses(tenant_id) WHERE is_active = TRUE; ``` ### 1.2 Tenant Local Database (SQLite / Knex) Location: `E:\nextgen\next-gen\server\src\database\` & `E:\nextgen\next-gen\server\data\school.db` ```sql -- SQLite Compatible Tenant License Table CREATE TABLE IF NOT EXISTS tenant_licenses ( id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, term_name TEXT NOT NULL, academic_year TEXT NOT NULL, start_date TEXT NOT NULL, end_date TEXT NOT NULL, grace_period_days INTEGER DEFAULT 7, max_students INTEGER DEFAULT 1000, max_staff INTEGER DEFAULT 200, license_key TEXT NOT NULL, signed_license_token TEXT NOT NULL, status TEXT DEFAULT 'ACTIVE', created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); ``` --- ## 2. CRYPTOGRAPHIC LICENSING ENGINE (SUPERADMIN CA) ### 2.1 Ed25519 Asymmetric Key Generation & Signing Service File to Update: `E:\nextgen\next-gen\superadmin\server\src\services\LicenseTokenGenerator.js` ```javascript /** * LicenseTokenGenerator.js * Acts as the Certificate Authority (CA) using Ed25519 (EdDSA) asymmetric signing. */ const crypto = require('crypto'); const jwt = require('jsonwebtoken'); class LicenseTokenGenerator { /** * Generates or retrieves the Ed25519 Key Pair */ static getKeyPair() { const privateKeyPem = process.env.SUPERADMIN_PRIVATE_KEY; const publicKeyPem = process.env.SUPERADMIN_PUBLIC_KEY; if (privateKeyPem && publicKeyPem) { return { privateKey: privateKeyPem, publicKey: publicKeyPem }; } // Fallback keypair generation for development if env variables are not supplied const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519', { privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, publicKeyEncoding: { type: 'spki', format: 'pem' } }); return { privateKey, publicKey }; } /** * Generate an Ed25519 cryptographically signed license token */ static generateToken(payload) { const { privateKey } = this.getKeyPair(); const nowSeconds = Math.floor(Date.now() / 1000); const nbf = payload.nbf || Math.floor(new Date(payload.start_date).getTime() / 1000); const exp = payload.exp || Math.floor(new Date(payload.end_date).getTime() / 1000); const licensePayload = { iss: 'super_admin_licensing_engine', sub: payload.tenant_id, tenant_code: payload.tenant_code, term: payload.term_name, academic_year: payload.academic_year, max_students: payload.max_students || 1000, max_staff: payload.max_staff || 200, nbf: nbf, exp: exp, status: 'active', iat: nowSeconds }; // Sign payload using Ed25519 (EdDSA algorithm in JWT standard) const token = jwt.sign(licensePayload, privateKey, { algorithm: 'EdDSA' }); const keyFormatted = `LIC-${(payload.term_name || 'TERM').toUpperCase().replace(/\s+/g, '')}-${payload.academic_year}-${token.slice(-16).toUpperCase()}`; return { token, license_key: keyFormatted, payload: licensePayload }; } /** * Verify an Ed25519 token using the Public Key */ static verifyToken(token) { const { publicKey } = this.getKeyPair(); try { const decoded = jwt.verify(token, publicKey, { algorithms: ['EdDSA'] }); return { isValid: true, payload: decoded }; } catch (err) { return { isValid: false, error: err.message }; } } } module.exports = LicenseTokenGenerator; ``` ### 2.2 SuperAdmin JWKS & Public Key Distribution Endpoint File to Update: `E:\nextgen\next-gen\superadmin\server\src\routes\superadmin.routes.js` Add route `/api/v1/auth/jwks` to expose the Ed25519 Public Key for online tenant bootstrapping: ```javascript router.get('/v1/auth/jwks', (req, res) => { const { publicKey } = LicenseTokenGenerator.getKeyPair(); res.json({ keys: [ { kty: 'OKP', crv: 'Ed25519', use: 'sig', alg: 'EdDSA', pubKeyPem: publicKey } ] }); }); ``` --- ## 3. HYBRID DUAL-DRIVER CACHING LAYER (TENANT BACKEND) File to Create: `E:\nextgen\next-gen\server\src\services\LicenseCacheService.js` ```javascript /** * LicenseCacheService.js * Hybrid Dual-Driver Cache (In-Memory LRU default + Redis Adapter) */ const { LRUCache } = require('lru-cache'); const redis = require('redis'); // In-Memory LRU Cache Instance (default zero-dependency fallback) const localMemoryCache = new LRUCache({ max: 500, // Maximum 500 cached tenant tokens ttl: 1000 * 60 * 60 * 2 // 2 hours default local memory check interval }); let redisClient = null; if (process.env.REDIS_URL) { redisClient = redis.createClient({ url: process.env.REDIS_URL }); redisClient.on('error', (err) => console.error('Redis License Cache Error:', err)); redisClient.connect().catch(() => { console.warn('⚠️ Could not connect to Redis; defaulting to in-memory LRU cache.'); }); } const LicenseCache = { async get(tenantId) { try { if (redisClient && redisClient.isOpen) { const data = await redisClient.get(`license:tenant:${tenantId}`); return data ? JSON.parse(data) : null; } } catch (e) { console.warn('Redis GET failed, falling back to LRU cache:', e.message); } return localMemoryCache.get(tenantId) || null; }, async set(tenantId, payload, ttlInSeconds) { try { if (redisClient && redisClient.isOpen) { await redisClient.set(`license:tenant:${tenantId}`, JSON.stringify(payload), { EX: Math.max(ttlInSeconds, 60) }); return; } } catch (e) { console.warn('Redis SET failed, falling back to LRU cache:', e.message); } localMemoryCache.set(tenantId, payload, { ttl: Math.max(ttlInSeconds, 60) * 1000 }); }, async del(tenantId) { if (redisClient && redisClient.isOpen) { await redisClient.del(`license:tenant:${tenantId}`); } localMemoryCache.delete(tenantId); } }; module.exports = LicenseCache; ``` --- ## 4. GLOBAL ACCESSMIDDLEWARE & CLOCK DRIFT PROTECTION File to Update: `E:\nextgen\next-gen\server\src\middleware\licensingMiddleware.js` ```javascript /** * licensingMiddleware.js * Intercepts incoming requests, verifies Ed25519 tokens via Hybrid Cache, * checks system clock drift, and enforces Read-Only restriction (HTTP 402) on expired licenses. */ const jwt = require('jsonwebtoken'); const Database = require('better-sqlite3'); const path = require('path'); const LicenseCache = require('../services/LicenseCacheService'); // Public Key injected via env or fetched from JWKS const SUPERADMIN_PUBLIC_KEY = process.env.SUPERADMIN_PUBLIC_KEY || `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA... -----END PUBLIC KEY-----`; let lastSuperAdminTimeSync = Date.now(); let serverTimeDriftOffsetMs = 0; // Track trusted time sync with SuperAdmin function updateSystemClockSync(superAdminTimestamp) { if (superAdminTimestamp) { const remoteTime = new Date(superAdminTimestamp).getTime(); serverTimeDriftOffsetMs = Math.abs(Date.now() - remoteTime); lastSuperAdminTimeSync = Date.now(); } } function verifyEd25519Token(token) { try { const decoded = jwt.verify(token, SUPERADMIN_PUBLIC_KEY, { algorithms: ['EdDSA'] }); return { isValid: true, payload: decoded }; } catch (err) { return { isValid: false, error: err.message }; } } async function verifyLicenseMiddleware(req, res, next) { const tenantId = req.headers['x-tenant-id'] || req.headers['x-tenant-code'] || process.env.TENANT_ID || '5b39bcb5-506a-456d-b7cb-91730b397cc1'; req.tenantId = tenantId; // Bypass routes (Auth, SysAdmin, Health, Billing) const PUBLIC_PATHS = ['/api/auth/login', '/api/auth/refresh', '/api/sysadmin', '/api/health', '/api/billing']; if (PUBLIC_PATHS.some(p => req.path.startsWith(p)) || req.user?.role === 'systems_admin') { return next(); } // Anti-Clock-Tampering Guard: Lock mutations if system clock has drifted > 5 minutes (300,000 ms) if (serverTimeDriftOffsetMs > 300000) { console.error(`🚨 System Clock Drift Detected: ${serverTimeDriftOffsetMs}ms variance.`); return blockMutationRequests(req, res, 'CLOCK_DRIFT_DETECTED', 'System clock tampering or significant time drift detected.'); } try { // 1. Query Hybrid Cache (Memory LRU / Redis) let cachedPayload = await LicenseCache.get(tenantId); // 2. Cache Miss Fallback: Read DB raw signed token & verify Ed25519 signature if (!cachedPayload) { const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/school.db'); const db = new Database(dbPath); const row = db.prepare('SELECT * FROM tenant_licenses WHERE tenant_id = ? AND status = "ACTIVE" ORDER FROM rowid DESC LIMIT 1').get(tenantId); db.close(); if (!row || !row.signed_license_token) { return blockMutationRequests(req, res, 'NO_LICENSE', 'No active license token found for tenant.'); } const verification = verifyEd25519Token(row.signed_license_token); if (!verification.isValid) { return blockMutationRequests(req, res, 'INVALID_SIGNATURE', 'License signature verification failed.'); } cachedPayload = verification.payload; const nowSec = Math.floor(Date.now() / 1000); const remainingTTL = (cachedPayload.exp || 0) - nowSec; if (remainingTTL > 0) { await LicenseCache.set(tenantId, cachedPayload, remainingTTL); } } // 3. Temporal Bound Check const currentSeconds = Math.floor(Date.now() / 1000); if (currentSeconds < cachedPayload.nbf || currentSeconds > cachedPayload.exp) { return blockMutationRequests(req, res, 'LICENSE_EXPIRED', 'Your termly license has expired.'); } // License is valid res.setHeader('X-License-Status', 'ACTIVE'); return next(); } catch (err) { console.error('License Middleware Error:', err); return blockMutationRequests(req, res, 'EVALUATION_ERROR', err.message); } } function blockMutationRequests(req, res, code, message) { const isReadOnly = ['GET', 'HEAD', 'OPTIONS'].includes(req.method.toUpperCase()); if (isReadOnly) { res.setHeader('X-License-Status', 'Expired-Read-Only'); return req.next ? req.next() : res.status(200); } return res.status(402).json({ error: 'Payment Required / Term License Expired', code: code || 'LICENSE_EXPIRED', message: message || 'Your termly license has expired. Please contact billing.', billing_url: '/billing' }); } module.exports = { verifyLicenseMiddleware, updateSystemClockSync }; ``` --- ## 5. CLIENT-SIDE PWA OFFLINE VERIFICATION (REACT VITE) Location: `E:\nextgen\next-gen\client\src\services\offlineLicenseVerifier.js` ```javascript /** * offlineLicenseVerifier.js * Uses Browser Native Web Crypto API to verify Ed25519 license tokens offline in React PWA. */ export async function verifyLicenseOffline(signedToken, publicKeyPem) { try { const [headerB64, payloadB64, signatureB64] = signedToken.split('.'); const dataToVerify = new TextEncoder().encode(`${headerB64}.${payloadB64}`); // Decode base64url signature const signatureBin = Uint8Array.from(atob(signatureB64.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); const payloadJson = JSON.parse(atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/'))); // Simple temporal validation const nowSeconds = Math.floor(Date.now() / 1000); if (nowSeconds < payloadJson.nbf || nowSeconds > payloadJson.exp) { return { isValid: false, reason: 'EXPIRED', payload: payloadJson }; } return { isValid: true, payload: payloadJson }; } catch (e) { return { isValid: false, reason: 'INVALID_FORMAT', error: e.message }; } } ``` --- ## 6. STEP-BY-STEP EXECUTION AGENT CHECKLIST 1. **Update Supabase Database Schema (`E:\nextgen\supabase\supabase_full_schema.sql`)**: - Ensure `tenant_licenses` table includes `signed_license_token TEXT` and `algorithm TEXT DEFAULT 'EdDSA'`. - Apply schema updates to Supabase PostgreSQL cloud instance via Supabase CLI or SQL Editor: ```bash supabase db push --schema-file E:\nextgen\supabase\supabase_full_schema.sql ``` 2. **Update SuperAdmin CA Generator (`E:\nextgen\next-gen\superadmin\server\src\services\LicenseTokenGenerator.js`)**: - Replace symmetric HS256 with Ed25519 (EdDSA) signing using `crypto.generateKeyPairSync('ed25519')` or PEM environment keys. 3. **Expose JWKS Endpoint (`E:\nextgen\next-gen\superadmin\server\src\routes\superadmin.routes.js`)**: - Add `/api/v1/auth/jwks` route returning public keys. 4. **Implement Hybrid Dual-Driver Cache (`E:\nextgen\next-gen\server\src\services\LicenseCacheService.js`)**: - Implement in-memory LRU (`lru-cache`) with optional Redis fallback. 5. **Update Tenant AccessMiddleware (`E:\nextgen\next-gen\server\src\middleware\licensingMiddleware.js`)**: - Integrate `LicenseCacheService`. - Add Ed25519 asymmetric verification. - Enforce HTTP 402 Payment Required for non-GET/HEAD/OPTIONS requests on expired licenses. - Add 5-minute system clock drift threshold check. 6. **Configure First Tenant Environment (`E:\nextgen\next-gen\.env` & `E:\nextgen\next-gen\server\.env`)**: - Populate `SUPERADMIN_PUBLIC_KEY` and `VITE_SUPERADMIN_PUBLIC_KEY`. 7. **Run Verification Commands**: - Test license creation in SuperAdmin UI and confirm sync to Supabase `tenant_licenses` table. - Test GET vs POST endpoints on `E:\nextgen\next-gen\server` under active vs expired license tokens.