Contract & Architecture Evolution Manager for NestJS
Automated API diffing, breaking-change detection, and living documentation β
built for teams that move fast without breaking things.
- Why ArchGuard?
- Features
- Installation
- NestJS Setup
- Quick Start
- Configuration
- CLI Commands
- Diff Report Example
- CI/CD Integration
- Programmatic Usage
- Roadmap
- Contributing
- License
| Problem | Without ArchGuard | With ArchGuard |
|---|---|---|
| API contract changes | Discovered by broken Frontend | Caught instantly, before merge |
| Documentation drift | Swagger is always outdated | Auto-generated from live spec |
| Change history | "Who changed this route?" π€· | Git-tracked diff reports forever |
| Breaking changes in PR | Found in code review (maybe) | Blocked at CI, flagged automatically |
- π Automatic API Snapshotting β Captures your OpenAPI/Swagger spec at any point in time
- π΄ Breaking-Change Detection β Flags removed endpoints, deleted required fields, changed parameter types
- π‘ Non-Breaking Change Tracking β Tracks added endpoints, optional parameters, response expansions
- π Markdown Diff Reports β Beautiful, readable reports committed directly into your git history
- π Living Architecture Index β Auto-maintained
INDEX.mdwith every diff ever generated - π€ NestJS-First β Designed for the NestJS +
@nestjs/swaggerecosystem; works with any OpenAPI 3.x spec - π€ GitHub Actions Integration β Posts diff reports as PR comments, blocks merges on breaking changes
- π Git Auto-Commit β Optionally auto-commits snapshots and reports so your architecture history is always versioned
- π¦ Library Mode β Use ArchGuard programmatically in your own scripts or tooling
npm install --save-dev archguard-cliThen add scripts to your package.json:
{
"scripts": {
"arch:init": "archguard init",
"arch:snapshot": "archguard snapshot",
"arch:diff": "archguard diff",
"arch:history": "archguard history"
}
}npm install -g archguard-clinpx archguard-cli init
npx archguard-cli snapshot
npx archguard-cli diffArchGuard reads your live OpenAPI spec. Make sure Swagger is enabled in your NestJS app:
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
// β This exposes the JSON spec at: http://localhost:3000/api-json
await app.listen(3000);
}
bootstrap();ArchGuard fetches
http://localhost:3000/api-jsonby default.
You can override this inarchguard.config.jsonor via--url.
# 1. Initialize ArchGuard in your NestJS project
npx archguard-cli init
# 2. Start your NestJS app
npm run start:dev
# 3. Capture the current API as a baseline snapshot
npx archguard-cli snapshot
# 4. Make changes to your API (add a route, change a DTO, remove a param...)
# 5. Generate a diff report
npx archguard-cli diffExpected output for archguard diff:
π‘ ArchGuard Diff
β Current snapshot captured
β Analysis complete β 3 change(s) detected
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Changes: 3 | π΄ Breaking: 1
β Added: 1 endpoints | β Removed: 1 | π Modified: 1
π Schemas: +0 ~1 -0
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Report saved: ./docs/architecture/history/diff-2024-01-15T10-30-00-to-2024-01-15T14-45-00.md
β Diff completed! Check the report for details.
The generated report appears at ./docs/architecture/history/diff-latest.md β ready to commit and share with your Frontend team.
ArchGuard is configured via archguard.config.json in your project root (created automatically by archguard init).
{
"projectName": "payments-api",
"historyPath": "./docs/architecture/history",
"snapshotPath": "./.archguard",
"swaggerUrl": "http://localhost:3000/api-json",
"notify": {
"breakingChangesOnly": false
},
"git": {
"autoCommit": true,
"commitMessage": "chore(docs): update architecture history [skip ci]"
}
}| Option | Type | Default | Description |
|---|---|---|---|
projectName |
string |
folder name | Display name for your project |
historyPath |
string |
"./docs/architecture/history" |
Where diff reports are stored |
snapshotPath |
string |
"./.archguard" |
Where snapshots are stored |
swaggerUrl |
string |
"http://localhost:3000/api-json" |
URL to fetch the OpenAPI JSON spec |
notify.breakingChangesOnly |
boolean |
false |
Only flag breaking changes |
git.autoCommit |
boolean |
false |
Auto-commit snapshots and reports |
git.commitMessage |
string |
"chore(docs): ..." |
Commit message template |
| Command | Description | Options |
|---|---|---|
archguard init |
Initialize ArchGuard in the current directory | --force overwrite existing config |
archguard snapshot |
Capture the current OpenAPI spec | --url <url> override Swagger URL |
archguard diff |
Compare latest snapshot with current spec | --url <url>, --no-commit |
archguard history |
List stored snapshots and diff reports | --snapshots, --reports |
Creates:
archguard.config.jsonβ project configuration.archguard/β snapshot storage (add to.gitignoreif desired)docs/architecture/history/β diff report history (commit this!)- Appends ArchGuard entries to
.gitignore
archguard snapshot [--url http://localhost:3000/api-json]Fetches your OpenAPI spec and saves a timestamped JSON snapshot. Always writes snapshot-latest.json as the baseline for the next diff.
archguard diff [--url <url>] [--no-commit]- Loads
snapshot-latest.jsonas baseline - Fetches the current spec from your running app
- Runs the diff engine (endpoints + schemas + parameters + responses)
- Classifies each change as breaking, non-breaking, or informational
- Generates a Markdown report with Before/After details
- Updates
INDEX.mdand optionally auto-commits to git
archguard history [--snapshots] [--reports]Lists all snapshots and diff reports with timestamps.
Generated reports look like this:
# π‘ ArchGuard Diff Report
**Project:** payments-api
**From:** `snapshot-2024-01-14T10-00-00.json`
**To:** `snapshot-2024-01-15T14-30-00.json`
## π Summary
| Metric | Count |
|--------|-------|
| π΄ Breaking Changes | **2** |
| Total Changes | 5 |
| β Added Endpoints | 1 |
| β Removed Endpoints | 1 |
| π Modified Endpoints | 0 |
| Modified Schemas | 2 |
> β οΈ **WARNING:** 2 breaking change(s) require immediate Frontend attention.
## π Endpoint Changes
### β π΄ `DELETE /v1/users/{id}`
**Severity:** BREAKING
**Change:** [Users] Endpoint removed: Delete user
**Frontend Impact:** β οΈ Remove all calls to this endpoint from your codebase.
---
### β π’ `POST /v2/users/{id}/deactivate`
**Severity:** NON-BREAKING
**Change:** [Users] Endpoint added: Deactivate user
**Frontend Impact:** New endpoint available β implement integration if needed.Copy .github/workflows/archguard.yml to your NestJS repository:
name: π‘ ArchGuard API Contract Check
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
api-contract-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Start NestJS app
run: |
npm run start:prod &
timeout 60 bash -c 'until curl -sf http://localhost:3000/api-json; do sleep 2; done'
- name: Restore snapshot cache
uses: actions/cache@v4
with:
path: .archguard/
key: archguard-snapshot-${{ github.base_ref || github.ref_name }}
- name: Run ArchGuard diff
if: github.event_name == 'pull_request'
run: npx archguard-cli diff --no-commit
- name: Comment PR with diff
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const file = 'docs/architecture/history/diff-latest.md';
if (!fs.existsSync(file)) return;
const body = fs.readFileSync(file, 'utf-8').slice(0, 65000);
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## π‘ ArchGuard API Diff\n\n${body}`
});
- name: Block merge on breaking changes
if: github.event_name == 'pull_request'
run: |
if grep -q "Breaking Changes | \*\*[1-9]" docs/architecture/history/diff-latest.md 2>/dev/null; then
echo "π΄ Breaking API changes detected! Fix before merging."
exit 1
fi
- name: Save snapshot on main push
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npx archguard-cli snapshotUse ArchGuard as a library in your own scripts:
import {
captureSnapshot,
loadLatestSnapshot,
saveSnapshot,
generateDiff,
generateMarkdownReport,
saveReport,
loadConfig,
} from 'archguard-cli';
const config = loadConfig(); // reads archguard.config.json
// Capture current state
const current = await captureSnapshot(config);
// Load previous state
const previous = loadLatestSnapshot(config);
if (previous) {
// Generate diff
const report = generateDiff(previous, current);
console.log(`Breaking changes: ${report.summary.breakingChanges}`);
// Generate and save Markdown report
const markdown = generateMarkdownReport(report, config);
saveReport(markdown, report, config);
}
// Save current as new baseline
saveSnapshot(current, config);| Phase | Feature | Status |
|---|---|---|
| Phase 1 | Core CLI β init, snapshot, diff, history | β Done |
| Phase 2 | GitHub Actions CI/CD + PR comments | β Done |
| Phase 3 | 47 unit tests + Jest coverage | β Done |
| Phase 4 | Static extraction from NestJS decorators (no running server) | π¨ In Progress |
| Phase 5 | Frontend SDK type generation from diff | π Planned |
| Phase 6 | Web dashboard β visual architecture timeline | π Planned |
Contributions are welcome!
# 1. Fork and clone
git clone https://github.com/YvesDeSa/ArchGuard.git
cd ArchGuard
# 2. Install dependencies
npm install
# 3. Run tests
npm test
# 4. Develop with live TypeScript (no build step)
npm run dev -- snapshot --url http://localhost:3000/api-json
# 5. Build
npm run buildsrc/
βββ bin/
β βββ archguard.ts # CLI entry point (Commander.js)
βββ commands/
β βββ init.ts # archguard init
β βββ snapshot.ts # archguard snapshot
β βββ diff.ts # archguard diff
β βββ history.ts # archguard history
βββ core/
β βββ snapshot.ts # Snapshot capture & persistence
β βββ differ.ts # OpenAPI diff engine (breaking change detection)
β βββ reporter.ts # Markdown report generator
β βββ git-integration.ts # simple-git auto-commit
βββ utils/
β βββ config.ts # Config loader & path resolution
β βββ logger.ts # Chalk-powered logger
βββ types/
β βββ index.ts # All TypeScript interfaces
βββ __tests__/
β βββ differ.test.ts # 35 diff engine tests
β βββ snapshot.test.ts # Snapshot I/O tests
β βββ reporter.test.ts # Report generation tests
βββ index.ts # Public library API
MIT Β© Yves De SΓ‘