feat: budget-tracker — spec, constitution, data-model, API contracts, plan

This commit is contained in:
Nox (OpenClaw)
2026-03-16 06:59:06 +00:00
commit 6895609edc
26 changed files with 4838 additions and 0 deletions
+247
View File
@@ -0,0 +1,247 @@
# Contrats API REST — Budget Tracker
**Version** : 1.0.0 | **Base URL** : `/api/v1` | **Format** : JSON
## Conventions
- Tous les montants sont en **centimes** (integer)
- Authentification : `Authorization: Bearer <access_token>`
- Dates : ISO 8601 (`YYYY-MM-DD`)
- Mois : `YYYY-MM`
- Soft-delete : les ressources supprimées retournent 404
- Erreurs : `{"detail": "message d'erreur"}`
---
## Authentification
### POST /auth/register
Créer un compte utilisateur.
**Body** :
```json
{"email": "user@example.com", "password": "...", "full_name": "Jean Dupont"}
```
**Réponse 201** :
```json
{"id": "uuid", "email": "user@example.com", "full_name": "Jean Dupont"}
```
### POST /auth/login
Obtenir les tokens JWT.
**Body** : `application/x-www-form-urlencoded` : `username=email&password=...`
**Réponse 200** :
```json
{"access_token": "...", "refresh_token": "...", "token_type": "bearer"}
```
### POST /auth/refresh
Renouveler l'access token.
**Body** : `{"refresh_token": "..."}`
**Réponse 200** : `{"access_token": "...", "token_type": "bearer"}`
### POST /auth/logout
Invalider le refresh token.
**Réponse 204** : no content
---
## Transactions
### GET /transactions
Lister les transactions (paginées, filtrables).
**Query params** : `?month=2026-03&category_id=uuid&type=expense&page=1&per_page=20`
**Réponse 200** :
```json
{
"items": [
{
"id": "uuid",
"amount_cents": 4500,
"type": "expense",
"description": "Courses Leclerc",
"category": {"id": "uuid", "name": "Alimentation", "color": "#4CAF50"},
"transaction_date": "2026-03-15",
"created_at": "2026-03-15T10:30:00Z"
}
],
"total": 42,
"page": 1,
"per_page": 20
}
```
### POST /transactions
Créer une transaction.
**Body** :
```json
{
"amount_cents": 4500,
"type": "expense",
"category_id": "uuid",
"description": "Courses Leclerc",
"transaction_date": "2026-03-15"
}
```
**Réponse 201** : transaction complète
### GET /transactions/{id}
Détail d'une transaction. **Réponse 200** : transaction complète
### PUT /transactions/{id}
Modifier une transaction. **Body** : mêmes champs que POST. **Réponse 200** : transaction mise à jour
### DELETE /transactions/{id}
Soft-delete. **Réponse 204** : no content
---
## Catégories
### GET /categories
Lister les catégories de l'utilisateur (y compris les défauts système).
**Query** : `?type=expense`
**Réponse 200** :
```json
[
{"id": "uuid", "name": "Alimentation", "type": "expense", "color": "#4CAF50", "icon": "shopping-cart", "is_default": true}
]
```
### POST /categories
Créer une catégorie personnalisée.
**Body** : `{"name": "Loisirs", "type": "expense", "color": "#9C27B0", "icon": "gamepad"}`
**Réponse 201** : catégorie créée
### PUT /categories/{id}
Modifier une catégorie. **Réponse 200** : catégorie mise à jour
### DELETE /categories/{id}
Soft-delete. Erreur 409 si des transactions y sont liées.
---
## Budgets (Enveloppes)
### GET /budgets
Lister les budgets du mois courant ou d'un mois donné.
**Query** : `?month=2026-03`
**Réponse 200** :
```json
[
{
"id": "uuid",
"category": {"id": "uuid", "name": "Alimentation"},
"month": "2026-03",
"limit_cents": 30000,
"spent_cents": 12500,
"remaining_cents": 17500,
"percentage_used": 41.7
}
]
```
### POST /budgets
Définir un budget pour une catégorie/mois.
**Body** : `{"category_id": "uuid", "month": "2026-03", "limit_cents": 30000}`
**Réponse 201** : budget créé
### PUT /budgets/{id}
Modifier la limite d'un budget. **Réponse 200** : budget mis à jour
### DELETE /budgets/{id}
Supprimer un budget. **Réponse 204**
---
## Dashboard
### GET /dashboard
KPIs du mois courant ou d'un mois donné.
**Query** : `?month=2026-03`
**Réponse 200** :
```json
{
"month": "2026-03",
"balance_cents": 150000,
"total_income_cents": 250000,
"total_expense_cents": 100000,
"by_category": [
{"category_id": "uuid", "name": "Alimentation", "total_cents": 45000, "percentage": 45.0}
],
"monthly_trend": [
{"month": "2026-01", "income_cents": 240000, "expense_cents": 110000},
{"month": "2026-02", "income_cents": 245000, "expense_cents": 95000},
{"month": "2026-03", "income_cents": 250000, "expense_cents": 100000}
],
"budget_alerts": [
{"category_id": "uuid", "name": "Loisirs", "percentage_used": 92.0, "status": "warning"}
]
}
```
---
## Historique
### GET /history
Résumé mensuel navigable.
**Query** : `?year=2026`
**Réponse 200** :
```json
[
{
"month": "2026-03",
"income_cents": 250000,
"expense_cents": 100000,
"balance_cents": 150000,
"transaction_count": 42
}
]
```
---
## Export
### GET /export/csv
Exporter les transactions en CSV.
**Query** : `?month=2026-03` (optionnel — tout exporter si absent)
**Réponse 200** : `Content-Type: text/csv`, fichier `transactions_2026-03.csv`
### GET /export/pdf
Exporter le rapport mensuel en PDF.
**Query** : `?month=2026-03`
**Réponse 200** : `Content-Type: application/pdf`, fichier `rapport_2026-03.pdf`
---
## Codes d'erreur
| Code | Signification |
|------|--------------|
| 400 | Données invalides (validation Pydantic) |
| 401 | Token manquant ou expiré |
| 403 | Ressource appartenant à un autre utilisateur |
| 404 | Ressource introuvable (ou soft-deleted) |
| 409 | Conflit (doublon, contrainte métier) |
| 422 | Erreur de validation (détail par champ) |
| 500 | Erreur serveur |