1. Objective
Deploy Nexus to AWS and expose all pipeline-building capabilities to app owners through the Orchestrator interface. App owners interact exclusively through:
- The Nexus Hub Dashboard and Orchestrator SPA
- API endpoints authenticated by per-tenant API keys they manage themselves
- MCP connector endpoints they register through the interface
App owners have no database access and no code access. All pipeline creation, configuration, running, and monitoring is done through the canvas editor, the node property forms, and the App Management page.
This document supersedes the informal plan discussed in session 2026-05-08 and is the authoritative reference for sprint scope, acceptance criteria, and infrastructure specification for NX-S18, NX-S19, and NX-S20.
Prerequisite Reading
Before acting on this document, read the following in order (per NEXUS_DOC_HIERARCHY.html Tier 1-3 protocol):
- NEXUS_COMPONENT_STATUS.html Section 8.1 — full inventory of what the Orchestrator canvas already does. Do not treat canvas capabilities as missing before reading this.
- NEXUS_CAPABILITY_GAP_ANALYSIS.md (GAP-2.0) Section 5-6 — GAP-11, GAP-12, GAP-13 are the UI-layer gaps. Engine-layer gaps (GAP-01..10) are mostly resolved.
- NEXUS_LLD.md Section 3.3.1 + Section 4 + Section 13 — target data-flow design and hardcoded-data elimination checklist.
- NEXUS_ROADMAP.md Section 9 (O6 milestone) —
app_catalogAPI is fully spec'd; NX-S18-WP1/WP2 implement it.
2. Current Platform State
The following capabilities are already implemented as of NX-S17 (Gate 11: 130/130 PASS). The AWS deployment plan builds on these, not around them.
2.1 Engine (Wormwood)
| Component | Status | Key Facts |
|---|---|---|
| FastAPI App + Pipeline Routes | Production | 2,936 lines combined. Full pipeline CRUD, run, SSE telemetry, org/team/user management. |
| Rule Engine + Formula Parser | Production | 874 rules across 25 JSON files. 11 operators, 2 evaluation modes. |
| BDT Validator | Production | 21 registered types, lifecycle enforcement. |
| API Key Store + Auth | Production | 248 + 135 lines. API key auth on all routes requiring auth. |
| 36 Node Executors | Implemented | All 36 nodes implemented and tested. HttpForward, AiTransform, HumanGate, SchedulerTrigger, WebhookTrigger, SmsIngest/Reply, PdfGenerator, FieldMapper, GraphBuild, and 27 others. |
| Orchestration Engine | Implemented | DAG execution, gate suspension/resume, revision loop. 316 lines. |
| Admin Panel | Production | Flask 3. CRUD for all entities on port 8011. Internal tool only. |
| Local Runtime | Production | Default execution mode. SQLite in dev, PostgreSQL target for prod. |
| Lambda Handler | Scaffold | wormwood/api/lambda_handler.py — 19 lines. Shell only. NX-S19 completes. |
2.2 Orchestrator Canvas (WORMWOOD_APP.html)
| Capability | Status | API Wired To |
|---|---|---|
| Node palette (44 types), drag-and-drop to canvas | Production | Node type registry |
| Edge drawing between node pins | Production | — (client-side) |
| Load pipeline graph from engine | Production | GET /pipelines/{id} |
| Save pipeline to engine | Production | PUT /pipelines/{id} |
| Create new pipeline | Production | POST /pipelines |
| Run pipeline + SSE live animation | Production | POST /pipelines/{id}/run + SSE stream |
| Run history + per-node logs | Production | GET /pipelines/{id}/runs |
| Node property editor (breadcrumb nav) | Production | — (generic shell) |
| Classes / Properties / Rules level tabs | Production | GET /types, GET /rules |
| Per-node-type property field schemas | Partial | NX-S18-WP4 GAP-11 |
| App catalog card grid (dynamic) | Hardcoded | NX-S18-WP2 GAP-12 |
| API key management UI | Missing | NX-S18-WP3 |
3. AWS Target Architecture
Resource Naming Convention (Live — eu-west-2, account 654654215330)
All AWS resources in the live deployment use the prefix nexus-prod- regardless of the DNS environment label.
The DNS subdomain nexus-dev.codezerogroup.com reflects product maturity (development-stage product),
not a separate AWS environment tier. There is a single AWS environment; its resources carry the -prod label
because they are the sole production-grade deployment of this product at this time.
The two labels are independent and do not map to each other.
| Component | Doc says | Live AWS name |
|---|---|---|
| ECS cluster | nexus-engine-svc cluster | nexus-prod |
| ECS task definition | nexus-engine | nexus-prod-engine:1 |
| ALB | (unnamed in §3.1) | nexus-prod-alb |
| Secrets Manager (API key) | Secrets Manager (generic) | nexus/prod/api-key-jUmQyN (field: api_key) |
| Secrets Manager (DB URL) | Secrets Manager (generic) | nexus/prod/db-XqDtrO (field: url) |
| S3 — SPA hosting | nexus-static | nexus-nsd-packages (see note) |
| S3 — NSD packages | nexus-nsd-packages | nexus-nsd-packages |
S3 note: nexus-static is taken in the global S3 namespace by a different AWS account.
The SPA is hosted in nexus-nsd-packages under a /nexus-ui/ key prefix until a dedicated bucket is provisioned.
nexus-deploy-agent IAM policy permits s3:CreateBucket only for pre-approved bucket names
(currently: nexus-nsd-packages). See KNOWN_ISSUES ISSUE-072.
Target Stack: Cloud-Native SaaS
The target deployment is the Cloud-Native SaaS combination from NEXUS_DEPLOYMENT_MATRIX.html Section 4:
C: aws-lambda + M: postgresql + V: chameleonv2-react + O: aws-step-functions.
For initial deployment (NX-S19), the controller runs on ECS Fargate (not Lambda) to avoid cold-start latency
on the SSE telemetry stream. Lambda migration (using the existing scaffold in lambda_handler.py) is a Phase 4 item.
3.1 Infrastructure Components
Network Layer
/api/* to engine target group (port 8010). Routes /admin/* to admin target group (port 8011). Routes /nexus-ui/* to S3 static hosting.Compute Layer
nexus-engine (Wormwood FastAPI, port 8010, 1 vCPU / 2GB RAM) and nexus-admin (Flask admin panel, port 8011, 0.5 vCPU / 1GB RAM). Both run in private subnets. Auto-scaling on CPU utilisation (70% threshold).nexus/engine and nexus/admin. CI pipeline pushes tagged images on merge to main.wormwood/api/lambda_handler.py scaffold enables eventual Lambda migration. Not in NX-S19 scope — Fargate is the initial target.Data Layer
db.t3.medium multi-AZ. Replaces SQLite in the production environment. Alembic migration runs in ECS task at deploy time. Separate databases per environment (prod / staging / dev).nexus-nsd-packages (NSD versioned packages, lifecycle rules retain last 10 versions) and nexus-static (SPA HTML/CSS/JS, served via ALB or CloudFront). Both with versioning enabled.CI/CD Pipeline
main branch (protected, requires PR + passing tests).latest.3.2 DNS and Domain
| Endpoint | Target | Auth |
|---|---|---|
api.nexus-dev.codezerogroup.com | ALB → nexus-engine (port 8010) | API key header X-API-Key |
admin.nexus-dev.codezerogroup.com | ALB → nexus-admin (port 8011) | Session auth, VPN-restricted |
app.nexus-dev.codezerogroup.com | ALB → S3 static / CloudFront | API key (stored in browser nexus-login.key) |
mcp.nexus-dev.codezerogroup.com | ALB → nexus-engine /mcp/* | API key header, MCP transport (SSE + HTTP) |
3.3 REST API Integration
App owners and external tools integrate with the engine via REST over HTTPS.
Auth is via X-API-Key header (or api_key query param for SSE EventSource connections).
Keys are DB-backed, scoped per org, and returned raw exactly once at creation.
Full integration reference: NEXUS_INTEGRATION_GUIDE.html.
OpenAPI spec and Swagger UI: https://api.nexus-dev.codezerogroup.com/docs.
Note: MCP endpoint routes are not present in this deployment. MCP is a separate system (Nexus1) on an unrelated domain.
4. App Owner Self-Service Model
An app owner is a person who has been provisioned a tenant on the Nexus platform.
They have an API key and access to the Nexus Hub at app.nexus-dev.codezerogroup.com.
They have no database credentials, no SSH access, and no code repository access.
4.1 What App Owners Can Do After NX-S18
| Action | How | Gate |
|---|---|---|
| Browse available apps in Orchestrator | Dynamic card grid from GET /apps/catalog | NX-S18-WP2 delivers |
| Open a pipeline in the canvas editor | Select org → select pipeline → canvas loads | Already delivered (NX-S17) |
| Add a node from the palette | Toggle palette → drag node to canvas | Already delivered (NX-S17) |
| Connect nodes with edges | Click output pin → drag to input pin | Already delivered (NX-S17) |
| Configure a node's properties | Right-click node → open property editor → fill fields | NX-S18-WP4 delivers (6 priority nodes) |
| Save a pipeline | Toolbar save button → PUT /pipelines/{id} | Already delivered (NX-S17) |
| Run a pipeline and see live progress | Run button → SSE animation on canvas | Already delivered (NX-S17) |
| View run history and per-node logs | Run log panel → history list → node detail | Already delivered (NX-S17) |
| Manage their own API keys | App Management → API Keys tab → create/revoke/rotate | NX-S18-WP3 delivers |
| Register an MCP connector | App Management → Connectors tab → add endpoint + auth | NX-S18-WP3 (basic); full connector registry NX-S20 |
4.2 What Requires a Platform Admin (App Owners Cannot Do)
| Action | Why Restricted | Sprint |
|---|---|---|
| Provision a new tenant / app | Requires DB migration + seed. Platform admin only until WP-5.6 self-service tenant provisioning API. | NX-S20 |
| Assign users to a tenant | RBAC user assignment requires admin panel until user management UI is built. | NX-S20 |
| Publish an app to the catalog | App versioning and publishing (WP-5.5) not yet implemented. | Post NX-S20 |
| Configure external credentials (Twilio, Anthropic) | Secrets stored in AWS Secrets Manager, accessible via admin panel or IaC only. | Post NX-S20 |
5. Sprint Plan
app_catalog, app_component, and app_action tables per the schema in NEXUS_LLD.md Section 6.
New FastAPI route GET /apps/catalog returns all apps with their components, versions, actions, and connection topology.
Seed script populates 5 active use cases (ARC, Nesto, EDR, ENDO, AER) in app_catalog.
- Alembic migration runs clean (exit 0) against both SQLite dev and PostgreSQL staging
GET /apps/catalogreturns 200 with schema:[{slug, display_name, components[], actions[], connections[]}]- 5 use-case rows in
app_catalogafter seed - Migration is reversible (downgrade to previous head, tables drop cleanly)
USE_CASES hardcoded array in WORMWOOD_APP.htmlvar USE_CASES = [...] JavaScript constant in WORMWOOD_APP.html (line ~942) with a fetch(engineUrl + '/apps/catalog') call.
The card rendering function renderCards() is rewritten to consume the API response.
Gate 11 Section 11 (Orchestrator SPA) must still PASS.
GAP-12
grep -c "USE_CASES" docs/WORMWOOD_APP.htmlreturns 0- Orchestrator card grid shows the 5 seeded apps from the database
- Adding a new row to
app_catalogmakes it appear in the Orchestrator without code changes - Gate 11 Section 11 PASS (all Orchestrator scenarios)
API Keys tab: Lists all API keys for the current org (masked, last-used, created dates). Create new key (generates UUID, copies to clipboard once). Revoke key (with confirmation). Rename key (display label). Backed by the existing
core/api_key_store.py (248 lines, Production) via new routes in routes_orgs.py:
GET /apps/{slug}/api-keys, POST /apps/{slug}/api-keys, DELETE /apps/{slug}/api-keys/{key_id}.
Connectors tab: Register an external connector endpoint (name, URL, auth type, auth value). Used by HttpForward and WebhookTrigger nodes to reference named connectors instead of hardcoded URLs. Backed by a new
connector table (id, org_slug, name, url, auth_type, auth_value_encrypted).
CRUD: GET /apps/{slug}/connectors, POST /apps/{slug}/connectors, DELETE /apps/{slug}/connectors/{id}.
Auth values encrypted at rest using Fernet (symmetric key stored in Secrets Manager on AWS, env var locally).
- API Keys tab renders in APP_MGMT.html with list, create, revoke, rename
- Creating a key returns a UUID displayed once; subsequent views show masked value
- Revoking a key makes subsequent API calls with that key return 401
- Connectors tab renders with list, add, delete
- Connector auth values are not returned in GET response (masked or omitted)
- Gate 11 Section 8 (App Management) PASS after changes
core/api_key_store.py (exists, Production). New: connector table migration + routes. Fernet key via env var NEXUS_ENCRYPT_KEY._open(pid, nid, nd) property editor shell exists in WORMWOOD_APP.html but renders a generic form for all node types.
Define JSON schemas for the 6 most-used nodes and register them in the editor's node-type dispatch table.
GAP-11
Priority nodes:
HttpForward (url, method, headers, timeout_seconds, auth_type, auth_value),
FormNode (schema_ref, rbac_role, style_ref, submit_label),
AiTransform (provider, model, prompt_template, max_tokens),
FieldMapper (mappings table: source_field / target_field / transform / drop),
StoreNode (entity_class, deltaPrism_config, mode: create/update/upsert),
IngestNode (source_type, source_config, field_map).
Each schema registers in a
NODE_SCHEMAS map keyed by node type name.
The _open() function reads NODE_SCHEMAS[nd.type] and renders typed fields:
text input, dropdown (enum), URL input, integer, toggle (boolean), key-value table.
- Opening property editor for HttpForward shows url/method/headers/timeout/auth fields
- Opening property editor for FormNode shows schema_ref/rbac_role/style_ref/submit_label
- Opening property editor for AiTransform shows provider dropdown/model/prompt template/max_tokens
- Opening property editor for FieldMapper shows a mappings table (add row, delete row)
- Opening property editor for StoreNode shows entity_class/deltaPrism_config/mode dropdown
- Opening property editor for IngestNode shows source_type dropdown/source_config/field_map
- Saving a pipeline after configuring node properties persists the config in the engine DB
- Unknown node types fall back to the existing generic form (no regression)
_open() framework in WORMWOOD_APP.html (exists). Node type definitions in wormwood/schema/node_registry.py (1130 lines) as reference for field names.infra/modules/network.
VPC with CIDR 10.0.0.0/16. Two availability zones.
Public subnets (10.0.1.0/24, 10.0.2.0/24) for ALB.
Private subnets (10.0.11.0/24, 10.0.12.0/24) for ECS and RDS.
Internet Gateway, NAT Gateways (one per AZ), route tables.
Security groups per Section 3.1.
Terraform state in S3 bucket nexus-tf-state with DynamoDB lock.
terraform planexits 0 with no unexpected changes after apply- VPC and all subnets visible in AWS Console
- Security group rules match Section 3.1 specification exactly
terraform destroyremoves all resources cleanly
db.t3.medium, multi-AZ, in private subnets.
DB credentials auto-generated and stored in AWS Secrets Manager (nexus/prod/db).
Alembic is already configured in the engine repo — update DATABASE_URL to read from Secrets Manager at runtime.
Run all existing migrations against the new RDS instance via a one-off ECS task at deploy time.
Include the NX-S18-WP1 app_catalog migration.
- RDS instance is reachable from ECS task SG on port 5432 only
- All existing Alembic migrations apply cleanly (exit 0)
- NX-S18-WP1 migration applies cleanly (5 rows in app_catalog after seed)
- Engine connects to RDS on startup (
GET /healthreturns 200 with db_status: ok) - RDS is not reachable from the public internet
nexus/engine and nexus/admin. Both already have requirements.txt and run as Python processes.
ECR repositories created via Terraform.
ECS cluster, two services (nexus-engine-svc, nexus-admin-svc).
Task definitions read DB credentials and API key from Secrets Manager via task IAM role (no env vars in task def).
Engine task: 1 vCPU / 2GB RAM, min 1 / max 4 replicas.
Admin task: 0.5 vCPU / 1GB RAM, min 1 / max 1 replica.
Health check: GET /health every 30s, unhealthy threshold 3.
- Both Docker images build cleanly (
docker buildexits 0) - Images push to ECR successfully
- ECS services reach RUNNING state (0 stopped tasks)
GET /healthreturns 200 from within the VPC (ECS exec or bastion)- No secrets in task definition environment variables or Docker images
*.nexus-dev.codezerogroup.com (DNS validation via Route 53).
Listener on port 443, redirect port 80 to 443.
Target groups: engine (port 8010, health /health), admin (port 8011, health /health).
Listener rules: /api/* → engine TG, /admin/* → admin TG, default → S3 static bucket (SPA).
Route 53 A record api.nexus-dev.codezerogroup.com aliased to ALB DNS name.
curl https://api.nexus-dev.codezerogroup.com/healthreturns HTTP 200 (from public internet)- HTTP 80 redirects to HTTPS 443 (curl -I shows 301)
- ACM certificate is ISSUED and shows as valid in browser
- Admin endpoint is not reachable from public internet (returns 403 or connection refused)
nexus-nsd-packages S3 bucket (static website hosting enabled, public read).
ALB host-routing rule created (priority 30, host-header: app.nexus-dev.codezerogroup.com → HTTPS redirect to S3 REST endpoint).
Bootstrap script injected into ui/index.html: sets ww_base_url to https://api.nexus-dev.codezerogroup.com on first load.
scripts/smoke_test_aws.py exits 0. Naming deviation documented in ISSUE-072.
nexus-static with static website hosting enabled.
ALB host-based routing rule: requests with Host: app.nexus-dev.codezerogroup.com forwarded to S3 static bucket.
SPA ww_base_url localStorage default updated from localhost:8010 to https://api.nexus-dev.codezerogroup.com via substitution in ui/index.html before S3 sync.
CI pipeline syncs ui/ to the bucket on each merge to main.
S3 bucket for NSD packages (nexus-nsd-packages) created with versioning enabled, private ACL, lifecycle rule retaining last 10 versions.
https://app.nexus-dev.codezerogroup.comserves Nexus Hub SPA (HTTP 200, body containsww_base_url, NOTWormwood EngineSwagger signature)https://app.nexus-dev.codezerogroup.comandhttps://api.nexus-dev.codezerogroup.comreturn different content (confirms ALB host-routing is active)- SPA default engine URL is
https://api.nexus-dev.codezerogroup.com(not localhost) - CI sync runs on merge and updates S3 within 2 minutes
nexus-nsd-packagesbucket exists, versioning enabled, not publicly readablescripts/smoke_test_aws.pyexits 0 (all three checks pass)
main: run full test suite (pytest), build Docker images, push to ECR, run Alembic migrations via ECS task, update ECS service, sync docs to S3.
On PR: run tests only.
Fail fast: if any test fails or Docker build fails, deployment does not proceed.
Deployment secrets (AWS credentials, ECR URLs) stored in GitHub Actions secrets or CodePipeline IAM role.
- Push to
maintriggers pipeline automatically - Pipeline fails if any of the 2,712 tests fail
- Pipeline fails if Docker build fails
- Successful run deploys to ECS and syncs S3 within 10 minutes
- Pipeline run log is visible in GitHub Actions / CodePipeline console
tenant table per NEXUS_LLD.md Section 7.2 schema.
app_catalog table gains tenant_id foreign key.
All existing org data migrated to a default uv-internal tenant.
Tenant provisioning API: POST /tenants (platform admin only),
GET /tenants/{slug}, DELETE /tenants/{slug}.
- Migration applies cleanly to production RDS
- Existing data migrated to
uv-internaltenant with no data loss POST /tenantscreates a new tenant and returns the tenant slug and a provisioned admin API key- New tenant has empty app_catalog (no apps from other tenants visible)
role (id, tenant_id, name, permissions JSON), user_role (user_id, role_id, app_slug).
All pipeline queries in routes_pipelines.py gain a tenant_id filter.
API keys are now tenant-scoped: a key for Tenant A cannot list or run Tenant B pipelines.
Role hierarchy from NEXUS_LLD.md Section 8.1: platform_admin / tenant_admin / app_admin / app_user / app_viewer.
- API key for Tenant A returns 403 on
GET /pipelines?org_slug=tenantB-app - Tenant A pipelines do not appear in Tenant B app catalog
- platform_admin key can access all tenants
- Existing tests still pass (uv-internal tenant scoping applied correctly)
rbac_visibility field map: per-field, per-role: visible / read_only / hidden.
The engine enforces this at the API level (hidden fields stripped from response).
ChameleonV2 enforces this at the form level (read_only = non-editable, hidden = not rendered).
ApprovalGate node gains a role_required enforcement: only users with nesto_reviewer or nesto_hr_admin can approve.
- nesto_submitter cannot see the
approval_resultfield - nesto_auditor sees all fields as read-only
- nesto_reviewer can approve/reject at the ApprovalGate node
- nesto_submitter attempting to POST to the ApprovalGate resume endpoint returns 403
- Gate 11 Nesto scenarios PASS
POST /apps/{slug}/users/invite, PUT /apps/{slug}/users/{user_id}/role, DELETE /apps/{slug}/users/{user_id}.
- Users tab renders in APP_MGMT.html with user list and role badges
- Invite generates a token (emailed or copied); accepting invite creates the user record
- Role change takes effect on next API call from that user
- Removing a user revokes all their API keys for that app
6. Open Items and Risks
| ID | Item | Sprint | Risk Level | Mitigation |
|---|---|---|---|---|
| RISK-01 | SSE telemetry stream compatibility with ALB timeout | NX-S19 | Medium | ALB idle timeout default is 60s. SSE connections are long-lived. Set ALB idle timeout to 3600s for the engine target group. Alternatively, configure SSE to send keepalive comments every 30s (already supported in routes_pipelines.py). |
| RISK-02 | ChameleonV2 BDT Phase 1 (GAP-02) not in NX-S18..S20 scope | Post S20 | Medium | FormNode property editor in NX-S18-WP4 uses the demo form layer (plain HTML/JS, authorised by NEXUS_DEMO_SPEC.html REM-01..08) until ChameleonV2 Phase 1 (M-NEXUS-CV-2/CV-3) delivers. This is an accepted scoped exception per Tier 4 hierarchy rules. App owners can still configure and run pipelines; the production form renderer is a separate sprint. |
| RISK-03 | Lambda handler scaffold is 19 lines — cold start on SSE | Post S20 | Low | Fargate is the initial compute target (NX-S19). Lambda migration is a Phase 4 item. The scaffold exists; no action required until Phase 4. |
| RISK-04 | Connector credential encryption key management | NX-S18 | Medium | For NX-S18 (local dev), Fernet key via env var NEXUS_ENCRYPT_KEY. For NX-S19 (AWS), key stored in Secrets Manager and accessed via ECS task IAM role. Do not hardcode the key or commit it to the repository. |
| RISK-05 | NANO/PICO rule wiring (GAP-13) deferred | Post S20 | Low | Rule references can be set in the property editor (setRuleRef exists). Full inline rule editing via PICO level is post-S20. App owners can view rule IDs in the editor and use the Rule Registry HTML for reference. |
7. Document Chain Cross-References
| This Document | References | Relationship |
|---|---|---|
| ADP-1.0 Section 2 | NEXUS_COMPONENT_STATUS.html Section 8.1 | Reads current state from. Do not duplicate; reference only. |
| ADP-1.0 Section 2 (gaps) | NEXUS_CAPABILITY_GAP_ANALYSIS.md GAP-11, GAP-12, GAP-13 | Sprint WPs close these gaps. Update gap status on sprint completion. |
| ADP-1.0 Section 5 NX-S18-WP1/2 | NEXUS_ROADMAP.md Section 9 (O6 milestone) | O6 scope fully implemented by WP1+WP2. Mark O6 SCHEDULED: NX-S18. |
| ADP-1.0 Section 5 NX-S18-WP3/4 | NEXUS_LLD.md Section 3.3.1, Section 13 | WP3 adds new routes per LLD design. WP4 clears LLD Section 13 USE_CASES row. |
| ADP-1.0 Section 3 | NEXUS_DEPLOYMENT_MATRIX.html Section 4 (Cloud-Native SaaS) | Target stack is the Cloud-Native SaaS combo. ADP-1.0 is the concrete instantiation. |
| ADP-1.0 Section 5 NX-S20 | NEXUS_LLD.md Section 7 (Multi-Tenancy), Section 8 (RBAC) | WP1-WP4 implement the LLD data models exactly. No divergence permitted. |
| ADP-1.0 Section 6 RISK-02 | NEXUS_DEMO_SPEC.html REM-01..08, NEXUS_DOC_HIERARCHY.html Tier 4 | Demo form layer in NX-S18 property editor is a Tier 4-authorised exception. References the same authorisation as WORMWOOD_APP.html demo panels. |
8. Version History
| Version | Date | Changes |
|---|---|---|
| ADP-1.0 | 2026-05-08 | Initial document. Three-sprint plan (NX-S18..NX-S20). AWS target architecture. Self-service model. 5 risk items. Cross-reference table. Authority: Tier 3. |