doc: improve contributor guidance
Co-authored-by: OpenAI/GPT-5.6-Terra <vibecoder@antoineve.me> Co-authored-by: Google/Gemini-3.5-Flash <vibecoder@antoineve.me> Co-authored-by: DeepSeek/DeepSeek-v4-Flash <vibecoder@antoineve.me>
This commit is contained in:
26
AGENTS.md
26
AGENTS.md
@@ -1,6 +1,8 @@
|
|||||||
# CLAUDE.md
|
# AGENTS.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
Ce fichier fournit des directives et des consignes pour les agents d'intelligence artificielle et assistants de développement (multi-modèles et multi-fournisseurs) travaillant sur ce dépôt.
|
||||||
|
|
||||||
|
Pour une présentation complète de l'architecture, de la configuration et du guide de démarrage, se référer à [docs/onboarding.md](docs/onboarding.md).
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@@ -25,14 +27,28 @@ python -m venv .venv
|
|||||||
sudo systemctl edit --full tableau-de-bord-pro # configurer SECRET_KEY
|
sudo systemctl edit --full tableau-de-bord-pro # configurer SECRET_KEY
|
||||||
sudo systemctl restart tableau-de-bord-pro
|
sudo systemctl restart tableau-de-bord-pro
|
||||||
|
|
||||||
# Git commit (GPG signing désactivé — pinentry inaccessible dans cet env)
|
# Qualité du code (Ruff)
|
||||||
git -c commit.gpgsign=false commit -m "..."
|
.venv/bin/ruff check .
|
||||||
|
.venv/bin/ruff format --check .
|
||||||
|
.venv/bin/ruff format .
|
||||||
|
|
||||||
|
# Découverte des modèles OpenCode (configuration environnementale hors dépôt)
|
||||||
|
grep -A 1 -B 1 subagent /home/antoine/.config/opencode/opencode.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Variables d'environnement
|
## Variables d'environnement
|
||||||
|
|
||||||
- `SECRET_KEY` : requis en production (défaut `dev-secret-change-in-prod` en dev)
|
- `SECRET_KEY` : requis en production (défaut `dev-secret-change-in-prod` en dev)
|
||||||
|
|
||||||
|
## Git & Conventions de Commit
|
||||||
|
|
||||||
|
- **Politique Git** : Les commits intermédiaires générés par les agents d'IA doivent être non signés en utilisant l'option `git -c commit.gpgsign=false commit -m "..."` (car pinentry est inaccessible dans cet environnement). L'utilisateur effectuera un amend signé (`git commit --amend -S`) du commit final lorsqu'il sera disponible.
|
||||||
|
- **Convention de trailers** : Chaque commit réalisé par un agent d'IA doit inclure le trailer suivant à la fin du message de commit pour identifier le modèle utilisé :
|
||||||
|
```text
|
||||||
|
Co-authored-by: Fournisseur/Modèle <vibecoder@antoineve.me>
|
||||||
|
```
|
||||||
|
*Exemple :* `Co-authored-by: Anthropic/Claude-3.5-Sonnet <vibecoder@antoineve.me>` ou `Co-authored-by: Google/Gemini-3.5-Flash <vibecoder@antoineve.me>`.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Flask app using the factory pattern (`create_app()` in `app/__init__.py`). The DB is SQLite via SQLAlchemy, stored in `instance/worklog.db`. All vehicle/journey/tax configuration lives in `config.toml` (loaded at startup into `app.config["TOML"]`), not in the database.
|
Flask app using the factory pattern (`create_app()` in `app/__init__.py`). The DB is SQLite via SQLAlchemy, stored in `instance/worklog.db`. All vehicle/journey/tax configuration lives in `config.toml` (loaded at startup into `app.config["TOML"]`), not in the database.
|
||||||
@@ -62,7 +78,7 @@ Flask app using the factory pattern (`create_app()` in `app/__init__.py`). The D
|
|||||||
|
|
||||||
- **Pas de migration de schéma** : l'app utilise `db.create_all()` uniquement (pas d'Alembic). Tout changement de modèle nécessite de supprimer `instance/worklog.db` en dev, ou une migration manuelle en prod.
|
- **Pas de migration de schéma** : l'app utilise `db.create_all()` uniquement (pas d'Alembic). Tout changement de modèle nécessite de supprimer `instance/worklog.db` en dev, ou une migration manuelle en prod.
|
||||||
- **Barème kilométrique** : les tranches dans `config.toml` sont à mettre à jour manuellement chaque année (section `[bareme_kilometrique.YYYY]`).
|
- **Barème kilométrique** : les tranches dans `config.toml` sont à mettre à jour manuellement chaque année (section `[bareme_kilometrique.YYYY]`).
|
||||||
- **`datetime.utcnow()` deprecated** : les modèles utilisent `datetime.utcnow` (warning sur Python 3.14+). À remplacer par `datetime.now(UTC)` lors d'une prochaine évolution des modèles.
|
- **`datetime.utcnow()` déprécié** : Les modèles utilisent actuellement `datetime.utcnow` (générant un avertissement sur Python 3.12+ et obsolète sur Python 3.14+). Il est formellement recommandé d'utiliser `datetime.now(UTC)` (avec `from datetime import UTC`) à la place pour toute nouvelle manipulation de date/heure ou lors de la prochaine évolution des modèles.
|
||||||
- **Filtres Jinja2** (définis dans `app/__init__.py`) : `{{ date | date_fr }}` pour les dates en français ; `{{ day_type | day_type_fr }}` pour les libellés de types de jours (WORK→Travail, TT→Télétravail, etc.).
|
- **Filtres Jinja2** (définis dans `app/__init__.py`) : `{{ date | date_fr }}` pour les dates en français ; `{{ day_type | day_type_fr }}` pour les libellés de types de jours (WORK→Travail, TT→Télétravail, etc.).
|
||||||
- **`db.get_engine()` deprecated** en Flask-SQLAlchemy 3.x → utiliser `db.engine`.
|
- **`db.get_engine()` deprecated** en Flask-SQLAlchemy 3.x → utiliser `db.engine`.
|
||||||
- **Migration `_migrate_db`** : vérifier l'existence de la table avant `ALTER TABLE` — SQLite peut avoir un fichier DB sans tables (ex: premier démarrage avec `instance/worklog.db` vide).
|
- **Migration `_migrate_db`** : vérifier l'existence de la table avant `ALTER TABLE` — SQLite peut avoir un fichier DB sans tables (ex: premier démarrage avec `instance/worklog.db` vide).
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ sudo systemctl restart tableau-de-bord-pro
|
|||||||
- En **production** : Tu dois écrire une migration manuelle dans la fonction `_migrate_db` située dans `app/__init__.py`. Cette fonction s'exécute au démarrage de l'application, vérifie l'existence des colonnes via SQLite, et applique les instructions `ALTER TABLE` nécessaires de manière sécurisée.
|
- En **production** : Tu dois écrire une migration manuelle dans la fonction `_migrate_db` située dans `app/__init__.py`. Cette fonction s'exécute au démarrage de l'application, vérifie l'existence des colonnes via SQLite, et applique les instructions `ALTER TABLE` nécessaires de manière sécurisée.
|
||||||
|
|
||||||
### Dépréciations à surveiller
|
### Dépréciations à surveiller
|
||||||
- **`datetime.utcnow()`** : Utilisé dans les modèles de données. Cette méthode est dépréciée depuis Python 3.12. Lors d'une prochaine évolution majeure des modèles, il faudra la remplacer par `datetime.now(UTC)`.
|
- **`datetime.utcnow()`** : Cette méthode est dépréciée depuis Python 3.12. Il est formellement recommandé d'utiliser `datetime.now(UTC)` (avec `from datetime import UTC`) à la place. Lors d'une prochaine évolution majeure des modèles, il faudra remplacer les occurrences existantes.
|
||||||
- **`db.get_engine()`** : Déprécié dans Flask-SQLAlchemy 3.x. Utilise toujours `db.engine` à la place.
|
- **`db.get_engine()`** : Déprécié dans Flask-SQLAlchemy 3.x. Utilise toujours `db.engine` à la place.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ git commit -m "feat: TOML config loader for vehicles, journeys, and tax scales"
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
from app import db
|
from app import db
|
||||||
from datetime import date, time, datetime
|
from datetime import date, time, datetime, UTC
|
||||||
from enum import Enum as PyEnum
|
from enum import Enum as PyEnum
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as so
|
import sqlalchemy.orm as so
|
||||||
@@ -410,9 +410,9 @@ class WorkEntry(db.Model):
|
|||||||
journey_profile_id: so.Mapped[str | None] = so.mapped_column(sa.String(64), nullable=True)
|
journey_profile_id: so.Mapped[str | None] = so.mapped_column(sa.String(64), nullable=True)
|
||||||
day_type: so.Mapped[str] = so.mapped_column(sa.String(16), nullable=False, default="WORK")
|
day_type: so.Mapped[str] = so.mapped_column(sa.String(16), nullable=False, default="WORK")
|
||||||
comment: so.Mapped[str | None] = so.mapped_column(sa.Text, nullable=True)
|
comment: so.Mapped[str | None] = so.mapped_column(sa.Text, nullable=True)
|
||||||
created_at: so.Mapped[datetime] = so.mapped_column(sa.DateTime, default=datetime.utcnow)
|
created_at: so.Mapped[datetime] = so.mapped_column(sa.DateTime, default=lambda: datetime.now(UTC))
|
||||||
updated_at: so.Mapped[datetime] = so.mapped_column(
|
updated_at: so.Mapped[datetime] = so.mapped_column(
|
||||||
sa.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
sa.DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC)
|
||||||
)
|
)
|
||||||
|
|
||||||
time_slots: so.Mapped[list["TimeSlot"]] = so.relationship(
|
time_slots: so.Mapped[list["TimeSlot"]] = so.relationship(
|
||||||
|
|||||||
Reference in New Issue
Block a user