Central Data Manager
Inspiration
Every DevOps team I know lives with the same frustration: four browser tabs open at once — GitHub for pipelines, Jira for the sprint board, Azure DevOps for work items, GitLab for another project. Releasing a feature means manually checking each one, copy-pasting statuses into Slack, and hoping nobody missed something.
The problem compounds in microservice architectures. A shared library update — a breaking change in an internal SDK, a new API contract, a security patch — doesn't touch one repository. It cascades. My own release process for a platform with multiple microservices looks like this: deploy the common library first, then deploy five microservices in parallel, then — only after all five succeed — apply the environment configs for each cluster. That's a DAG with a synchronisation barrier: parallel work that has to converge before the next phase starts.
Before CDM, that meant nine browser tabs, manual sequencing, and hoping nobody triggered the config step before all five microservices were healthy. One mistake in the order meant a broken environment and a rollback hunt.
I wanted a tool where you could draw that graph, hit Run, and let the system handle the parallelism and the barriers automatically. The constraint that shaped everything: provider tokens must never be exposed — not in the browser, not in logs, not in transit. That became the north star. The hackathon pushed it further: pair the frontend with a proper serverless backend on AWS so workspace data survives a browser clear, syncs across devices, and can be shared safely with teammates — with the security model to match.
What it does
Central Data Manager is a DevOps dashboard that aggregates your entire delivery pipeline into one place, deployed as a web app on Vercel. Because workspace data lives in AWS, you can open CDM on any device or browser and pick up exactly where you left off.
- CI/CD Pipelines — browse, trigger, re-run and cancel GitHub Actions and GitLab CI jobs across all your repositories, with per-workflow health metrics (success rate, average duration, trend sparkline)
- Chain Builder — define ordered sequences of pipelines across multiple repositories and fire them with one click. A shared library update that cascades through three repos becomes a single saved chain: CDM triggers each pipeline in order, waits for success, then moves to the next — no manual tab-switching, no sequencing errors
- Chain Orchestrator — wire chains into a visual drag-and-drop DAG with real parallelism and synchronisation barriers. Independent branches run concurrently; downstream nodes only start when every upstream node has succeeded. A real example: deploy a shared library first → fan out to N microservices in parallel → fan back in to apply environment configs only after all of them are healthy. No manual waiting, no sequencing mistakes
- Boards — Kanban view with drag-and-drop state transitions for Azure DevOps and Jira, with sprint filters, configurable columns, and a full work-item side panel
- Blockers Map — visual dependency graph showing which items are blocking others, with transitive impact scores and a top-blocker ranking
- Pull Requests — unified PR/MR list with live review status (Approved / Changes Requested / Awaiting), diff viewer, and one-click approve/merge
- Releases — track which tag is deployed per environment, compare any two refs, and generate a Markdown changelog
- Integrations — poll any HTTP endpoint, map its JSON response to a status, and surface it as a node in the Orchestrator
- GitHub App support — register GitHub App installations so the proxy uses short-lived, installation-scoped tokens instead of long-lived PATs; finer-grained access and smaller blast radius per credential
- Team Workspaces — create a team, invite colleagues by email, assign roles (admin / operator / viewer), and share chains, graphs, and integrations — each team's data is isolated in its own DynamoDB partition
- SSO via Azure AD — teams already on Microsoft Entra ID can authenticate through the Cognito hosted UI without creating a separate account; the OAuth exchange happens server-side
- RBAC — Cognito groups enforce access per role in every Lambda: viewers read, operators trigger, admins manage tokens and team settings
- Cloud Backup — workspace data syncs to AWS and restores on any device or browser; provider tokens are stored server-side, encrypted at rest, and never sent back to the browser
- Audit Log — persistent in-app audit trail with webhook forwarding to any HTTP endpoint (Slack, n8n, SIEM)
How we built it
The frontend is Angular 22 with standalone components and Angular Signals for all reactive state — no NgModules, no RxJS state management, just fine-grained signals and computed values. Three HTTP interceptors handle JWT attachment, transparent session refresh, and exponential-backoff retry on 429/503. Deployed on Vercel.
The backend is a fully serverless AWS stack deployed with the AWS CDK:
Amazon Cognito handles authentication, issues short-lived JWTs, and manages both RBAC groups (admin, operator, viewer) and team groups (team-{uuid}). The browser receives a JWT — never a provider token. The same Cognito primitive handles authentication, RBAC, and team isolation without any extra database tables. SSO via Azure AD is supported through Cognito OIDC federation.
DynamoDB stores all workspace data in a single table, partitioned by user and team. Chains, graphs, releases, settings, integrations, and encrypted tokens all live in the same table — no joins, no migrations. Shared team data lives under TEAM#{group-uuid} partitions, verified server-side against the JWT on every request.
AWS Lambda proxies all provider API calls. The Lambda fetches the encrypted PAT server-side, decrypts it in memory, injects the provider auth header, and forwards the call. The raw token never travels back to the browser and is never cached between requests — each call decrypts fresh.
Token encryption — PATs are encrypted with AES-256-GCM before being written to DynamoDB. The encryption key is stored in AWS SSM Parameter Store as a SecureString, protected by KMS. Teams that need automatic key rotation can switch to AWS Secrets Manager via a configuration flag.
GitHub App support — for organisation-owned repositories the proxy prefers a short-lived installation access token (minted per-request via the GitHub App private key in SSM) over the user's PAT. Smaller blast radius, no scope creep.
RBAC is enforced in every Lambda from the JWT claims — no valid group, no access. The frontend applies the same role signals for UI gating, but the Lambda is the authoritative enforcement point.
API Gateway HTTP v2 routes requests to the appropriate Lambda with JWT authorisation built in.
Challenges we ran into
Secure server-side token storage without per-secret cost. Storing one secret per provider token in a dedicated secrets service would be expensive at scale. The solution was a shared encryption key in a managed parameter store, combined with application-level authenticated encryption (AES-256-GCM with a random IV and authentication tag per write). Defence in depth: the stored data is useless without a separate key that requires its own IAM access to retrieve.
Removing the Lambda token cache. An early version cached the decrypted token in the Lambda execution context to reduce SSM/DynamoDB read latency. During a security review we realised that a warm Lambda instance could serve requests from multiple users — meaning one user's decrypted token could linger in memory while another user's request was handled. The cache was removed entirely. Each request decrypts fresh, and the marginal latency is within acceptable bounds.
Preventing SSRF through user-supplied URLs. GitLab and Jira let users supply a custom base URL. Without validation, a crafted URL could redirect Lambda traffic to the AWS instance metadata service or internal VPC endpoints. A strict URL guard (https-only, no IP literals, no localhost, no internal-zone suffixes) is applied before any outbound request is made.
Team isolation. Making shared workspace data visible only to the right team — and nobody else — required careful design at the data layer. The DynamoDB partition key for shared data is derived from the JWT claims server-side; a user cannot supply their own team group identity. The frontend sends an X-CDM-Active-Team header; the Lambda validates it against the groups in the JWT before accepting it.
SVG canvas interactions on the Orchestrator. A mouse event bubbling to the canvas cleared the selection before a delete button could respond, making the button disappear before it could be clicked. Stopping propagation on the right events on interactive elements fixed it — a small change that took a while to diagnose.
Identifying a freshly dispatched workflow run. When a workflow is triggered via workflow_dispatch, GitHub does not return the new run ID in the trigger response. Filtering by event=workflow_dispatch and created>=triggerTimestamp gives a candidate set; the executor then latches onto the run ID once found and tracks it exclusively by ID — never re-matching by timestamp to avoid false matches from concurrent dispatches.
Auto-paginating repositories. GitHub and GitLab cap responses at 100 items per page. Users with large organisations saw incomplete lists. The solution chains requests transparently until the full list is loaded — invisible to the user.
Accomplishments that we're proud of
Getting four completely different provider APIs (GitHub, GitLab, Azure DevOps, Jira) to feel like a single coherent experience — same status vocabulary, same card patterns, same interactions — without a backend normalisation layer.
The security model is cleaner than expected. The Lambda proxy pattern means provider credentials exist in exactly one place (DynamoDB, AES-256-GCM encrypted), are decrypted in exactly one place (Lambda, in memory, per-request), and are used in exactly one place (the outbound provider request). There is no code path that returns a plaintext PAT to the browser.
The team collaboration model scales without a dedicated tenancy database. A Cognito group is the only coordination point — create a group, add users, and the shared workspace partition is automatically available. No migration scripts, no schema changes, no extra services.
The Chain Orchestrator's DAG executor resolves Promise.all per topological layer, so independent chains genuinely run in parallel. Watching three pipelines start simultaneously from a single graph run is satisfying every time.
Server-side scheduled chains. Any chain can be put on a cron or rate schedule via EventBridge Scheduler — the cdm-chain-exec Lambda fires it even with the browser closed. Runs land in the normal chain history and audit log, so nothing is lost.
Webhook notifications. Chain and orchestrator completion events, audit log entries, and pipeline failures can be forwarded to any HTTP endpoint — Slack incoming webhooks, Teams connectors, n8n, or a SIEM. One URL in Settings is all it takes.
Self-hosted GitLab and GitHub Enterprise. The base URL is a first-class field in the token model, validated by the SSRF guard before any outbound request. Teams on private GitLab instances or GitHub Enterprise get the same experience as cloud users.
The multi-device story goes beyond data sync. The entire interface — including the Kanban boards, sprint widget, and pipeline views — was designed to work on both desktop and mobile. You can move a work item between sprint columns, check a pipeline run, or trigger a chain from your phone just as naturally as from your laptop. CDM was built to be where you are, not just where your desk is.
What we learned
DynamoDB's single-table design takes discipline. Collapsing chains, graphs, releases, settings, tokens, and integrations into one table with composite keys cut read latency and simplified Lambda code considerably — but requires thinking in access patterns from the start.
Angular Signals eliminate an entire class of change-detection bugs. Migrating to OnPush was straightforward once every mutable piece of state was a signal — the compiler tells you exactly where you forgot.
The line between auth and authz blurs quickly in a multi-tenant app. Cognito handles identity; DynamoDB key design handles tenancy; Lambda enforces both on every request. Getting all three layers to agree — and to fail closed — is where the real architectural work was.
Security architecture is multiplicative, not additive. Moving from browser-stored PATs to server-side encrypted storage didn't just improve security — it changed the entire threat model. A browser XSS attack that used to mean full token exfiltration now yields only a short-lived JWT. The blast radius of a compromise went from "all providers, indefinitely" to "one session, until expiry."
Building directly against four provider APIs without a normalisation layer forces you to understand each API's quirks deeply. GitHub's review decision model, GitLab's pipeline retry semantics, Azure DevOps's work-item state machine — they're all different, and making them feel the same in the UI is where most of the complexity lives.
What's next for Central Data Manager
- Server-side audit log — the current audit trail is per-user in DynamoDB; a unified team audit log with search and export is on the roadmap
- Board performance at scale — virtual scrolling for large sprints, lazy-loading of work item details, and optimistic updates so drag-and-drop feels instant even over slow connections
- Backend unit tests — the frontend has Vitest coverage; the Lambda functions need equivalent test harnesses
Built With
- amazon-dynamodb
- aws-api-gateway
- aws-cdk
- aws-lambda
- azure-devops-rest-api
- docker
- github-actions-api
- gitlab-ci-api
- jira-rest-api
- nginx
- scss
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.