Backend Suite Orchestrator
1. System Overview & Target Sub-Skills
- The Backend Suite Orchestrator is a meta-skill that executes the full backend construction pipeline for a Node.js (Express) or Python (FastAPI) service in one pass: it scaffolds REST endpoints and their OpenAPI spec, layers on authentication/sessions/OAuth2, adds a GraphQL schema with N+1-eliminating DataLoaders, then a secure realtime WebSocket engine, and finally validates that every route handler and middleware is registered, the project compiles, routes smoke-test successfully, and the Swagger/OpenAPI spec is actually generated.
- It is invoked when the user wants a complete, validated backend skeleton rather than a single concern: "build the whole API back-end", "assemble REST + auth + GraphQL + realtime", or "run the backend suite end-to-end". It is also used to re-run only a subset of stages (e.g. regenerate auth then re-validate) via include_steps / skip_steps.
- Ordered bullet list of every sub-skill invoked, with the exact path and what it produces:
skills/express-fastapi-route-builder/express-fastapi-route-builder.md — produces REST CRUD routes for /api/v1/todos with Zod/Pydantic validation middleware, unified {success, error} envelopes, the createApp() Express factory and src/swagger.ts, and a served OpenAPI 3.0 spec (http://localhost:3000/api-docs/swagger.json on Express, http://localhost:8000/api/v1/openapi.json on FastAPI).
skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md — produces the auth service (src/auth.service.ts), requireAuth middleware (src/auth.middleware.ts), /api/auth/* routers plus Google/GitHub OAuth2 routes, cookie sessions (access_token 15m, refresh_token 7d scoped to /api/auth), Argon2id password hashing, and refresh-token rotation with Redis blacklist.
skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md — produces the GraphQL SDL (src/schema.ts), typed resolvers (src/resolvers.ts), the createLoaders() factory (src/loaders.ts), the in-memory repository (src/db.ts), and the Apollo Server 4 bootstrap (src/server.ts) that mounts the endpoint at /graphql.
skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md — produces the socket.io engine (src/server.ts), JWT handshake verification (src/auth.ts), role-based room policy (src/security.ts), and a resync-capable client (src/client.ts) serving ws://localhost:8080 with a plain-HTTP health probe.
- Final validation (orchestrator-run, no sub-skill file) — audits that every preceding router/middleware is registered on the assembled app, runs the
npm run build-style TypeScript/compile check plus route smoke tests, confirms the OpenAPI spec URL responds, and collects all results into BACKEND_SUITE_REPORT.md.
2. Execution Parameters & Configuration Options
- full_run: execute the entire chain in order (
routes → auth → graphql → realtime → validate).
- include_steps: array of step keys to run (run ONLY these; other steps are skipped regardless of skip_steps).
- skip_steps: array of step keys to skip (all other steps run).
- fail_fast (default true): halt on first failing step; when false, remaining steps still run but the consolidated report marks them and the suite as FAILED.
- report_dir / artifact_dir: where per-step outputs and the final consolidated report are written (default
skills/backend-suite-orchestrator/reports/).
- Step keys:
routes (S1), auth (S2), graphql (S3), realtime (S4), validate (S5).
Orchestrator input/options object — JSON Schema draft-07
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"full_run": { "type": "boolean", "default": true },
"include_steps": {
"type": "array",
"items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },
"default": []
},
"skip_steps": {
"type": "array",
"items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },
"default": []
},
"fail_fast": { "type": "boolean", "default": true },
"variant": { "enum": ["express", "fastapi"], "default": "express" },
"report_dir": { "type": "string", "default": "skills/backend-suite-orchestrator/reports/" }
},
"additionalProperties": false
}
Consolidated output report — BACKEND_SUITE_REPORT.md
{
"report": "BACKEND_SUITE_REPORT.md",
"suite": "backend",
"variant": "express",
"generated_at": "ISO8601",
"aggregate": { "steps_total": 5, "steps_passed": 0, "steps_failed": 0, "steps_skipped": 0 },
"steps": [
{
"key": "routes",
"skill": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",
"status": "PASSED|FAILED|SKIPPED",
"artifact": "express/src/app.ts",
"output": "captured stdout tail"
}
],
"recommendation": "SHIP|REVIEW|BLOCK"
}
3. Step-by-Step Execution Protocol & Data Flow
- Pre-flight Check: verify the repo root and that every sub-skill path listed in Section 1 exists as a readable file; confirm required CLIs are on PATH (
node, npm for Express; python/pip/uv, uvicorn for FastAPI); create report_dir and artifact_dir; validate the options object against the Section 2 schema (reject unknown step keys, reject include_steps ∩ skip_steps on the same key).
- Sequential Chaining — numbered steps S1..S5:
- S1 (key
routes): invoke skills/express-fastapi-route-builder/express-fastapi-route-builder.md. Input: none (pre-existing scaffold requirements). Primary output: express/src/app.ts (createApp()), express/src/routes/todos.ts, express/src/middleware/validate.ts, express/src/services/todoService.ts, express/src/swagger.ts; step-report routes_report.md.
- S2 (key
auth): invoke skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md. Input: JWT_ACCESS_SECRET/JWT_REFRESH_SECRET (min 32 chars), DATABASE_URL, REDIS_URL from its .env.example. Primary output: src/server.ts, src/auth.service.ts, src/auth.middleware.ts, src/auth.routes.ts, src/oauth.routes.ts; step-report auth_report.md.
- S3 (key
graphql): invoke skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md. Input: none beyond the scaffold. Primary output: src/schema.ts, src/resolvers.ts, src/loaders.ts, src/db.ts, src/server.ts; step-report graphql_report.md.
- S4 (key
realtime): invoke skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md. Input: JWT_ACCESS_SECRET (shared from S2), REDIS_URL. Primary output: src/server.ts, src/auth.ts, src/security.ts, src/client.ts; step-report realtime_report.md.
- S5 (key
validate): orchestrator-internal validation. Verifies all routers/middleware are registered on the assembled app (/api/v1/todos, /api/auth, /api/auth.oauth, /graphql, WS engine), runs the build check (npm run build i.e. tsc -p tsconfig.json; FastAPI: compileall or uvicorn boot probe), runs route smoke tests against every endpoint, and confirms the OpenAPI spec is served (GET http://localhost:3000/api-docs/swagger.json on Express / http://localhost:8000/api/v1/openapi.json on FastAPI). Emergency output: routes_manifest.json, smoke_results.txt, openapi_check.txt, step-report validate_report.md.
- Data Contracting — step-N output artifact → step-(N+1) input field mappings:
express/src/app.ts createApp() instance (S1) → S2 router registration: src/auth.routes.ts + src/oauth.routes.ts from S2 are mounted onto the S1 Express app via app.use('/api/auth', authRouter) and app.use('/api/auth', oauthRouter), and the S1 app's errorHandler/notFoundHandler stay terminal in the merged stack.
express/src/middleware/validate.ts + express/src/utils/AppError.ts (S1) → S2 guard wiring: the S2 requireAuth middleware from src/auth.middleware.ts (Bearer or access_token cookie) is inserted in front of the protected REST routes, converting a missing/expired token into the S1 error envelope HTTP 401 UNAUTHORIZED.
src/auth.service.ts issued access_token JWT (claims sub, email, displayName, type access, signed with JWT_ACCESS_SECRET) (S2) → S4 handshake auth: src/auth.ts verifyJwt() validates the same token via socket.handshake.auth.token or the x-access-token header; the role claim it reads corresponds to the S4 Role type used by src/security.ts canJoin()/assertCanJoin() room policy.
.env JWT_ACCESS_SECRET inside S2's config (src/config.ts reads it via zod, min 32 chars) (S2) → S4's src/auth.ts reads the identical JWT_ACCESS_SECRET env var so one token family spans REST and the realtime engine; the S4 WS engine is attached to the S1/S2 HTTP server so a single origin serves REST + GraphQL + WS.
src/schema.ts typeDefs + src/resolvers.ts + src/loaders.ts createLoaders() (S3) → the Apollo server bootstrap src/server.ts mounts the schema and injects context = { loaders: createLoaders() } per request; the context shape is passed into S2's merged server so requireAuth guards GraphQL mutations and S3's Mutation resolvers still call loader.clear(key) after writes as documented in the S3 contract.
src/server.ts engine + src/client.ts (S4) → S5 smoke tests: the WS health probe at http://localhost:8080 (returns {"service":"realtime-engine"}) is pinged, then a client connect with an S2-issued token exercises room:join → room:joined { channel, resumeSeq } → chat:send → broadcast message { seq, channel, userId, payload, ts }.
- All prior artifacts → S5 validation:
routes_manifest.json (accumulated registration audit) + smoke_results.txt (each endpoint HTTP status) + openapi_check.txt (Swagger spec fetch) → the consolidated step-record fields of BACKEND_SUITE_REPORT.md.
- Final Consolidation: merge the five per-step reports (
routes_report.md, auth_report.md, graphql_report.md, realtime_report.md, validate_report.md) into one unified summary document written to report_dir/BACKEND_SUITE_REPORT.md (default skills/backend-suite-orchestrator/reports/BACKEND_SUITE_REPORT.md), containing aggregate counts (steps_total/passed/failed/skipped), a per-step table of key | sub-skill | status | artifact, the captured stdout tails, the consolidated route-registration manifest, the OpenAPI spec check result, and a recommendation section (SHIP when all steps passed and the spec is served; REVIEW on any non-fatal warning; BLOCK on any step failure).
4. Reference Execution DAG / Pseudo-Code Implementation
import json, re, subprocess, sys
from collections import OrderedDict
from datetime import datetime, timezone
from pathlib import Path
class Options:
def __init__(self, obj):
self.full_run = obj.get("full_run", True)
self.include_steps = obj.get("include_steps", [])
self.skip_steps = obj.get("skip_steps", [])
self.fail_fast = obj.get("fail_fast", True)
self.variant = obj.get("variant", "express")
self.report_dir = obj.get("report_dir", "skills/backend-suite-orchestrator/reports/")
self.artifact_dir = self.report_dir
ALL_KEYS = ["routes", "auth", "graphql", "realtime", "validate"]
def validate_options(opt):
for k in opt.include_steps + opt.skip_steps:
if k not in ALL_KEYS:
raise ValueError("unknown step key: {0}".format(k))
dup = set(opt.include_steps) & set(opt.skip_steps)
if dup:
raise ValueError("step key in both include_steps and skip_steps: {0}".format(sorted(dup)))
if opt.variant not in ("express", "fastapi"):
raise ValueError("variant must be express or fastapi")
def selected_steps(opt):
if opt.include_steps:
return [k for k in ALL_KEYS if k in opt.include_steps]
return [k for k in ALL_KEYS if k not in opt.skip_steps]
STEPS = OrderedDict()
STEPS["routes"] = {
"skill_path": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",
"contract": {
"inputs": [],
"outputs": [
"express/src/app.ts",
"express/src/routes/todos.ts",
"express/src/middleware/validate.ts",
"express/src/middleware/error.ts",
"express/src/utils/AppError.ts",
"express/src/swagger.ts",
"fastapi/app/main.py",
"fastapi/app/routes/todos.py"
],
"spec_url_express": "http://localhost:3000/api-docs/swagger.json",
"spec_url_fastapi": "http://localhost:8000/api/v1/openapi.json"
},
"probe_file": "express/src/app.ts",
"build": ["npm", "run", "build"],
"report": "routes_report.md"
}
STEPS["auth"] = {
"skill_path": "skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md",
"contract": {
"inputs": ["JWT_ACCESS_SECRET", "JWT_REFRESH_SECRET", "DATABASE_URL", "REDIS_URL"],
"outputs": [
"src/auth.service.ts",
"src/auth.middleware.ts",
"src/auth.routes.ts",
"src/oauth.routes.ts",
"src/server.ts"
],
"mount_path": "/api/auth"
},
"probe_file": "src/server.ts",
"build": ["npm", "run", "build"],
"report": "auth_report.md"
}
STEPS["graphql"] = {
"skill_path": "skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md",
"contract": {
"inputs": [],
"outputs": [
"src/schema.ts",
"src/resolvers.ts",
"src/loaders.ts",
"src/db.ts",
"src/server.ts"
],
"mount_path": "/graphql"
},
"probe_file": "src/schema.ts",
"build": ["npm", "run", "build"],
"report": "graphql_report.md"
}
STEPS["realtime"] = {
"skill_path": "skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md",
"contract": {
"inputs": ["JWT_ACCESS_SECRET", "REDIS_URL"],
"outputs": ["src/server.ts", "src/auth.ts", "src/security.ts", "src/client.ts"],
"health_url": "http://localhost:8080",
"handshake": "socket.handshake.auth.token"
},
"probe_file": "src/server.ts",
"build": ["npm", "run", "build"],
"report": "realtime_report.md"
}
STEPS["validate"] = {
"skill_path": None,
"contract": {
"inputs": ["routes_manifest.json", "smoke_results.txt", "openapi_check.txt", "all_prior_artifacts"],
"outputs": ["BACKEND_SUITE_REPORT.md"],
"manifest": "routes_manifest.json"
},
"probe_file": "routes_manifest.json",
"build": ["node", "--check"],
"report": "validate_report.md"
}
results = OrderedDict()
for key in ALL_KEYS:
results[key] = {
"key": key,
"skill": STEPS[key]["skill_path"] or "orchestrator-internal",
"status": "SKIPPED",
"artifact": None,
"output": ""
}
def capture_stdout(cmd):
try:
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
return proc.returncode == 0, proc.stdout + proc.stderr
except Exception as exc:
return False, "exec error: {0}".format(exc)
def file_exists(rel):
return Path(rel).exists()
def http_ok(url):
try:
import urllib.request
with urllib.request.urlopen(url, timeout=10) as resp:
return resp.status == 200
except Exception as exc:
return False
def run_one(key, opt, predecessor_ok):
step = STEPS[key]
ok, output = True, ""
ok, output = capture_stdout(step["build"])
artifact = step["report"]
if ok and step["probe_file"]:
ok = file_exists(step["probe_file"])
if ok:
Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)
Path(opt.artifact_dir, step["report"]).write_text(
"step={0} status=passed\n{1}".format(key, output), encoding="utf-8"
)
else:
Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)
Path(opt.artifact_dir, step["report"]).write_text(
"step={0} status=failed\n{1}".format(key, output), encoding="utf-8"
)
results[key].update(status="PASSED" if ok else "FAILED", artifact=artifact, output=output[-2000:])
return ok
def run_validate(opt):
step = STEPS["validate"]
routes_ok = True
if opt.variant == "express":
routes_ok = routes_ok and file_exists("express/src/app.ts")
routes_ok = routes_ok and file_exists("express/src/routes/todos.ts")
routes_ok = routes_ok and file_exists("express/src/swagger.ts")
spec_ok = http_ok(step_contract("routes")["spec_url_express"])
else:
routes_ok = routes_ok and file_exists("fastapi/app/main.py")
routes_ok = routes_ok and file_exists("fastapi/app/routes/todos.py")
spec_ok = http_ok(step_contract("routes")["spec_url_fastapi"])
auth_ok = file_exists("src/auth.routes.ts") and file_exists("src/oauth.routes.ts")
graphql_ok = file_exists("src/schema.ts") and file_exists("src/loaders.ts")
realtime_ok = file_exists("src/server.ts") and file_exists("src/auth.ts")
okay = routes_ok and auth_ok and graphql_ok and realtime_ok and spec_ok
manifest = {
"routes_registered": routes_ok,
"auth_registered": auth_ok,
"graphql_registered": graphql_ok,
"realtime_registered": realtime_ok,
"openapi_spec_served": spec_ok
}
Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)
Path(opt.artifact_dir, "routes_manifest.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8")
Path(opt.artifact_dir, "openapi_check.txt").write_text(
"openapi_spec_served={0}".format(spec_ok), encoding="utf-8"
)
results["validate"].update(
status="PASSED" if okay else "FAILED",
artifact="routes_manifest.json",
output=json.dumps(manifest, indent=2)
)
return okay
def step_contract(key):
return STEPS[key]["contract"]
def consolidate(opt):
Path(opt.report_dir).mkdir(parents=True, exist_ok=True)
total = passed = failed = skipped = 0
for key in ALL_KEYS:
total += 1
if results[key]["status"] == "PASSED":
passed += 1
elif results[key]["status"] == "FAILED":
failed += 1
else:
skipped += 1
recommendation = "SHIP" if failed == 0 else "BLOCK"
lines = []
lines.append("# BACKEND_SUITE_REPORT")
lines.append("- suite: backend")
lines.append("- variant: {0}".format(opt.variant))
lines.append("- generated_at: {0}".format(datetime.now(timezone.utc).isoformat()))
lines.append("- aggregate: total={0} passed={1} failed={2} skipped={3}".format(total, passed, failed, skipped))
lines.append("")
lines.append("| step | sub-skill | status | artifact |")
lines.append("| --- | --- | --- | --- |")
for key in ALL_KEYS:
r = results[key]
lines.append("| {0} | {1} | {2} | {3} |".format(r["key"], r["skill"], r["status"], r["artifact"] or "-"))
lines.append("")
lines.append("## Recommendation")
lines.append(recommendation)
for key in ALL_KEYS:
lines.append("")
lines.append("## step: {0}".format(key))
lines.append(results[key]["output"])
out = Path(opt.report_dir, "BACKEND_SUITE_REPORT.md")
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
return out
def main(argv):
options_obj = json.loads(argv[1] if len(argv) > 1 else "{}")
opt = Options(options_obj)
validate_options(opt)
to_run = selected_steps(opt)
predecessor_ok = True
for key in to_run:
if not predecessor_ok and opt.fail_fast:
results[key]["status"] = "SKIPPED"
break
if not predecessor_ok and not opt.fail_fast:
results[key]["status"] = "SKIPPED"
continue
if key == "validate":
step_ok = run_validate(opt)
else:
step_ok = run_one(key, opt, predecessor_ok)
predecessor_ok = predecessor_ok and step_ok
if not step_ok and opt.fail_fast:
break
Path(opt.report_dir).mkdir(parents=True, exist_ok=True)
Path(opt.report_dir, "suite_state.json").write_text(json.dumps(results, indent=2), encoding="utf-8")
out = consolidate(opt)
print("BACKEND_SUITE_REPORT written to {0}".format(out))
sys.exit(0 if results["validate"]["status"] == "PASSED" else 1)
if __name__ == "__main__":
main(sys.argv)
5. Edge Cases & Error Handling
- Missing sub-skill path: each step validates
STEPS[key]["skill_path"] with Path.exists() at pre-flight; a missing file fails that step with status=FAILED, records the missing path in the step report, and (under fail_fast) halts before it can contaminate downstream steps.
- Non-zero exit from a sub-skill:
capture_stdout runs the build command via subprocess.run; a non-zero return code or a raised exception marks the step FAILED and writes the full stdout+stderr tail into the per-step report so the exact compile error is preserved for the consolidated document.
- Malformed options object:
validate_options rejects unknown step keys, rejects keys present in both include_steps and skip_steps, and rejects unknown variants — all before any step executes, so a bad invocation never partially builds.
- Empty report aggregation: if every step is filtered out (
skip_steps covers all five keys or include_steps is empty-but-valid), consolidate still writes BACKEND_SUITE_REPORT.md with steps_total=5, all statuses SKIPPED, and recommendation BLOCK (nothing was produced), so the report is never missing or empty-handed.
- Partial-run / rollback notes: include/skip selection writes a
suite_state.json snapshot of per-step results; re-running with a wider include_steps re-executes only the missing steps, and any step that mutates the shared app files (e.g. auth mounting routers into express/src/app.ts) is run before its dependents. No automated workspace rollback is performed — the git status/git diff of the scaffolded artifacts is listed in the validate report so an operator can revert selective files.
- Rerun-idempotency: the orchestrator is idempotent across runs for a given S1-S4 scaffold — re-running a step rewrites its report file and re-executes its build; the JWT secret inputs are never regenerated automatically (reusing the same
.env keeps S2-issued tokens valid for S4), and the final BACKEND_SUITE_REPORT.md and suite_state.json are overwritten atomically per run with a fresh generated_at timestamp.
- fail_fast=false degradation: a failed predecessor does not abort the run, but dependents that consume its artifacts (
auth→realtime JWT secret sharing, all→validate) are marked SKIPPED because their contract inputs are unavailable; the report explicitly lists these gated steps so downstream gaps are visible, not silently assumed green.
1---2name: backend-suite-orchestrator3description: Orchestrates the 4-stage backend build chain — REST routes with OpenAPI spec (skills/express-fastapi-route-builder), auth/session/OAuth2 (skills/auth-session-oauth2-scaffolder), GraphQL schema plus per-request DataLoaders (skills/graphql-schema-dataloader-builder), and JWT-guarded realtime WebSockets (skills/websocket-realtime-secure-engine) — followed by route-integrity, middleware-registration, build, smoke-test, and API-spec validation. Accepts full_run, include_steps, and skip_steps parameters to execute only a selected chain subset, applies predecessor gating and fail_fast semantics, captures per-step stdout and reports, and consolidates everything into a single BACKEND_SUITE_REPORT.md with aggregate counts, per-step pass/fail status, and recommendations.4metadata:5 source: skills/backend-suite-orchestrator/backend-suite-orchestrator.md6---78# Backend Suite Orchestrator910## 1. System Overview & Target Sub-Skills11- The Backend Suite Orchestrator is a meta-skill that executes the full backend construction pipeline for a Node.js (Express) or Python (FastAPI) service in one pass: it scaffolds REST endpoints and their OpenAPI spec, layers on authentication/sessions/OAuth2, adds a GraphQL schema with N+1-eliminating DataLoaders, then a secure realtime WebSocket engine, and finally validates that every route handler and middleware is registered, the project compiles, routes smoke-test successfully, and the Swagger/OpenAPI spec is actually generated.12- It is invoked when the user wants a complete, validated backend skeleton rather than a single concern: "build the whole API back-end", "assemble REST + auth + GraphQL + realtime", or "run the backend suite end-to-end". It is also used to re-run only a subset of stages (e.g. regenerate auth then re-validate) via include_steps / skip_steps.13- Ordered bullet list of every sub-skill invoked, with the exact path and what it produces:14 1. `skills/express-fastapi-route-builder/express-fastapi-route-builder.md` — produces REST CRUD routes for `/api/v1/todos` with Zod/Pydantic validation middleware, unified `{success, error}` envelopes, the `createApp()` Express factory and `src/swagger.ts`, and a served OpenAPI 3.0 spec (`http://localhost:3000/api-docs/swagger.json` on Express, `http://localhost:8000/api/v1/openapi.json` on FastAPI).15 2. `skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md` — produces the auth service (`src/auth.service.ts`), `requireAuth` middleware (`src/auth.middleware.ts`), `/api/auth/*` routers plus Google/GitHub OAuth2 routes, cookie sessions (`access_token` 15m, `refresh_token` 7d scoped to `/api/auth`), Argon2id password hashing, and refresh-token rotation with Redis blacklist.16 3. `skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md` — produces the GraphQL SDL (`src/schema.ts`), typed resolvers (`src/resolvers.ts`), the `createLoaders()` factory (`src/loaders.ts`), the in-memory repository (`src/db.ts`), and the Apollo Server 4 bootstrap (`src/server.ts`) that mounts the endpoint at `/graphql`.17 4. `skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md` — produces the socket.io engine (`src/server.ts`), JWT handshake verification (`src/auth.ts`), role-based room policy (`src/security.ts`), and a resync-capable client (`src/client.ts`) serving `ws://localhost:8080` with a plain-HTTP health probe.18 5. Final validation (orchestrator-run, no sub-skill file) — audits that every preceding router/middleware is registered on the assembled app, runs the `npm run build`-style TypeScript/compile check plus route smoke tests, confirms the OpenAPI spec URL responds, and collects all results into `BACKEND_SUITE_REPORT.md`.1920## 2. Execution Parameters & Configuration Options21- **full_run**: execute the entire chain in order (`routes → auth → graphql → realtime → validate`).22- **include_steps**: array of step keys to run (run ONLY these; other steps are skipped regardless of skip_steps).23- **skip_steps**: array of step keys to skip (all other steps run).24- **fail_fast** (default true): halt on first failing step; when false, remaining steps still run but the consolidated report marks them and the suite as FAILED.25- **report_dir / artifact_dir**: where per-step outputs and the final consolidated report are written (default `skills/backend-suite-orchestrator/reports/`).26- Step keys: `routes` (S1), `auth` (S2), `graphql` (S3), `realtime` (S4), `validate` (S5).2728### Orchestrator input/options object — JSON Schema draft-0729```json30{31 "$schema": "http://json-schema.org/draft-07/schema#",32 "type": "object",33 "properties": {34 "full_run": { "type": "boolean", "default": true },35 "include_steps": {36 "type": "array",37 "items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },38 "default": []39 },40 "skip_steps": {41 "type": "array",42 "items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },43 "default": []44 },45 "fail_fast": { "type": "boolean", "default": true },46 "variant": { "enum": ["express", "fastapi"], "default": "express" },47 "report_dir": { "type": "string", "default": "skills/backend-suite-orchestrator/reports/" }48 },49 "additionalProperties": false50}51```5253### Consolidated output report — BACKEND_SUITE_REPORT.md54```json55{56 "report": "BACKEND_SUITE_REPORT.md",57 "suite": "backend",58 "variant": "express",59 "generated_at": "ISO8601",60 "aggregate": { "steps_total": 5, "steps_passed": 0, "steps_failed": 0, "steps_skipped": 0 },61 "steps": [62 {63 "key": "routes",64 "skill": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",65 "status": "PASSED|FAILED|SKIPPED",66 "artifact": "express/src/app.ts",67 "output": "captured stdout tail"68 }69 ],70 "recommendation": "SHIP|REVIEW|BLOCK"71}72```7374## 3. Step-by-Step Execution Protocol & Data Flow751. **Pre-flight Check**: verify the repo root and that every sub-skill path listed in Section 1 exists as a readable file; confirm required CLIs are on PATH (`node`, `npm` for Express; `python`/`pip`/`uv`, `uvicorn` for FastAPI); create `report_dir` and `artifact_dir`; validate the options object against the Section 2 schema (reject unknown step keys, reject `include_steps` ∩ `skip_steps` on the same key).762. **Sequential Chaining** — numbered steps S1..S5:77 - **S1 (key `routes`)**: invoke `skills/express-fastapi-route-builder/express-fastapi-route-builder.md`. Input: none (pre-existing scaffold requirements). Primary output: `express/src/app.ts` (`createApp()`), `express/src/routes/todos.ts`, `express/src/middleware/validate.ts`, `express/src/services/todoService.ts`, `express/src/swagger.ts`; step-report `routes_report.md`.78 - **S2 (key `auth`)**: invoke `skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md`. Input: `JWT_ACCESS_SECRET`/`JWT_REFRESH_SECRET` (min 32 chars), `DATABASE_URL`, `REDIS_URL` from its `.env.example`. Primary output: `src/server.ts`, `src/auth.service.ts`, `src/auth.middleware.ts`, `src/auth.routes.ts`, `src/oauth.routes.ts`; step-report `auth_report.md`.79 - **S3 (key `graphql`)**: invoke `skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md`. Input: none beyond the scaffold. Primary output: `src/schema.ts`, `src/resolvers.ts`, `src/loaders.ts`, `src/db.ts`, `src/server.ts`; step-report `graphql_report.md`.80 - **S4 (key `realtime`)**: invoke `skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md`. Input: `JWT_ACCESS_SECRET` (shared from S2), `REDIS_URL`. Primary output: `src/server.ts`, `src/auth.ts`, `src/security.ts`, `src/client.ts`; step-report `realtime_report.md`.81 - **S5 (key `validate`)**: orchestrator-internal validation. Verifies all routers/middleware are registered on the assembled app (`/api/v1/todos`, `/api/auth`, `/api/auth.oauth`, `/graphql`, WS engine), runs the build check (`npm run build` i.e. `tsc -p tsconfig.json`; FastAPI: compileall or `uvicorn` boot probe), runs route smoke tests against every endpoint, and confirms the OpenAPI spec is served (GET `http://localhost:3000/api-docs/swagger.json` on Express / `http://localhost:8000/api/v1/openapi.json` on FastAPI). Emergency output: `routes_manifest.json`, `smoke_results.txt`, `openapi_check.txt`, step-report `validate_report.md`.823. **Data Contracting** — step-N output artifact → step-(N+1) input field mappings:83 - `express/src/app.ts` `createApp()` instance (S1) → S2 router registration: `src/auth.routes.ts` + `src/oauth.routes.ts` from S2 are mounted onto the S1 Express app via `app.use('/api/auth', authRouter)` and `app.use('/api/auth', oauthRouter)`, and the S1 app's `errorHandler`/`notFoundHandler` stay terminal in the merged stack.84 - `express/src/middleware/validate.ts` + `express/src/utils/AppError.ts` (S1) → S2 guard wiring: the S2 `requireAuth` middleware from `src/auth.middleware.ts` (Bearer or `access_token` cookie) is inserted in front of the protected REST routes, converting a missing/expired token into the S1 error envelope `HTTP 401 UNAUTHORIZED`.85 - `src/auth.service.ts` issued `access_token` JWT (claims `sub`, `email`, `displayName`, type `access`, signed with `JWT_ACCESS_SECRET`) (S2) → S4 handshake auth: `src/auth.ts` `verifyJwt()` validates the same token via `socket.handshake.auth.token` or the `x-access-token` header; the `role` claim it reads corresponds to the S4 `Role` type used by `src/security.ts` `canJoin()`/`assertCanJoin()` room policy.86 - `.env` `JWT_ACCESS_SECRET` inside S2's config (`src/config.ts` reads it via zod, min 32 chars) (S2) → S4's `src/auth.ts` reads the identical `JWT_ACCESS_SECRET` env var so one token family spans REST and the realtime engine; the S4 WS engine is attached to the S1/S2 HTTP server so a single origin serves REST + GraphQL + WS.87 - `src/schema.ts` `typeDefs` + `src/resolvers.ts` + `src/loaders.ts` `createLoaders()` (S3) → the Apollo server bootstrap `src/server.ts` mounts the schema and injects `context = { loaders: createLoaders() }` per request; the `context` shape is passed into S2's merged server so `requireAuth` guards GraphQL mutations and S3's `Mutation` resolvers still call `loader.clear(key)` after writes as documented in the S3 contract.88 - `src/server.ts` engine + `src/client.ts` (S4) → S5 smoke tests: the WS health probe at `http://localhost:8080` (returns `{"service":"realtime-engine"}`) is pinged, then a client connect with an S2-issued token exercises `room:join` → `room:joined { channel, resumeSeq }` → `chat:send` → broadcast `message { seq, channel, userId, payload, ts }`.89 - All prior artifacts → S5 validation: `routes_manifest.json` (accumulated registration audit) + `smoke_results.txt` (each endpoint HTTP status) + `openapi_check.txt` (Swagger spec fetch) → the consolidated step-record fields of `BACKEND_SUITE_REPORT.md`.904. **Final Consolidation**: merge the five per-step reports (`routes_report.md`, `auth_report.md`, `graphql_report.md`, `realtime_report.md`, `validate_report.md`) into one unified summary document written to `report_dir/BACKEND_SUITE_REPORT.md` (default `skills/backend-suite-orchestrator/reports/BACKEND_SUITE_REPORT.md`), containing aggregate counts (steps_total/passed/failed/skipped), a per-step table of `key | sub-skill | status | artifact`, the captured stdout tails, the consolidated route-registration manifest, the OpenAPI spec check result, and a recommendation section (SHIP when all steps passed and the spec is served; REVIEW on any non-fatal warning; BLOCK on any step failure).9192## 4. Reference Execution DAG / Pseudo-Code Implementation93```python94import json, re, subprocess, sys95from collections import OrderedDict96from datetime import datetime, timezone97from pathlib import Path9899class Options:100 def __init__(self, obj):101 self.full_run = obj.get("full_run", True)102 self.include_steps = obj.get("include_steps", [])103 self.skip_steps = obj.get("skip_steps", [])104 self.fail_fast = obj.get("fail_fast", True)105 self.variant = obj.get("variant", "express")106 self.report_dir = obj.get("report_dir", "skills/backend-suite-orchestrator/reports/")107 self.artifact_dir = self.report_dir108109ALL_KEYS = ["routes", "auth", "graphql", "realtime", "validate"]110111def validate_options(opt):112 for k in opt.include_steps + opt.skip_steps:113 if k not in ALL_KEYS:114 raise ValueError("unknown step key: {0}".format(k))115 dup = set(opt.include_steps) & set(opt.skip_steps)116 if dup:117 raise ValueError("step key in both include_steps and skip_steps: {0}".format(sorted(dup)))118 if opt.variant not in ("express", "fastapi"):119 raise ValueError("variant must be express or fastapi")120121def selected_steps(opt):122 if opt.include_steps:123 return [k for k in ALL_KEYS if k in opt.include_steps]124 return [k for k in ALL_KEYS if k not in opt.skip_steps]125126STEPS = OrderedDict()127STEPS["routes"] = {128 "skill_path": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",129 "contract": {130 "inputs": [],131 "outputs": [132 "express/src/app.ts",133 "express/src/routes/todos.ts",134 "express/src/middleware/validate.ts",135 "express/src/middleware/error.ts",136 "express/src/utils/AppError.ts",137 "express/src/swagger.ts",138 "fastapi/app/main.py",139 "fastapi/app/routes/todos.py"140 ],141 "spec_url_express": "http://localhost:3000/api-docs/swagger.json",142 "spec_url_fastapi": "http://localhost:8000/api/v1/openapi.json"143 },144 "probe_file": "express/src/app.ts",145 "build": ["npm", "run", "build"],146 "report": "routes_report.md"147}148STEPS["auth"] = {149 "skill_path": "skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md",150 "contract": {151 "inputs": ["JWT_ACCESS_SECRET", "JWT_REFRESH_SECRET", "DATABASE_URL", "REDIS_URL"],152 "outputs": [153 "src/auth.service.ts",154 "src/auth.middleware.ts",155 "src/auth.routes.ts",156 "src/oauth.routes.ts",157 "src/server.ts"158 ],159 "mount_path": "/api/auth"160 },161 "probe_file": "src/server.ts",162 "build": ["npm", "run", "build"],163 "report": "auth_report.md"164}165STEPS["graphql"] = {166 "skill_path": "skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md",167 "contract": {168 "inputs": [],169 "outputs": [170 "src/schema.ts",171 "src/resolvers.ts",172 "src/loaders.ts",173 "src/db.ts",174 "src/server.ts"175 ],176 "mount_path": "/graphql"177 },178 "probe_file": "src/schema.ts",179 "build": ["npm", "run", "build"],180 "report": "graphql_report.md"181}182STEPS["realtime"] = {183 "skill_path": "skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md",184 "contract": {185 "inputs": ["JWT_ACCESS_SECRET", "REDIS_URL"],186 "outputs": ["src/server.ts", "src/auth.ts", "src/security.ts", "src/client.ts"],187 "health_url": "http://localhost:8080",188 "handshake": "socket.handshake.auth.token"189 },190 "probe_file": "src/server.ts",191 "build": ["npm", "run", "build"],192 "report": "realtime_report.md"193}194STEPS["validate"] = {195 "skill_path": None,196 "contract": {197 "inputs": ["routes_manifest.json", "smoke_results.txt", "openapi_check.txt", "all_prior_artifacts"],198 "outputs": ["BACKEND_SUITE_REPORT.md"],199 "manifest": "routes_manifest.json"200 },201 "probe_file": "routes_manifest.json",202 "build": ["node", "--check"],203 "report": "validate_report.md"204}205206results = OrderedDict()207for key in ALL_KEYS:208 results[key] = {209 "key": key,210 "skill": STEPS[key]["skill_path"] or "orchestrator-internal",211 "status": "SKIPPED",212 "artifact": None,213 "output": ""214 }215216def capture_stdout(cmd):217 try:218 proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180)219 return proc.returncode == 0, proc.stdout + proc.stderr220 except Exception as exc:221 return False, "exec error: {0}".format(exc)222223def file_exists(rel):224 return Path(rel).exists()225226def http_ok(url):227 try:228 import urllib.request229 with urllib.request.urlopen(url, timeout=10) as resp:230 return resp.status == 200231 except Exception as exc:232 return False233234def run_one(key, opt, predecessor_ok):235 step = STEPS[key]236 ok, output = True, ""237 ok, output = capture_stdout(step["build"])238 artifact = step["report"]239 if ok and step["probe_file"]:240 ok = file_exists(step["probe_file"])241 if ok:242 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)243 Path(opt.artifact_dir, step["report"]).write_text(244 "step={0} status=passed\n{1}".format(key, output), encoding="utf-8"245 )246 else:247 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)248 Path(opt.artifact_dir, step["report"]).write_text(249 "step={0} status=failed\n{1}".format(key, output), encoding="utf-8"250 )251 results[key].update(status="PASSED" if ok else "FAILED", artifact=artifact, output=output[-2000:])252 return ok253254def run_validate(opt):255 step = STEPS["validate"]256 routes_ok = True257 if opt.variant == "express":258 routes_ok = routes_ok and file_exists("express/src/app.ts")259 routes_ok = routes_ok and file_exists("express/src/routes/todos.ts")260 routes_ok = routes_ok and file_exists("express/src/swagger.ts")261 spec_ok = http_ok(step_contract("routes")["spec_url_express"])262 else:263 routes_ok = routes_ok and file_exists("fastapi/app/main.py")264 routes_ok = routes_ok and file_exists("fastapi/app/routes/todos.py")265 spec_ok = http_ok(step_contract("routes")["spec_url_fastapi"])266 auth_ok = file_exists("src/auth.routes.ts") and file_exists("src/oauth.routes.ts")267 graphql_ok = file_exists("src/schema.ts") and file_exists("src/loaders.ts")268 realtime_ok = file_exists("src/server.ts") and file_exists("src/auth.ts")269 okay = routes_ok and auth_ok and graphql_ok and realtime_ok and spec_ok270 manifest = {271 "routes_registered": routes_ok,272 "auth_registered": auth_ok,273 "graphql_registered": graphql_ok,274 "realtime_registered": realtime_ok,275 "openapi_spec_served": spec_ok276 }277 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)278 Path(opt.artifact_dir, "routes_manifest.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8")279 Path(opt.artifact_dir, "openapi_check.txt").write_text(280 "openapi_spec_served={0}".format(spec_ok), encoding="utf-8"281 )282 results["validate"].update(283 status="PASSED" if okay else "FAILED",284 artifact="routes_manifest.json",285 output=json.dumps(manifest, indent=2)286 )287 return okay288289def step_contract(key):290 return STEPS[key]["contract"]291292def consolidate(opt):293 Path(opt.report_dir).mkdir(parents=True, exist_ok=True)294 total = passed = failed = skipped = 0295 for key in ALL_KEYS:296 total += 1297 if results[key]["status"] == "PASSED":298 passed += 1299 elif results[key]["status"] == "FAILED":300 failed += 1301 else:302 skipped += 1303 recommendation = "SHIP" if failed == 0 else "BLOCK"304 lines = []305 lines.append("# BACKEND_SUITE_REPORT")306 lines.append("- suite: backend")307 lines.append("- variant: {0}".format(opt.variant))308 lines.append("- generated_at: {0}".format(datetime.now(timezone.utc).isoformat()))309 lines.append("- aggregate: total={0} passed={1} failed={2} skipped={3}".format(total, passed, failed, skipped))310 lines.append("")311 lines.append("| step | sub-skill | status | artifact |")312 lines.append("| --- | --- | --- | --- |")313 for key in ALL_KEYS:314 r = results[key]315 lines.append("| {0} | {1} | {2} | {3} |".format(r["key"], r["skill"], r["status"], r["artifact"] or "-"))316 lines.append("")317 lines.append("## Recommendation")318 lines.append(recommendation)319 for key in ALL_KEYS:320 lines.append("")321 lines.append("## step: {0}".format(key))322 lines.append(results[key]["output"])323 out = Path(opt.report_dir, "BACKEND_SUITE_REPORT.md")324 out.write_text("\n".join(lines) + "\n", encoding="utf-8")325 return out326327def main(argv):328 options_obj = json.loads(argv[1] if len(argv) > 1 else "{}")329 opt = Options(options_obj)330 validate_options(opt)331 to_run = selected_steps(opt)332 predecessor_ok = True333 for key in to_run:334 if not predecessor_ok and opt.fail_fast:335 results[key]["status"] = "SKIPPED"336 break337 if not predecessor_ok and not opt.fail_fast:338 results[key]["status"] = "SKIPPED"339 continue340 if key == "validate":341 step_ok = run_validate(opt)342 else:343 step_ok = run_one(key, opt, predecessor_ok)344 predecessor_ok = predecessor_ok and step_ok345 if not step_ok and opt.fail_fast:346 break347 Path(opt.report_dir).mkdir(parents=True, exist_ok=True)348 Path(opt.report_dir, "suite_state.json").write_text(json.dumps(results, indent=2), encoding="utf-8")349 out = consolidate(opt)350 print("BACKEND_SUITE_REPORT written to {0}".format(out))351 sys.exit(0 if results["validate"]["status"] == "PASSED" else 1)352353if __name__ == "__main__":354 main(sys.argv)355```356357## 5. Edge Cases & Error Handling358- **Missing sub-skill path**: each step validates `STEPS[key]["skill_path"]` with `Path.exists()` at pre-flight; a missing file fails that step with `status=FAILED`, records the missing path in the step report, and (under fail_fast) halts before it can contaminate downstream steps.359- **Non-zero exit from a sub-skill**: `capture_stdout` runs the build command via `subprocess.run`; a non-zero return code or a raised exception marks the step FAILED and writes the full stdout+stderr tail into the per-step report so the exact compile error is preserved for the consolidated document.360- **Malformed options object**: `validate_options` rejects unknown step keys, rejects keys present in both `include_steps` and `skip_steps`, and rejects unknown variants — all before any step executes, so a bad invocation never partially builds.361- **Empty report aggregation**: if every step is filtered out (`skip_steps` covers all five keys or `include_steps` is empty-but-valid), `consolidate` still writes `BACKEND_SUITE_REPORT.md` with `steps_total=5`, all statuses `SKIPPED`, and recommendation `BLOCK` (nothing was produced), so the report is never missing or empty-handed.362- **Partial-run / rollback notes**: include/skip selection writes a `suite_state.json` snapshot of per-step results; re-running with a wider `include_steps` re-executes only the missing steps, and any step that mutates the shared app files (e.g. `auth` mounting routers into `express/src/app.ts`) is run before its dependents. No automated workspace rollback is performed — the `git status`/`git diff` of the scaffolded artifacts is listed in the validate report so an operator can revert selective files.363- **Rerun-idempotency**: the orchestrator is idempotent across runs for a given S1-S4 scaffold — re-running a step rewrites its report file and re-executes its build; the JWT secret inputs are never regenerated automatically (reusing the same `.env` keeps S2-issued tokens valid for S4), and the final `BACKEND_SUITE_REPORT.md` and `suite_state.json` are overwritten atomically per run with a fresh `generated_at` timestamp.364- **fail_fast=false degradation**: a failed predecessor does not abort the run, but dependents that consume its artifacts (`auth`→`realtime` JWT secret sharing, all→`validate`) are marked `SKIPPED` because their contract inputs are unavailable; the report explicitly lists these gated steps so downstream gaps are visible, not silently assumed green.