Development Guidelines¶
Rules for contributing to this project. All contributors (including AI assistants) must follow these guidelines.
Git Workflow¶
- Fresh branch from main - Always create a new branch from
mainbefore starting work - Never commit to main - All changes must go through Pull Requests
- Validate locally - Run
npm run validate(build + tests) before committing - PR-only merges - Keep local development files local, do not commit artifacts to git
Security & Privacy¶
- Security first - Every task must consider security and privacy implications
- Never commit credentials - No tokens, passwords, or API keys in code or config committed to git
- Validate external input - Sanitize data from banks, APIs, and user config
- Minimize dependencies - Prefer native APIs (e.g.,
fetch()) over third-party packages to reduce attack surface
Quality Standards¶
- Evaluate every change - Each modification must be checked, measured, and have clear metrics
- Explain improvements - Document how the change improves the project
- Justify the change - Explain why we should do it
- Document risks - Explain why not (tradeoffs, risks, downsides)
- Clean code - Follow clean code principles at all times
- SOLID principles - Follow Open/Closed principle and other SOLID principles
- 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
- No
anytypes - CI enforces zero: anyin source (ratchet = 0) - OCP maps over if/else chains - Use lookup maps for extensible dispatch patterns
- ESLint enforced -
npm run lintmust pass: max-lines (200), max-lines-per-function (20), with per-folder overrides ineslint.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 inconfig/. Adding one at root failslint:config-structureinvalidate:all. Onlyeslint.config.mjs,tsconfig.json,package.json,.gitignore,.dockerignore, and.husky/stay at root (tool constraints).
Verification Before PR¶
- Build locally -
npm run buildmust pass with zero errors - Run lint -
npm run lintmust pass with zero errors - Run tests -
npm testmust pass all tests - 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)
- Build Docker image -
docker build -t israeli-bank-importer:test . - Run E2E tests first -
npm run test:e2ewith mock scraper, preceded by Docker ×2 run to populate budget data - Then run with real config - Docker run with
config.jsonto verify with real bank data (optional, after E2E passes)
Documentation¶
- Always update documentation - Every code change must include relevant doc updates
- Update .md files before work - Plan and document in task files before implementation begins
- CHANGELOG.md is auto-generated - release-please updates it from conventional commits. Do NOT edit manually.
- Remove unused files - Keep the repository clean, no dead or orphaned files
Development Process¶
- 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¶
- You create a PR with a conventional commit title (e.g.,
feat: Add health check) - PR passes CI (build, tests, Trivy container scan, markdownlint, lychee, CodeQL) → you squash & merge
- release-please runs automatically and creates/updates a Release PR
- The Release PR bumps
package.jsonversion and updatesCHANGELOG.md - Multiple code PRs accumulate in the same Release PR
- When you're ready to ship → merge the Release PR
- release-please creates a git tag (e.g.,
v1.9.0) and a GitHub Release with notes - The tag push triggers the Docker Build & Publish workflow
- Builds multi-platform images (linux/amd64, linux/arm64)
- Pushes to Docker Hub
- Generates SBOM (Software Bill of Materials)
- 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 sectionchore: ...→ patch bump, hidden from CHANGELOG
Task Workflow¶
When working on tasks from the tasks/ folder:
- Read the task
.mdfile thoroughly - Update task status to
IN PROGRESSintasks/README.md - Create a fresh branch:
git checkout -b task-XX-description - Implement following the steps documented in the task file
- Run
npm run validate(build + tests) - Build Docker image and run E2E tests first, then optionally with real config
- Create a Pull Request with a conventional commit title (e.g.,
feat: Add health check endpoint) - After merge, update task status to
DONEintasks/README.md - release-please will update CHANGELOG.md and version automatically
Last Updated: 2026-02-20