Skip to content

YvesDeSa/ArchGuard

Repository files navigation

πŸ›‘ ArchGuard

Contract & Architecture Evolution Manager for NestJS

Automated API diffing, breaking-change detection, and living documentation β€”
built for teams that move fast without breaking things.

npm version npm downloads license node TypeScript tests


πŸ“š Table of Contents

  1. Why ArchGuard?
  2. Features
  3. Installation
  4. NestJS Setup
  5. Quick Start
  6. Configuration
  7. CLI Commands
  8. Diff Report Example
  9. CI/CD Integration
  10. Programmatic Usage
  11. Roadmap
  12. Contributing
  13. License

πŸ’‘ Why ArchGuard?

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

✨ Features

  • πŸ” 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.md with every diff ever generated
  • 🀝 NestJS-First β€” Designed for the NestJS + @nestjs/swagger ecosystem; 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

πŸ“¦ Installation

As a dev dependency in your NestJS project (recommended)

npm install --save-dev archguard-cli

Then add scripts to your package.json:

{
  "scripts": {
    "arch:init":     "archguard init",
    "arch:snapshot": "archguard snapshot",
    "arch:diff":     "archguard diff",
    "arch:history":  "archguard history"
  }
}

Global install (use anywhere)

npm install -g archguard-cli

Without installing (npx)

npx archguard-cli init
npx archguard-cli snapshot
npx archguard-cli diff

πŸ— NestJS Setup

ArchGuard 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-json by default.
You can override this in archguard.config.json or via --url.


πŸš€ Quick Start

# 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 diff

Expected 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.


βš™οΈ Configuration

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

πŸ’» CLI Commands

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

archguard init

Creates:

  • archguard.config.json β€” project configuration
  • .archguard/ β€” snapshot storage (add to .gitignore if desired)
  • docs/architecture/history/ β€” diff report history (commit this!)
  • Appends ArchGuard entries to .gitignore

archguard snapshot

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

archguard diff [--url <url>] [--no-commit]
  1. Loads snapshot-latest.json as baseline
  2. Fetches the current spec from your running app
  3. Runs the diff engine (endpoints + schemas + parameters + responses)
  4. Classifies each change as breaking, non-breaking, or informational
  5. Generates a Markdown report with Before/After details
  6. Updates INDEX.md and optionally auto-commits to git

archguard history

archguard history [--snapshots] [--reports]

Lists all snapshots and diff reports with timestamps.


πŸ“‹ Diff Report Example

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.

πŸ€– CI/CD Integration

GitHub Actions

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 snapshot

πŸ”§ Programmatic Usage

Use 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);

πŸ—Ί Roadmap

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

🀝 Contributing

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 build

Project Structure

src/
β”œβ”€β”€ 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

πŸ“„ License

MIT Β© Yves De SΓ‘


Made with ❀️ for the NestJS community

NPM Β· Issues Β· Changelog

If ArchGuard saved you from a breaking change, give it a ⭐

About

πŸ›‘οΈ Automated API diffing and breaking-change detection for NestJS and Swagger.

Topics

Resources

Stars

Watchers

Forks

Contributors