-
-
End-to-end architecture: Next.js on Vercel → server actions/routes → Drizzle → Aurora PostgreSQL. OIDC→IAM, no passwords
-
Executive overview: estate health score, risk mix, and a labeled Aurora scale-test card (500 programs / 2,000 edges seeded in Aurora).
-
Claude-generated per-program report: what it does, why it's risky, migration strategy, and auto-generated modernization tickets.
-
Amazon Aurora PostgreSQL Serverless v2 cluster h0-cobol-estate — Available in us-east-1, the system of record for the estate graph.
-
Product UI designed and iterated in v0 — the enterprise dashboard shell, dependency views, and report screens generated here.
-
Public repo: typed schema, recursive-CTE cycle traversal, ADRs, and Vitest tests running against a real PostgreSQL 16 container.
-
Dependency intelligence: interactive call graph with a recursive cycle (CLAIMS42) flagged as a first-class modernization risk.
-
Vercel ↔ Amazon Aurora connector: the database wired to the deployment via the official integration, keyless OIDC→IAM access.
-
Keyless security spine: IAM Authentication enabled, reached via VercelConsoleAccessRole — no static AWS keys, no DATABASE_URL in the repo.
Inspiration
Trillions of dollars in banking, insurance, and government systems still run on legacy mainframe code — much of it COBOL — that almost nobody on staff fully understands anymore. The real risk isn't any single program. It's the 'callgraph' which program calls which, where the cycles are, and what breaks if you touch the wrong node. Modernization teams spend months reverse-engineering that graph by hand before they can safely change a line. I wanted to compress that discovery phase from months to minutes.
What it does
COBOL Estate Modernizer ingests a legacy estate and turns it into a live, queryable knowledge base: -Dependency graph: programs and copybooks as nodes, typed CALL / COPY edges, laid out automatically. Node size scales with coupling so the load-bearing programs are obvious at a glance.
Cycle-safe call-chain traversal: the technical centerpiece. COBOL call graphs can be mutually recursive (A calls B, B calls A). A naive traversal never terminates. We walk the entire downstream chain in 'one databaseround-trip' and surface cycles as a first-class modernization risk instead of crashing on them.
AI analysis: per-program Explain / Modernize / Assess / Extract modes, streamed live, with every run recorded back to the database as lineage.
How we built it
Frontend & deploy: Next.js 16 (App Router, Turbopack) + React 19, deployed on Vercel, with the product UI designed and iterated in v0. The dependency graph renders with React Flow, laid out server-side with dagre so the client just paints.
Database: 'Amazon Aurora PostgreSQL Serverless v2 (PG16)'. The estate is a graph, and the headline feature is recursive traversal — which maps directly onto a native WITH RECURSIVE CTE. We didn't choose DynamoDB (adjacency fights the key-value model) and Aurora DSQL (narrower recursive-CTE surface) for exactly this reason. Auth is Vercel OIDC → AWS IAM federation via the official AWS connector: the deployment assumes a scoped IAM role and mints a short-lived RDS auth token at runtime — no password, no DATABASE_URL, no static AWS keys in the repo. The same role federates console access, so even human inspection of the database happens through the OIDC identity rather than root credentials.
The cycle guard: the recursive CTE carries an explicit path uuid[] accumulator and an is_cycle flag. A node already in its own path is flagged, the recursive arm stops expanding that branch (WHERE NOT c.is_cycle), and a maxDepth bound backs it up. The cycle becomes a 'surfaced product feature'. Its a
re-platforming risk ticket — not a hidden safeguard.
AI layer: Anthropic SDK. Claude Sonnet runs the analysis; Claude Haiku runs a cheap triage gate. Every analytical call runs at 'temperature 0'. Critically, we 'never trust the model's own summary' — the model returns structured details, and the summary is 'derived in code' and reconciled back into the details. The model generates; the application stays the source of truth.
Challenges we ran into
Termination on cyclic input: Proving the traversal always halts on a mutually-recursive estate took an automated test that seeds an A↔B cycle and asserts a finite, cycle-flagged result. If the guard regresses, the test hangs until timeout — a loud failure by design.
Passwordless DB auth on serverless: Aurora Serverless v2 scales to zero, so connections churn. IAM tokens are valid ~15 min; we cache the signed token with a safety margin so we don't re-sign on every cold pool connection.
Keeping the data layer honest: We constrained the entire schema to core PG16 — no Aurora-only extensions — so persistence stays a swappable concern rather than a lock-in.
What we learned
The hard part of legacy modernization isn't generating new code — it's building a trustworthy 'model' of the old system first. Treating the LLM as a structured extractor whose output is reconciled in code, rather than an oracle you trust blindly, is what makes the result safe to act on.
What's next
Diffable "what-if" sandboxes for testing a modernization before committing it, and automated migration-ticket generation across a whole estate.
Built With
- amazon-aurora
- anthropic
- claude
- dagre
- drizzle-orm
- iam
- next.js
- pnpm
- postgresql
- react
- react-flow
- testcontainers
- typescript
- vercel
- vitest
Log in or sign up for Devpost to join the conversation.