# Contributing to Spendif.ai *Italian version: [CONTRIBUTING.md](CONTRIBUTING.md).* Thanks for your interest! These guidelines describe how to report issues, propose features, and contribute code. --- ## Table of contents 1. [Priority system](#priority-system) 2. [Reporting a bug](#reporting-a-bug) 3. [Proposing a feature](#proposing-a-feature) 4. [Contributing code](#contributing-code) 5. [Translating Spendif.ai](#translating-spendifai) 6. [Development environment setup](#development-environment-setup) 7. [Conventions](#conventions) --- ## Priority system Every issue carries a priority label. The system has 4 levels: | Label | Color | Meaning | When we use it | |-------|-------|---------|----------------| | ๐Ÿ”ด **P0 ยท now** | Red | Blocks the beta or is a quick UX fix | Critical bugs, regressions, pre-release quick wins | | ๐ŸŸก **P1 ยท v2.5** | Yellow | Completes the core workflow | Features that close existing usage loops | | ๐Ÿ”ต **P2 ยท v3.0** | Blue | Significant product expansion | New modules, integrations, deep improvements | | โšช **P3 ยท roadmap** | Gray | Long-term vision | Important ideas without a defined timeline | ### Practical rules - **P0** โ†’ open a PR within the current sprint; if you can't, flag it in the issue comments - **P1** โ†’ target release `v2.5`; milestone assigned when the issue is picked up - **P2** โ†’ target release `v3.0`; can be moved up if an external contribution lands - **P3** โ†’ no timeline; contributions welcome, but quick review is not guaranteed ### How to propose a priority change Open a comment on the issue with your reasoning. The maintainer re-evaluates and updates the label. --- ## Reporting a bug 1. Search the [open issues](https://github.com/spendifai/spendif-ai/issues) โ€” it may already exist 2. Open a new issue using the **Bug report** template 3. Include: - Spendif.ai version (or commit hash) - OS and Docker/Python version - Steps to reproduce - Expected vs actual behavior - Relevant logs (`docker compose logs spendifai`) --- ## Proposing a feature 1. Check the [backlog](https://github.com/spendifai/spendif-ai/issues) โ€” it may already exist as a P2/P3 issue 2. Open an issue using the **Feature request** template 3. Describe: - The problem it solves (not just the solution) - Who benefits (end user, developer, ops) - Estimated impact on privacy, performance, complexity --- ## Contributing code ### Standard flow ``` fork โ†’ branch โ†’ commit โ†’ PR โ†’ review โ†’ merge ``` 1. **Fork** the repository 2. Create a branch: `git checkout -b feat/feature-name` or `fix/bug-name` 3. Develop with tests โ€” see [Setup](#development-environment-setup) 4. Open a **Pull Request** against `develop` 5. Link the PR to the issue with `Closes #N` in the body ### The two long-lived branches `develop` is where work lands. `main` is what has been released: the website is served from it, the container image is published from it, and a release is a tag cut on it. So `main` moves once per release, by merging `develop`, and never by a direct push. A pull request therefore targets `develop`, not `main`, unless it repairs something already in the hands of users. ### What to expect from review - Feedback within ~3 business days for P0/P1 - Feedback within ~1 week for P2/P3 - The PR is merged only if CI is green (tests + lint + Docker smoke test) --- ## Translating Spendif.ai Translations are one of the most welcome contributions: all you need is a text editor and a few minutes. You don't need to be a developer. ### Current language status | Language | Streamlit UI | Landing page (HTML) | |----------|--------------|---------------------| | ๐Ÿ‡ฎ๐Ÿ‡น Italiano | โœ… master (human-verified) | โœ… master (human-verified) | | ๐Ÿ‡ฌ๐Ÿ‡ง English | โœ… LLM-translated, partially verified | โœ… LLM-translated, partially verified | | ๐Ÿ‡ฉ๐Ÿ‡ช / ๐Ÿ‡ซ๐Ÿ‡ท / ๐Ÿ‡ช๐Ÿ‡ธ / ๐Ÿ‡ต๐Ÿ‡น / ๐Ÿ‡ณ๐Ÿ‡ฑ / ๐Ÿ‡ฏ๐Ÿ‡ต / ๐Ÿ‡ต๐Ÿ‡ฑ | โŒ not available | โœ… LLM-translated, **not yet human-verified** | LLM-only translations are an imperfect baseline: they all need human eyes. If you're a native speaker or have skills in one of these languages, your contribution makes a difference. ### Translation architecture Spendif.ai has **two areas** that require separate translations: 1. **Streamlit UI** โ€” `sw_artifacts/ui/i18n/.json` โ€” a flat keyโ†’string file per language. Loaded at runtime by the app. The key schema follows the convention `area.element` and `area.element.desc` for descriptions (e.g. `nav.import` + `nav.import.desc`). 2. **Landing page** โ€” `sw_artifacts/index..html` โ€” a complete HTML file per language. **Schema in transition**: we're migrating these to a JSON system similar to `ui/i18n/` (tracked in `backlog.json` AI-14). Until that refactor lands, landing translations are done by editing the HTML directly โ€” see the [Landing page (transitional)](#landing-page-transitional) section below. ### Translating the Streamlit UI (recommended โ€” the easiest flow) #### Step 1 โ€” Pick a language Example: you want to add German (`de`). #### Step 2 โ€” Copy the master ```bash cp sw_artifacts/ui/i18n/en.json sw_artifacts/ui/i18n/de.json ``` Start from `en.json` as the master (it's the reference baseline). Never start from `it.json` unless you're Italian: you risk linguistic calques. #### Step 3 โ€” Edit the file Open `sw_artifacts/ui/i18n/de.json` with your editor of choice. The structure is simple: ```json { "_language_name": "Deutsch", "nav.import": "๐Ÿ“ฅ Importieren", "nav.import.desc": "CSV/XLSX-Dateien aus deinen Bankkonten importieren", "nav.history": "๐Ÿ“œ Importverlauf" } ``` Rules: - **Change `_language_name`** to the language name in the language itself (e.g. `Deutsch`, not `German`) - **Keep keys unchanged** โ€” they are identifiers, not text to translate - **Keep emoji and formatting unchanged** where present โ€” they are part of the design - **Keep `{var}` or `%(name)s` substitutions** โ€” they are placeholders for dynamic values - **`.desc` keys** are longer descriptions used as hints or tooltips โ€” don't skip them #### Step 4 โ€” Recommended editors for non-developers If you're not familiar with JSON, any of these makes life easier: - [**BabelEdit**](https://www.codeandweb.com/babeledit) โ€” free for open source projects. Side-by-side EN/target language UI, highlights missing keys, flags double spaces. - [**Tolgee Cloud**](https://tolgee.io/) โ€” side-by-side web interface with built-in AI suggestions. Free tier is sufficient. - [**VS Code**](https://code.visualstudio.com/) with the "JSON Tools" extension โ€” for those who just want a solid editor. - [**JSONedit**](https://tomeko.net/software/JSONedit/) โ€” Windows desktop, free, lightweight. #### Step 5 โ€” Validate and PR ```bash # Verify that the JSON is valid python -c "import json; json.load(open('sw_artifacts/ui/i18n/de.json'))" ``` Open a PR following the standard flow ([Contributing code](#contributing-code)). In the PR body include: - The language added or updated - How many keys you translated / verified - Any non-obvious terminology decisions (e.g. "I rendered `ledger` as `Hauptbuch` because...") ### Landing page (transitional) **Current workflow (transitional)**: edit `sw_artifacts//index.html` directly. Open the canonical English `sw_artifacts/index.html` alongside as a reference, change only visible text (NOT CSS, JS, or `href` URLs), save, PR. Practical tips: - Keep two editors or two tabs side by side: EN on the left, target language on the right - Search for `

