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.4---56# Backend Suite Orchestrator78## 1. System Overview & Target Sub-Skills9- 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.10- 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.11- Ordered bullet list of every sub-skill invoked, with the exact path and what it produces:12 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).13 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.14 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`.15 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.16 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`.1718## 2. Execution Parameters & Configuration Options19- **full_run**: execute the entire chain in order (`routes → auth → graphql → realtime → validate`).20- **include_steps**: array of step keys to run (run ONLY these; other steps are skipped regardless of skip_steps).21- **skip_steps**: array of step keys to skip (all other steps run).22- **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.23- **report_dir / artifact_dir**: where per-step outputs and the final consolidated report are written (default `skills/backend-suite-orchestrator/reports/`).24- Step keys: `routes` (S1), `auth` (S2), `graphql` (S3), `realtime` (S4), `validate` (S5).2526### Orchestrator input/options object — JSON Schema draft-0727```json28{29 "$schema": "http://json-schema.org/draft-07/schema#",30 "type": "object",31 "properties": {32 "full_run": { "type": "boolean", "default": true },33 "include_steps": {34 "type": "array",35 "items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },36 "default": []37 },38 "skip_steps": {39 "type": "array",40 "items": { "enum": ["routes", "auth", "graphql", "realtime", "validate"] },41 "default": []42 },43 "fail_fast": { "type": "boolean", "default": true },44 "variant": { "enum": ["express", "fastapi"], "default": "express" },45 "report_dir": { "type": "string", "default": "skills/backend-suite-orchestrator/reports/" }46 },47 "additionalProperties": false48}49```5051### Consolidated output report — BACKEND_SUITE_REPORT.md52```json53{54 "report": "BACKEND_SUITE_REPORT.md",55 "suite": "backend",56 "variant": "express",57 "generated_at": "ISO8601",58 "aggregate": { "steps_total": 5, "steps_passed": 0, "steps_failed": 0, "steps_skipped": 0 },59 "steps": [60 {61 "key": "routes",62 "skill": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",63 "status": "PASSED|FAILED|SKIPPED",64 "artifact": "express/src/app.ts",65 "output": "captured stdout tail"66 }67 ],68 "recommendation": "SHIP|REVIEW|BLOCK"69}70```7172## 3. Step-by-Step Execution Protocol & Data Flow731. **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).742. **Sequential Chaining** — numbered steps S1..S5:75 - **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`.76 - **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`.77 - **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`.78 - **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`.79 - **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`.803. **Data Contracting** — step-N output artifact → step-(N+1) input field mappings:81 - `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.82 - `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`.83 - `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.84 - `.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.85 - `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.86 - `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 }`.87 - 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`.884. **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).8990## 4. Reference Execution DAG / Pseudo-Code Implementation91```python92import json, re, subprocess, sys93from collections import OrderedDict94from datetime import datetime, timezone95from pathlib import Path9697class Options:98 def __init__(self, obj):99 self.full_run = obj.get("full_run", True)100 self.include_steps = obj.get("include_steps", [])101 self.skip_steps = obj.get("skip_steps", [])102 self.fail_fast = obj.get("fail_fast", True)103 self.variant = obj.get("variant", "express")104 self.report_dir = obj.get("report_dir", "skills/backend-suite-orchestrator/reports/")105 self.artifact_dir = self.report_dir106107ALL_KEYS = ["routes", "auth", "graphql", "realtime", "validate"]108109def validate_options(opt):110 for k in opt.include_steps + opt.skip_steps:111 if k not in ALL_KEYS:112 raise ValueError("unknown step key: {0}".format(k))113 dup = set(opt.include_steps) & set(opt.skip_steps)114 if dup:115 raise ValueError("step key in both include_steps and skip_steps: {0}".format(sorted(dup)))116 if opt.variant not in ("express", "fastapi"):117 raise ValueError("variant must be express or fastapi")118119def selected_steps(opt):120 if opt.include_steps:121 return [k for k in ALL_KEYS if k in opt.include_steps]122 return [k for k in ALL_KEYS if k not in opt.skip_steps]123124STEPS = OrderedDict()125STEPS["routes"] = {126 "skill_path": "skills/express-fastapi-route-builder/express-fastapi-route-builder.md",127 "contract": {128 "inputs": [],129 "outputs": [130 "express/src/app.ts",131 "express/src/routes/todos.ts",132 "express/src/middleware/validate.ts",133 "express/src/middleware/error.ts",134 "express/src/utils/AppError.ts",135 "express/src/swagger.ts",136 "fastapi/app/main.py",137 "fastapi/app/routes/todos.py"138 ],139 "spec_url_express": "http://localhost:3000/api-docs/swagger.json",140 "spec_url_fastapi": "http://localhost:8000/api/v1/openapi.json"141 },142 "probe_file": "express/src/app.ts",143 "build": ["npm", "run", "build"],144 "report": "routes_report.md"145}146STEPS["auth"] = {147 "skill_path": "skills/auth-session-oauth2-scaffolder/auth-session-oauth2-scaffolder.md",148 "contract": {149 "inputs": ["JWT_ACCESS_SECRET", "JWT_REFRESH_SECRET", "DATABASE_URL", "REDIS_URL"],150 "outputs": [151 "src/auth.service.ts",152 "src/auth.middleware.ts",153 "src/auth.routes.ts",154 "src/oauth.routes.ts",155 "src/server.ts"156 ],157 "mount_path": "/api/auth"158 },159 "probe_file": "src/server.ts",160 "build": ["npm", "run", "build"],161 "report": "auth_report.md"162}163STEPS["graphql"] = {164 "skill_path": "skills/graphql-schema-dataloader-builder/graphql-schema-dataloader-builder.md",165 "contract": {166 "inputs": [],167 "outputs": [168 "src/schema.ts",169 "src/resolvers.ts",170 "src/loaders.ts",171 "src/db.ts",172 "src/server.ts"173 ],174 "mount_path": "/graphql"175 },176 "probe_file": "src/schema.ts",177 "build": ["npm", "run", "build"],178 "report": "graphql_report.md"179}180STEPS["realtime"] = {181 "skill_path": "skills/websocket-realtime-secure-engine/websocket-realtime-secure-engine.md",182 "contract": {183 "inputs": ["JWT_ACCESS_SECRET", "REDIS_URL"],184 "outputs": ["src/server.ts", "src/auth.ts", "src/security.ts", "src/client.ts"],185 "health_url": "http://localhost:8080",186 "handshake": "socket.handshake.auth.token"187 },188 "probe_file": "src/server.ts",189 "build": ["npm", "run", "build"],190 "report": "realtime_report.md"191}192STEPS["validate"] = {193 "skill_path": None,194 "contract": {195 "inputs": ["routes_manifest.json", "smoke_results.txt", "openapi_check.txt", "all_prior_artifacts"],196 "outputs": ["BACKEND_SUITE_REPORT.md"],197 "manifest": "routes_manifest.json"198 },199 "probe_file": "routes_manifest.json",200 "build": ["node", "--check"],201 "report": "validate_report.md"202}203204results = OrderedDict()205for key in ALL_KEYS:206 results[key] = {207 "key": key,208 "skill": STEPS[key]["skill_path"] or "orchestrator-internal",209 "status": "SKIPPED",210 "artifact": None,211 "output": ""212 }213214def capture_stdout(cmd):215 try:216 proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180)217 return proc.returncode == 0, proc.stdout + proc.stderr218 except Exception as exc:219 return False, "exec error: {0}".format(exc)220221def file_exists(rel):222 return Path(rel).exists()223224def http_ok(url):225 try:226 import urllib.request227 with urllib.request.urlopen(url, timeout=10) as resp:228 return resp.status == 200229 except Exception as exc:230 return False231232def run_one(key, opt, predecessor_ok):233 step = STEPS[key]234 ok, output = True, ""235 ok, output = capture_stdout(step["build"])236 artifact = step["report"]237 if ok and step["probe_file"]:238 ok = file_exists(step["probe_file"])239 if ok:240 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)241 Path(opt.artifact_dir, step["report"]).write_text(242 "step={0} status=passed\n{1}".format(key, output), encoding="utf-8"243 )244 else:245 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)246 Path(opt.artifact_dir, step["report"]).write_text(247 "step={0} status=failed\n{1}".format(key, output), encoding="utf-8"248 )249 results[key].update(status="PASSED" if ok else "FAILED", artifact=artifact, output=output[-2000:])250 return ok251252def run_validate(opt):253 step = STEPS["validate"]254 routes_ok = True255 if opt.variant == "express":256 routes_ok = routes_ok and file_exists("express/src/app.ts")257 routes_ok = routes_ok and file_exists("express/src/routes/todos.ts")258 routes_ok = routes_ok and file_exists("express/src/swagger.ts")259 spec_ok = http_ok(step_contract("routes")["spec_url_express"])260 else:261 routes_ok = routes_ok and file_exists("fastapi/app/main.py")262 routes_ok = routes_ok and file_exists("fastapi/app/routes/todos.py")263 spec_ok = http_ok(step_contract("routes")["spec_url_fastapi"])264 auth_ok = file_exists("src/auth.routes.ts") and file_exists("src/oauth.routes.ts")265 graphql_ok = file_exists("src/schema.ts") and file_exists("src/loaders.ts")266 realtime_ok = file_exists("src/server.ts") and file_exists("src/auth.ts")267 okay = routes_ok and auth_ok and graphql_ok and realtime_ok and spec_ok268 manifest = {269 "routes_registered": routes_ok,270 "auth_registered": auth_ok,271 "graphql_registered": graphql_ok,272 "realtime_registered": realtime_ok,273 "openapi_spec_served": spec_ok274 }275 Path(opt.artifact_dir).mkdir(parents=True, exist_ok=True)276 Path(opt.artifact_dir, "routes_manifest.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8")277 Path(opt.artifact_dir, "openapi_check.txt").write_text(278 "openapi_spec_served={0}".format(spec_ok), encoding="utf-8"279 )280 results["validate"].update(281 status="PASSED" if okay else "FAILED",282 artifact="routes_manifest.json",283 output=json.dumps(manifest, indent=2)284 )285 return okay286287def step_contract(key):288 return STEPS[key]["contract"]289290def consolidate(opt):291 Path(opt.report_dir).mkdir(parents=True, exist_ok=True)292 total = passed = failed = skipped = 0293 for key in ALL_KEYS:294 total += 1295 if results[key]["status"] == "PASSED":296 passed += 1297 elif results[key]["status"] == "FAILED":298 failed += 1299 else:300 skipped += 1301 recommendation = "SHIP" if failed == 0 else "BLOCK"302 lines = []303 lines.append("# BACKEND_SUITE_REPORT")304 lines.append("- suite: backend")305 lines.append("- variant: {0}".format(opt.variant))306 lines.append("- generated_at: {0}".format(datetime.now(timezone.utc).isoformat()))307 lines.append("- aggregate: total={0} passed={1} failed={2} skipped={3}".format(total, passed, failed, skipped))308 lines.append("")309 lines.append("| step | sub-skill | status | artifact |")310 lines.append("| --- | --- | --- | --- |")311 for key in ALL_KEYS:312 r = results[key]313 lines.append("| {0} | {1} | {2} | {3} |".format(r["key"], r["skill"], r["status"], r["artifact"] or "-"))314 lines.append("")315 lines.append("## Recommendation")316 lines.append(recommendation)317 for key in ALL_KEYS:318 lines.append("")319 lines.append("## step: {0}".format(key))320 lines.append(results[key]["output"])321 out = Path(opt.report_dir, "BACKEND_SUITE_REPORT.md")322 out.write_text("\n".join(lines) + "\n", encoding="utf-8")323 return out324325def main(argv):326 options_obj = json.loads(argv[1] if len(argv) > 1 else "{}")327 opt = Options(options_obj)328 validate_options(opt)329 to_run = selected_steps(opt)330 predecessor_ok = True331 for key in to_run:332 if not predecessor_ok and opt.fail_fast:333 results[key]["status"] = "SKIPPED"334 break335 if not predecessor_ok and not opt.fail_fast:336 results[key]["status"] = "SKIPPED"337 continue338 if key == "validate":339 step_ok = run_validate(opt)340 else:341 step_ok = run_one(key, opt, predecessor_ok)342 predecessor_ok = predecessor_ok and step_ok343 if not step_ok and opt.fail_fast:344 break345 Path(opt.report_dir).mkdir(parents=True, exist_ok=True)346 Path(opt.report_dir, "suite_state.json").write_text(json.dumps(results, indent=2), encoding="utf-8")347 out = consolidate(opt)348 print("BACKEND_SUITE_REPORT written to {0}".format(out))349 sys.exit(0 if results["validate"]["status"] == "PASSED" else 1)350351if __name__ == "__main__":352 main(sys.argv)353```354355## 5. Edge Cases & Error Handling356- **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.357- **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.358- **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.359- **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.360- **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.361- **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.362- **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.