Platform Module Technical Specifications
PlatformProvisioningService, MailService, PlatformSubscriptionService, BackupService, TenantManagementService, RealtimeVpsAutoUpgradeService, Aegis PITR, SidecarRestoreManager, ComplianceReportService.
System Metrics
Named services
25+
Collections
37, spanning provisioning, subscriptions, backup/PITR, and Aegis compliance
VPS providers
4 (Hetzner, Contabo, DigitalOcean, Vultr) via IVpsProvider interface
PITR adapters
2 (PgBackRestAdapter, ExternalPitrAdapter)
Provisioning job retry
3 attempts
Instance poll batch
100 per run
Temporal retention windows
7/30/90+ days + custom
Backup verification cadence
Weekly per tenant
Architecture Overview
| Capability | Responsibility |
|---|---|
| Provisioning | Async job queue, VPS provider abstraction, instance lifecycle |
| Self-hosted mail server provisioning on the tenant's VPS (Postfix / Dovecot / OpenDKIM) | |
| Subscriptions | Upgrade / downgrade / cancel / reactivate / trial / payment-webhook handling |
| Backup | Backup config, scheduling, job execution, PITR orchestration |
| Signup | Signup flow, plan assignment, entitlements grant |
| Tenant management | Tenant create / suspend / activate / archive |
| Realtime auto-upgrade | Auto-resize the tenant's VPS to match their Realtime subscription tier |
| Storage archive | Cold storage tiering for old backups |
| Aegis notification | Email / Slack / webhook for Aegis failures |
| Temporal sweep | Cron health visibility |
| Backup verification | Weekly restore-and-verify |
| Compliance reports | Monthly SOC2 / ISO27001 evidence |
| Aegis restore | Point-in-time restore |
| PITR | PITR orchestration |
| Bulk undo | Event-store bulk undo |
| Aegis heartbeat | Backup health monitoring |
| Federation | Code-free cross-tenant event sharing via signed Digital Alliance contracts |
| eBPF firewall | Ring-0 XDP kernel firewall — visual rules → C → clang → bpftool injection |
PlatformProvisioningService — VPS Job Queue
export interface ProvisioningJob { id: string; tenantId: string; subscriptionId?: string; type: | "create_tenant" | "provision_server" | "setup_domain" | "grant_entitlements" | "suspend" | "resume_instance" | "upgrade_tier"; status: "pending" | "running" | "completed" | "failed"; payload: Record<string, unknown>; // Job-type-specific data result?: Record<string, unknown>; // Populated on completion error?: string; // Populated on failure retryCount: number; startedAt?: string; completedAt?: string; createdAt: string;}```
**Job processing:**
```typescriptprocessJob(jobId) { // 1. Mark running (startedAt → now) // 2. executeJob() — switch on type // 3. Mark completed (completedAt → now, result → {}) // On error: retryCount++, if >= 3 → failed}
processAllPendingJobs(ctx) { // 1. List pending jobs (limit 50) // 2. For each: processJob() // 3. Called from daily cron}```
**VPS provider interface:**
```typescriptinterface IVpsProvider { readonly name: string; createServer(spec: VpsServerSpec, label: string): Promise<VpsServerResult>; deleteServer(serverId: string): Promise<void>; getServerStatus( serverId: string, ): Promise<"active" | "pending" | "off" | "error">; suspendServer?(serverId: string): Promise<void>; resumeServer?(serverId: string): Promise<void>; rebootServer?(serverId: string): Promise<void>; resizeServer?(serverId: string, newType: string): Promise<void>; getServerMetrics?( serverId: string, type: string, start: string, end: string, ): Promise<VpsMetricsResult>;}
// HetznerProvider, ContaboProvider, DigitalOceanProvider, and VultrProvider all implement IVpsProvider// Swappable — add AWS/DigitalOcean by implementing the same interface```
**Instance polling:**
```typescriptpollProvisioningInstances(ctx) { // 1. List instances with status = "provisioning" (limit 100) // 2. For each: call provider.getServerStatus() // 3. If running → status → "active" // 4. If not found → status → "failed" // 5. Called from hourly cron}Aegis — Point-in-Time Restore Architecture
Three-layer adapter system:
RestoreService
↕ delegates to
pitrRegistry.get() → PgBackRestAdapter | ExternalPitrAdapter
↕ (PgBackRestAdapter uses)
↕ (ExternalPitrAdapter uses)
SidecarRestoreManager
→ sidecar Postgres process
→ pg_dump | psql merge pipeline
→ selective table extract at specific timestamp
PgBackRestAdapter:
- Uses
pgbackrestCLI for backup/restore - Requires stanza to be created + configured
- Honest no-op:
{ enabled: false, reason: "stanza_not_created" }when not configured - Integrates SidecarRestoreManager for selective extract
ExternalPitrAdapter:
- For customer-managed Postgres scenarios
AEGIS_PITR_ADAPTER=externalopts into this adapter- Same API surface as PgBackRestAdapter
SidecarRestoreManager:
```typescript class SidecarRestoreManager { // Selective extract pipeline: // 1. Start sidecar Postgres process // 2. pg_dump with --table and --timestamp filters // 3. psql merge into target tenant DB // 4. Shutdown sidecar process
extractTablesAtTime( tables: string[], timestamp: Date, targetTenantId: string, ): Promise<void>; } ```
BulkUndoService: Event-store based. Read-only until operator calls bulkUndo.execute(). No side effects on registration. For reverting mass data corruption events.
BackupVerificationService — Weekly Restore-and-Verify
The SOC2 problem: "Untested backups are not backups." A backup that has never been restored is a liability — when you need it, you might find it's corrupt, incomplete, or incompatible with your current schema.
BackupVerificationService:
typescript
// Runs weekly per tenant (also available as a manual run)
async runVerification(ctx, options?: { tenantId?, manualRun? }): Promise<VerificationRunResult>
// 1. Check eligibility (skip if not due, or no backup to verify yet)
// 2. Find the most recent successful backup
// 3. Restore it and run integrity checks against the restored data
// 4. Record the run and emit aegis.verification.{passed,failed,skipped}
ComplianceReportService:
typescript
// Runs monthly per tenant (also available as a manual run)
async generateReport(ctx, tenantId): Promise<ComplianceReport>
// 1. Roll up all backup + verification activity for the period
// 2. Format as auditor-facing JSON + HTML
// 3. Upload to BYOB S3 alongside backups
// 4. Report includes: verification pass counts, retention compliance, artifacts
MailService — Self-Hosted Mail Server Provisioning
Rather than routing through a third-party ESP, MailService provisions a real mail server (Postfix + Dovecot + OpenDKIM) directly on the customer's own VPS instance over SSH — so hosted mailboxes live on infrastructure the tenant already owns.
```typescript // Configure Postfix + Dovecot + OpenDKIM for a domain on the tenant's VPS. // Generates DKIM keys, writes the OpenDKIM/Postfix/Dovecot config over SSH, // restarts the mail services, and returns the DKIM public key for DNS. async configureMail(ctx, tenantId, domain): Promise<{ dkimPublicKey: string }>
// Create a mailbox on the tenant's VPS (bcrypt-hashed password via Dovecot). async createMailbox(ctx, tenantId, email, password, displayName?, linkedUserId?, visibility?)
// Verify a domain's MX / SPF / DKIM / DMARC DNS records before enabling mail. async verifyEmailDns(ctx, domain): Promise<{ spf: { status: string; record: string }; dkim: { status: string; record: string }; dmarc: { status: string; record: string }; }> ```
Mailboxes created this way auto-connect to the Inbox module, so hosted mail shows up alongside the tenant's other conversations without a separate IMAP integration step.
PlatformSubscriptionService — Subscription Lifecycle
```typescript // Subscription states: trial | active | past_due | cancelled | suspended
// Upgrade: immediate entitlement grant upgradePlan(subscriptionId, newPlanId) { → subscriptionService.updateById({ plan: newPlanId }) → grantEntitlements(tenantId, plan.entitlements, plan.tier) → emit platform.subscription.upgraded }
// Cancel (end of period): flag set, no immediate action cancelSubscription(subscriptionId, immediately = false) → if immediately: status → cancelled, provisioning job → "suspend" → else: cancelAtPeriodEnd → true
// Cancel (immediately): suspends instances to stop billing // Cancel (end of period): billing stops at period end, instances suspended then
// Reactivate: clears flags, resumes suspended instances reactivate(subscriptionId) → status → active, cancelAtPeriodEnd → false, cancelledAt → null → list suspended instances → create "resume_instance" jobs
// Payment webhooks (from Billing module) handlePaymentSuccess(providerSubscriptionId) → Update period dates → Clear pastDueSince
handlePaymentFailure(providerSubscriptionId) → past_due status → Emit notification event → dunning sequence starts ```
Trial expiry cron: Daily cron checks for expired trials. Expired trial → status: "cancelled", notification sent to tenant.
RealtimeVpsAutoUpgradeService — Tier-Driven VPS Resizing
Each Realtime tier (starter / standard / pro / enterprise) needs a different class of VPS to run its real-time workload — Enterprise's 500-participant webinar mode pushes the LiveKit subprocess's RAM usage well past what a smaller box can hold alongside the rest of the stack. Rather than making tenants manually resize their own server, the service reacts to subscription changes and resizes the underlying VPS to match.
```typescript type RealtimeTier = "starter" | "standard" | "pro" | "enterprise";
// Subscribed to billing.subscription.upgraded / billing.subscription.downgraded. async handleTierChange(ctx, tenantId, fromTier, toTier): Promise<{ resized: boolean; reason?: string; }> ```
Flow:
- On a tier change event, look up the tenant's active instance and VPS provider
- Map the new tier to that provider's server type (e.g., Hetzner CX32 → CX42 for Enterprise) — different tiers that land on the same VPS class are a no-op
- Upgrades resize immediately, then email the tenant confirming the new server size; if the resize fails partway, a separate email tells them the subscription is active but the VPS upgrade needs support to finish
- Downgrades are deferred — scheduled for an off-peak cron run after a 7-day grace period, with a heads-up email sent immediately and another right before the resize happens
This keeps subscription changes from causing behind-the-scenes VPS resize churn on every plan click, while still making sure a tenant's server can actually handle the tier they've paid for.
TenantManagementService — Tenant Lifecycle
// Tenant states: active | disabled | archived
// Create: enforces plan-based tenant limits before provisioningasync createTenant(ctx, { name, slug?, subdomain? }) → reject if the tenant limit for the current plan tier is already reached → generate a unique slug, insert the tenant row (status: "active") → create the tenant's admin role + owning membership
// Delete (terminate): reversible by defaultasync deleteTenant(ctx, tenantIdToDelete, opts?) → default: tenant flips to a terminated state, members disabled — Aegis backups, event-store history, and aegis_* records all survive so an accidental termination can be undone → opts.purgeAegis = true: super-admin-only GDPR Article 17 erasure path, invokes AegisTenantPurgeService — NOT reversible
// Federation: code-free cross-tenant event sharing via signed data contractsFederationService.start() → subscribe to wildcard "*" (all events, every tenant) → on event: if envelope.federatedFrom is set → drop (loop guard) → find active platform_data_contracts where providerTenantId === event.tenantId → match event.name against contract.allowedEvents whitelist (exact or wildcard) → if allowed: deep-clone payload (JSON.parse(JSON.stringify(...))), re-emit to the consumer tenant, stamped { federatedFrom: <provider> } → hard-block system.* / platform.* / cron.* regardless of any whitelist // federated events are READ-ONLY signals — the consumer's own workflows act on them; // the provider can never write to the consumer's dataRing-0 Kernel Firewall — XDP eBPF
Aeion can drop hostile traffic at the eXpress Data Path (XDP) — the earliest hook in the Linux network stack, before the kernel allocates a socket buffer — so DDoS/abuse packets cost the application essentially zero CPU.
Authoring → kernel pipeline:
Admin defines threat-matrix rules in EbpfFirewallView
(block subnet, protect port, rate-limit source, …) → platform_firewall_rules
→ EbpfFilterGenerator (a Universal AST Engine target) compiles the rules to raw C
→ EbpfManager.compile(): clang -O2 -target bpf -c rule.c -o rule.o
→ EbpfManager.inject(): detach any existing XDP program on the NIC, then
bpftool ... attach the new .o to eth0's XDP hook
→ packets matching a drop rule are discarded in nanoseconds at the NIC
Honest degradation. EbpfManager.initialize() probes the host for Linux + clang + bpftool. If any is missing (e.g. a macOS dev box, or a container without the toolchain), it logs the reason and runs in simulation mode — rules can still be authored and stored, but no live kernel injection is attempted. Production Linux hosts with the toolchain get real in-kernel enforcement; everywhere else degrades gracefully instead of failing.
Aegis Temporal Retention — Sweep Logging
The silent-failure problem: A retention cron that silently fails (no error, no alert) means old audit logs sit in the database forever — growing, accumulating cost, and violating compliance requirements. This is the "silent-failure mode" that Aegis closes.
AegisTemporalSweepLogger:
typescript
// Subscribes to temporal sweep cron events
// Writes per-tenant log row for every sweep run
// Log row: { tenantId, cronType, startedAt, completedAt, tableCount, error? }
// → Surfaces in Aegis Hub Health card
// → Triggers notification on failure (via AegisNotificationService)
AegisNotificationService:
```typescript // Reads tenant.config.notifications.aegis notifications: { aegis: { email?: string[]; // destination addresses slack?: string[]; // Slack incoming-webhook URLs webhook?: string[]; // generic webhook URLs (POST JSON) includeSuccess?: boolean; // also notify on success-class events, not just failures } }
// Failure-class events (backup, restore, PITR, verification, compliance) always
// notify, subject to dedup. Success-class events only notify when
// includeSuccess is true (bulk-undo is the exception — it always notifies
// when the run reports failed > 0).
//
// Fan-out: when an Aegis alert fires,
// → email: emit notification.email.send (the same event auth/BI/etc use)
// → slack: POST to each configured webhook URL
// → webhook: generic HTTP POST to each configured URL
```
Key Architecture Decisions
Provisioning model
Async job queue — VPS API calls are slow (30-120s), must not block HTTP response
VPS abstraction
IVpsProvider interface — Swappable providers — add AWS/DO without changing service code
PITR
pgbackrest + adapter pattern — Customer-managed Postgres requires different adapter
Backup verification
Weekly restore-and-verify — SOC2 evidence: untested backups are not backups
Compliance reports
Monthly HTML/JSON upload to S3 — Auditor access without exposing admin UI
Realtime tier resizing
Subscription-event-driven VPS resize — Server class matches the tier the tenant is paying for, without manual resizing
Tenant suspension
Provisioning job (not inline) — Suspend/resume involves VPS API calls, must be async
Temporal retention
Cron + per-tenant log rows — Sweep failures visible in Hub Health card
AEION_MODE
"deployed" vs SaaS — Customer VPS gets backup/Aegis only, not full billing/provisioning