`, `

`, `

`, `

`, ``, `<meta>` to find translatable strings - **Do NOT translate**: `<style>`, `<script>`, `href="..."`, shell snippets in `<code-body>` (curl/irm/bash), id tags (`id="install"`), tab labels (`๐ŸŽ macOS`), proper names (Spendify, Ollama, Streamlit, GitHub) - Update `<html lang="...">` at the top **Future workflow (post AI-14)**: we're working to bring landings onto a JSON system similar to `ui/i18n/`. Once it's ready, contributing a language will mean editing a single `i18n/landing/<lang>.json` file instead of an entire HTML. If you want to help unblock this refactor, see backlog item AI-14. ### Human review of existing LLM translations Even just rereading and correcting an existing translation is a valuable contribution. If you find errors, awkward-sounding phrases, or wrong technical terms, open a PR with the fixes. Note in the commit message: ``` i18n(de): fix awkward LLM phrasings in nav and analytics sections i18n(ja): correct technical term for "ledger" โ€” ๅ…ƒๅธณ โ†’ ๅ–ๅผ•ๅฑฅๆญด ``` --- ## Development environment setup ### Prerequisites | Tool | Minimum version | |------|-----------------| | Python | 3.13 | | uv | any | | Docker Desktop | any (for local smoke test) | ### Installation ```bash git clone https://github.com/spendifai/spendif-ai.git cd spendifai uv sync cp .env.example .env # Startup script (recommended) ./start.sh # UI only (default) ./start.sh api # REST API only ./start.sh all # UI + API # Or manually uv run streamlit run app.py ``` ### Running tests ```bash # Tests with coverage uv run pytest tests/ -v --cov=. --cov-report=term-missing # A single module uv run pytest tests/test_normalizer.py -v # Local Docker smoke test docker compose -f docker/docker-compose.yml build docker compose -f docker/docker-compose.yml up -d curl -sf http://localhost:8501/_stcore/health docker compose -f docker/docker-compose.yml down -v ``` ### Expected coverage thresholds | Module | Minimum coverage | |--------|------------------| | `core/normalizer.py` | 100% | | `core/description_cleaner.py` | 100% | | `core/classifier.py` | โ‰ฅ 99% | | All others | โ‰ฅ 80% | --- ## Conventions ### Commit messages We follow [Conventional Commits](https://www.conventionalcommits.org/): ``` feat: add context filtering in the ledger fix: correct amount parsing with European separator test: add coverage for detect_internal_transfers docs: update installation guide for Docker arm64 refactor: extract pairing logic into a separate function chore: remove dead code in support/core_logic.py ``` ### Branch naming ``` feat/crea-regola-da-ledger fix/encoding-windows-1252 test/phase0-preprocessing docs/guida-installazione-en ``` ### Code style - **Formatter**: `ruff format` (configured in `pyproject.toml`) - **Linter**: `ruff check` - **Type hints**: required for public functions in `core/` modules - **Decimal**: monetary amounts always use `Decimal`, never `float` ```bash # Local check before committing uv run ruff check . uv run ruff format --check . ``` --- ## Questions? Open a [Discussion](https://github.com/spendifai/spendif-ai/discussions) or write in the comments of the issue closest to your case.