Files
kilo-cv/docs/plans/2026-02-20-devops-features-design.md
2026-02-20 16:46:34 +01:00

11 KiB

DevOps Features Design

Date: 2026-02-20 Status: Approved Author: Claude (AI Assistant)

Overview

Implement four DevOps features for the CV application:

  1. Swagger/OpenAPI Documentation - Interactive API docs at /api/docs
  2. Database Migrations - Knex.js-based migration system with auto-migration
  3. Quality Gates - Code coverage, bundle size, npm audit, Lighthouse CI
  4. Secret Scanning - Gitleaks pre-commit hook

1. Swagger/OpenAPI Documentation

Architecture

Route Files (JSDoc comments)
         │
         ▼
    swagger-jsdoc
    (generates spec at runtime)
         │
         ▼
    swagger-ui-express
         │
         ▼
    GET /api/docs → Interactive Swagger UI
    GET /api/docs.json → Raw OpenAPI spec

Endpoints

Method Path Description
GET /api/docs Swagger UI interface
GET /api/docs.json Raw OpenAPI JSON spec

Implementation

Dependencies:

  • swagger-jsdoc - Generate OpenAPI spec from JSDoc
  • swagger-ui-express - Serve Swagger UI

JSDoc format in route files:

/**
 * @openapi
 * /api/cv:
 *   get:
 *     summary: Get CV data
 *     tags: [CV]
 *     responses:
 *       200:
 *         description: CV data
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/CVData'
 *       404:
 *         description: CV data not found
 */
router.get('/', (req, res) => { ... });

/**
 * @openapi
 * /api/cv:
 *   put:
 *     summary: Update CV data
 *     tags: [CV]
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/CVData'
 *     responses:
 *       200:
 *         description: CV data updated
 *       401:
 *         description: Unauthorized
 */
router.put('/', authMiddleware, (req, res) => { ... });

Swagger setup:

// backend/routes/docs.js
import swaggerJsdoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';

const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'CV API',
      version: '1.0.0',
      description: 'API for CV/Resume management',
    },
    servers: [
      { url: '/api', description: 'API server' }
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
        },
      },
      schemas: {
        CVData: { /* schema definition */ },
      },
    },
  },
  apis: ['./routes/*.js'],
};

const specs = swaggerJsdoc(options);

router.use('/docs', swaggerUi.serve, swaggerUi.setup(specs));
router.get('/docs.json', (req, res) => res.json(specs));

2. Database Migrations (Knex.js)

Architecture

backend/
├── knexfile.js           # Knex configuration
├── migrations/
│   ├── 20260220000001_initial_schema.js
│   └── 20260220000002_add_auth_tables.js
├── seeds/
│   └── initial_cv_data.js
└── db/
    ├── connection.js     # Knex instance
    └── init.js           # Auto-migration on startup

Knex Configuration

// knexfile.js
export default {
  client: 'better-sqlite3',
  connection: {
    filename: process.env.DB_PATH || './data/cv.db'
  },
  migrations: {
    directory: './migrations',
    tableName: 'knex_migrations'
  },
  seeds: {
    directory: './seeds'
  },
  useNullAsDefault: true
};

Migration File Format

// migrations/20260220000001_initial_schema.js
export async function up(knex) {
  await knex.schema.createTable('cv_data', (table) => {
    table.integer('id').primary().checkTo('=', 1);
    table.text('data').notNullable();
    table.datetime('updated_at').defaultTo(knex.fn.now());
  });
}

export async function down(knex) {
  await knex.schema.dropTableIfExists('cv_data');
}

Auto-Migration on Startup

// db/init.js
import knex from 'knex';
import config from '../knexfile.js';

let db = null;

export async function getDB() {
  if (!db) {
    db = knex(config);
    await db.migrate.latest();
  }
  return db;
}

export async function closeDB() {
  if (db) {
    await db.destroy();
    db = null;
  }
}

CLI Commands

# Create new migration
npx knex migrate:make migration_name --knexfile knexfile.js

# Run migrations manually
npx knex migrate:latest --knexfile knexfile.js

# Rollback last migration
npx knex migrate:rollback --knexfile knexfile.js

# Run seeds
npx knex seed:run --knexfile knexfile.js

Dependencies

  • knex - SQL query builder and migrations

3. Quality Gates

Overview

Gate Tool Threshold Action
Code Coverage vitest + Codecov 80% minimum Fail CI
Bundle Size bundlesize 500KB max Fail CI
npm audit npm audit Moderate+ Fail CI
Lighthouse @lhci/cli Performance 90+ Fail CI

CI Workflow Integration

# .github/workflows/ci.yml additions

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
        
      # Code Coverage
      - name: Run tests with coverage
        run: npm run test:coverage
        
      - name: Upload to Codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true
          
      # Bundle Size
      - name: Build
        run: npm run build
        
      - name: Check bundle size
        run: npx bundlesize
        
      # npm audit
      - name: Security audit
        run: npm audit --audit-level=moderate
        
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Build
        run: npm run build
        
      - name: Run Lighthouse CI
        run: npm run test:lighthouse

