Skip to content

Development Guidelines

Rules for contributing to this project. All contributors (including AI assistants) must follow these guidelines.


Git Workflow

  1. Fresh branch from main - Always create a new branch from main before starting work
  2. Never commit to main - All changes must go through Pull Requests
  3. Validate locally - Run npm run validate (build + tests) before committing
  4. PR-only merges - Keep local development files local, do not commit artifacts to git

Security & Privacy

  1. Security first - Every task must consider security and privacy implications
  2. Never commit credentials - No tokens, passwords, or API keys in code or config committed to git
  3. Validate external input - Sanitize data from banks, APIs, and user config
  4. Minimize dependencies - Prefer native APIs (e.g., fetch()) over third-party packages to reduce attack surface

Quality Standards

  1. Evaluate every change - Each modification must be checked, measured, and have clear metrics
  2. Explain improvements - Document how the change improves the project
  3. Justify the change - Explain why we should do it
  4. Document risks - Explain why not (tradeoffs, risks, downsides)
  5. Clean code - Follow clean code principles at all times
  6. SOLID principles - Follow Open/Closed principle and other SOLID principles
  7. Aim for 10 lines per method - Extract longer methods into single-purpose functions. ESLint enforces 20 (blank and comment lines not counted), and 10 in some folders
  8. No any types - CI enforces zero : any in source (ratchet = 0)
  9. OCP maps over if/else chains - Use lookup maps for extensible dispatch patterns
  10. ESLint enforced - npm run lint must pass: max-lines (200), max-lines-per-function (20), with per-folder overrides in eslint.config.mjs (most of them tighter), max-params (3), max-len (100), no-unused, no-unsafe-function-type. Tests exempt from line limits. No warnings allowed (warn=error policy). 18a. Config file location - Tool config files (vitest, markdownlint, lychee, release-please) live in config/. Adding one at root fails lint:config-structure in validate:all. Only eslint.config.mjs, tsconfig.json, package.json, .gitignore, .dockerignore, and .husky/ stay at root (tool constraints).

Verification Before PR

  1. Build locally - npm run build must pass with zero errors
  2. Run lint - npm run lint must pass with zero errors
  3. Run tests - npm test must pass all tests
  4. Run validate:all - npm run validate:all — 6 gates must all pass:
    • type-check (TypeScript, zero errors)
    • test:unit (459 tests, 90%+ branch coverage)
    • E2E:mock (44 tests via mock scraper)
    • lint (ESLint: PascalCase, no-any, line limits)
    • lint:docs (markdownlint on README + GitHub templates)
    • lint:config-structure (no stray config files at root)
  5. Build Docker image - docker build -t israeli-bank-importer:test .
  6. Run E2E tests first - npm run test:e2e with mock scraper, preceded by Docker ×2 run to populate budget data
  7. Then run with real config - Docker run with config.json to verify with real bank data (optional, after E2E passes)

Documentation

  1. Always update documentation - Every code change must include relevant doc updates
  2. Update .md files before work - Plan and document in task files before implementation begins
  3. CHANGELOG.md is auto-generated - release-please updates it from conventional commits. Do NOT edit manually.
  4. Remove unused files - Keep the repository clean, no dead or orphaned files

Development Process

  1. Plan first, then implement - Create a plan, wait for review and approval before coding

Releases (release-please)

Releases are managed by release-please.

Release pipeline

┌─────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  Code PR    │────▶│  Release PR  │────▶│  Git Tag +   │────▶│ Docker Build │
│  (you)      │     │  (automatic) │     │  GitHub      │     │  + Publish   │
│             │     │              │     │  Release     │     │  (automatic) │
│ feat: ...   │     │ Bumps        │     │  (automatic) │     │              │
│ fix: ...    │     │ package.json │     │              │     │ amd64+arm64  │
│ refactor: . │     │ CHANGELOG.md │     │ v1.9.0 tag   │     │ Docker Hub   │
└─────────────┘     └──────────────┘     └──────────────┘     └──────────────┘
   Squash &            Accumulates          Created when         Triggered by
   merge to main       multiple PRs         you merge the        tag push
                       until you're         Release PR
                       ready to ship

Step by step

  1. You create a PR with a conventional commit title (e.g., feat: Add health check)
  2. PR passes CI (build, tests, Trivy container scan, markdownlint, lychee, CodeQL) → you squash & merge
  3. release-please runs automatically and creates/updates a Release PR
  4. The Release PR bumps package.json version and updates CHANGELOG.md
  5. Multiple code PRs accumulate in the same Release PR
  6. When you're ready to ship → merge the Release PR
  7. release-please creates a git tag (e.g., v1.9.0) and a GitHub Release with notes
  8. The tag push triggers the Docker Build & Publish workflow
  9. Builds multi-platform images (linux/amd64, linux/arm64)
  10. Pushes to Docker Hub
  11. Generates SBOM (Software Bill of Materials)
  12. Enriches the GitHub Release with Docker pull commands and stats

Commit message format

The PR title (used as squash commit message) determines the version bump:

  • feat: ... → minor version bump (1.8.x → 1.9.0), appears under "Added"
  • fix: ... → patch version bump (1.8.2 → 1.8.3), appears under "Fixed"
  • refactor: ... → patch bump, appears under "Refactored"
  • docs: ... / ci: ... / test: ... → patch bump, appears under respective section
  • chore: ... → patch bump, hidden from CHANGELOG

Task Workflow

When working on tasks from the tasks/ folder:

  1. Read the task .md file thoroughly
  2. Update task status to IN PROGRESS in tasks/README.md
  3. Create a fresh branch: git checkout -b task-XX-description
  4. Implement following the steps documented in the task file
  5. Run npm run validate (build + tests)
  6. Build Docker image and run E2E tests first, then optionally with real config
  7. Create a Pull Request with a conventional commit title (e.g., feat: Add health check endpoint)
  8. After merge, update task status to DONE in tasks/README.md
  9. release-please will update CHANGELOG.md and version automatically

Last Updated: 2026-02-20