Configuration Files

package.json:

{
  "scripts": {
    "test:coverage": "vitest run --coverage"
  },
  "bundlesize": [
    {
      "path": "./dist/assets/*.js",
      "maxSize": "500kb"
    },
    {
      "path": "./dist/assets/*.css",
      "maxSize": "100kb"
    }
  ]
}

vitest.config.js:

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov', 'html'],
      exclude: ['node_modules/', 'tests/'],
      lines: 80,
      functions: 80,
      branches: 80,
      statements: 80
    }
  }
});

.lighthouserc.json:

{
  "ci": {
    "collect": {
      "url": ["http://localhost:4173/"],
      "numberOfRuns": 3
    },
    "assert": {
      "assertions": {
        "categories:performance": ["error", { "minScore": 0.9 }],
        "categories:accessibility": ["warn", { "minScore": 0.9 }],
        "categories:best-practices": ["warn", { "minScore": 0.9 }]
      }
    },
    "upload": {
      "target": "temporary-public-storage"
    }
  }
}

Dependencies

  • @vitest/coverage-v8 - Coverage reporter
  • bundlesize - Bundle size checking

Secrets Required

Secret Description
CODECOV_TOKEN Codecov upload token

4. Secret Scanning (Gitleaks)

Architecture

Developer stages files
         │
         ▼
    git commit
         │
         ▼
    .husky/pre-commit
         │
         ├─► npm run lint
         │
         └─► gitleaks protect --staged
                │
                ▼
         Secrets found?
           │     │
          Yes    No
           │     │
           ▼     ▼
     Block commit  Allow commit

Pre-commit Hook

# .husky/pre-commit
npm run lint

# Gitleaks secret scanning
if command -v gitleaks &> /dev/null; then
  gitleaks protect --verbose --staged
  if [ $? -eq 1 ]; then
    echo ""
    echo "❌ Secrets detected in staged files!"
    echo "Please remove sensitive data before committing."
    echo ""
    exit 1
  fi
fi

Gitleaks Configuration

# .gitleaks.toml
title = "Gitleaks Configuration"

[extend]
useDefault = true

[[allowlists]]
description = "Allowlisted files"
paths = [
  'package-lock.json',
  'backend/package-lock.json',
  '.*\\.md$'
]

[[allowlists]]
description = "Allowlisted patterns"
regexes = [
  'VITE_API_URL.*localhost',
]

Developer Setup

Gitleaks must be installed on developer machines:

# macOS
brew install gitleaks

# Linux
# Download from https://github.com/gitleaks/gitleaks/releases
# Or use go install
go install github.com/gitleaks/gitleaks/v8@latest

# Windows
scoop install gitleaks
# Or
choco install gitleaks

Documentation

Add to README or CONTRIBUTING.md:

### Pre-commit Setup

This project uses Gitleaks for secret scanning. Install it before committing:

```bash
# macOS
brew install gitleaks

# Linux
curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.18.1/gitleaks_8.18.1_linux_x64.tar.gz | tar -xz
sudo mv gitleaks /usr/local/bin/

The pre-commit hook will automatically scan for secrets before each commit.


---

## Implementation Summary

### New Dependencies

**Backend:**
- `knex` - Database migrations and query builder
- `swagger-jsdoc` - OpenAPI spec generation
- `swagger-ui-express` - Swagger UI middleware

**Frontend:**
- `@vitest/coverage-v8` - Coverage reporting
- `bundlesize` - Bundle size checking

**Dev:**
- `gitleaks` (binary, not npm package)

### New Files

backend/ ├── knexfile.js ├── migrations/ │ └── 20260220000001_initial_schema.js ├── seeds/ │ └── initial_cv_data.js ├── routes/ │ └── docs.js └── db/ └── connection.js

.gitleaks.toml .lighthouserc.json


### Modified Files

package.json # Add scripts, bundlesize config vitest.config.js # Add coverage config .github/workflows/ci.yml # Add quality gates .husky/pre-commit # Add gitleaks backend/db/init.js # Use Knex instead of better-sqlite3 directly backend/routes/cv.js # Add JSDoc comments backend/routes/auth.js # Add JSDoc comments README.md # Add gitleaks setup instructions


---

## Post-Implementation Checklist

- [ ] Install dependencies
- [ ] Configure Knex and create initial migration
- [ ] Add Swagger UI route
- [ ] Add JSDoc comments to all API routes
- [ ] Configure Codecov (add CODECOV_TOKEN secret)
- [ ] Add bundlesize configuration
- [ ] Update CI workflow with quality gates
- [ ] Add gitleaks to pre-commit hook
- [ ] Update documentation