CI / test (push) Failing after 1m37s
- Dockerfile: copie du code avant installation (le package installé n'est plus vide — I6), utilisateur non-root, HEALTHCHECK - compose: version: obsolète retiré, variables d'auth, healthcheck - pyproject: version 0.2.0, jinja2 <4, config pytest - LICENSE (MIT), CHANGELOG 0.2.0, README réécrit (configuration, sécurité, API, tests), .dockerignore
162 lines
6.1 KiB
Markdown
162 lines
6.1 KiB
Markdown
# Kanbante
|
||
|
||
**Kanban project manager integrated with Gitea** — lightweight, self-hosted, dark theme.
|
||
|
||
## Features
|
||
|
||
- 📋 **Dashboard** — tous tes projets Gitea en un coup d'œil (actifs / inactifs / archivés — le vrai drapeau Gitea)
|
||
- 🗂️ **Kanban Board** — colonnes Backlog → À faire → En cours → Révision → Terminé, ordre des cartes persisté
|
||
- 🎯 **Drag & Drop** — glisse les issues entre colonnes ; en cas d'échec, la carte est replacée
|
||
- 🔗 **Gitea Sync bidirectionnelle** — « Terminé » ferme l'issue dans Gitea, la ressortir la rouvre ; l'état local est réconcilié à chaque chargement
|
||
- ➕ **Création d'issues** depuis le board, filtres texte + étiquettes, cartes liées à Gitea
|
||
- 🎯 **Vue Focus** — tout ce qui est En cours / En révision, tous projets confondus (`/focus`)
|
||
- 📝 **Notes** — bloc-notes par projet
|
||
- 🔐 **Authentification** Basic Auth intégrée + protection CSRF (voir Sécurité)
|
||
- 🌙 **Dark theme** — conçu pour les longues sessions
|
||
- 🐳 **Docker** — un seul conteneur, utilisateur non-root, healthcheck
|
||
- 📴 **Aucun CDN** — les bibliothèques JS sont vendorées dans `static/vendor/`, l'app fonctionne hors-ligne
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
# 1. Installer les dépendances
|
||
cd kanbante
|
||
pip install -e .
|
||
|
||
# 2. Configurer les variables d'environnement
|
||
export GITEA_URL=https://git.dracodev.net
|
||
export GITEA_TOKEN=ton_token_gitea
|
||
# Recommandé dès que le service dépasse localhost :
|
||
export KANBANTE_AUTH_USER=ton_nom
|
||
export KANBANTE_AUTH_PASSWORD=ton_mot_de_passe
|
||
|
||
# 3. Lancer
|
||
uvicorn app.main:app --reload --port 8080
|
||
```
|
||
|
||
Ouvrir http://localhost:8080
|
||
|
||
## Docker
|
||
|
||
### Avec docker-compose (recommandé)
|
||
|
||
```bash
|
||
cat > .env <<'EOF'
|
||
GITEA_TOKEN=ton_token
|
||
KANBANTE_AUTH_USER=ton_nom
|
||
KANBANTE_AUTH_PASSWORD=ton_mot_de_passe
|
||
EOF
|
||
docker compose up -d
|
||
```
|
||
|
||
La base SQLite vit dans le volume `kanbante_data` (monté sur `/data`,
|
||
chemin `KANBANTE_DB_PATH`) : les positions de cartes et les notes
|
||
survivent aux recréations du conteneur.
|
||
|
||
### Avec docker uniquement
|
||
|
||
```bash
|
||
docker build -t kanbante:latest .
|
||
docker volume create kanbante_data
|
||
docker run -d \
|
||
--name kanbante \
|
||
-p 8080:8080 \
|
||
-v kanbante_data:/data \
|
||
-e GITEA_URL=https://git.dracodev.net \
|
||
-e GITEA_TOKEN=ton_token \
|
||
-e KANBANTE_AUTH_USER=ton_nom \
|
||
-e KANBANTE_AUTH_PASSWORD=ton_mot_de_passe \
|
||
--restart unless-stopped \
|
||
kanbante:latest
|
||
```
|
||
|
||
### Déploiement sur Deepin 25 (Debian Bookworm)
|
||
|
||
```bash
|
||
sudo apt install -y docker.io docker-compose docker-buildx
|
||
sudo usermod -aG docker $USER
|
||
sudo systemctl enable --now docker
|
||
# Builder et lancer (voir section "Avec docker uniquement")
|
||
```
|
||
|
||
## Configuration
|
||
|
||
| Variable | Défaut | Rôle |
|
||
|---|---|---|
|
||
| `GITEA_URL` | `https://git.dracodev.net` | Instance Gitea |
|
||
| `GITEA_TOKEN` | *(vide)* | Jeton API Gitea — **portée conseillée : lecture + écriture des issues, sur un compte dédié, pas un jeton admin**. Sans jeton : contenu public seulement |
|
||
| `KANBANTE_DB_PATH` | `~/.kanbante/kanbante.db` | Base SQLite locale (en Docker : `/data/kanbante.db`) |
|
||
| `KANBANTE_AUTH_USER` / `KANBANTE_AUTH_PASSWORD` | *(vide)* | Active la Basic Auth dès que les deux sont définis |
|
||
| `KANBANTE_REQUIRE_AUTH` | `0` | `1` = l'app refuse de servir (503) si l'auth n'est pas configurée |
|
||
| `KANBANTE_ACTIVE_WINDOW_DAYS` | `365` | Un dépôt non archivé mis à jour depuis moins de N jours est « actif » |
|
||
| `KANBANTE_CACHE_TTL` | `30` | Secondes de cache des listes Gitea (dépôts, issues) |
|
||
| `KANBANTE_MAX_NOTE_CHARS` | `20000` | Taille maximale d'une note de projet |
|
||
| `KANBANTE_SYNC_GITEA` | `1` | `0` = les déplacements ne ferment/rouvrent plus les issues Gitea |
|
||
|
||
## Sécurité
|
||
|
||
- Sans `KANBANTE_AUTH_*`, **quiconque atteint le port 8080 voit tous les
|
||
dépôts visibles par le jeton et peut modifier les boards** — l'app
|
||
l'annonce par un avertissement au démarrage. Définis les identifiants,
|
||
ou mets Kanbante derrière un reverse proxy authentifiant, et pose
|
||
`KANBANTE_REQUIRE_AUTH=1` pour échouer fermé.
|
||
- Tous les POST exigent un jeton CSRF (cookie double-submit posé par les
|
||
pages) : les appels API directs doivent d'abord charger une page pour
|
||
obtenir le cookie, puis envoyer le jeton (en-tête `X-CSRF-Token` ou
|
||
champ `csrf_token`).
|
||
- Aucun secret n'est versionné : le jeton passe uniquement par
|
||
l'environnement / le fichier `.env` local (ignoré par git).
|
||
|
||
## Architecture
|
||
|
||
```
|
||
kanbante/
|
||
├── app/
|
||
│ ├── main.py # FastAPI app (routes, auth, CSRF, lifespan)
|
||
│ ├── config.py # Réglages par variables d'environnement
|
||
│ ├── gitea_client.py # Client API Gitea asynchrone, paginé, avec cache
|
||
│ ├── models.py # SQLite (état du board local + migrations)
|
||
│ └── templates/ # Jinja2 (dashboard, board, focus, error)
|
||
├── static/
|
||
│ ├── css/style.css # Design system dark theme
|
||
│ ├── js/board.js # Drag & drop, filtres, création d'issues
|
||
│ └── vendor/ # HTMX, Alpine, SortableJS (vendorés, aucun CDN)
|
||
├── tests/ # Suite pytest
|
||
├── Dockerfile
|
||
├── docker-compose.yml
|
||
└── README.md
|
||
```
|
||
|
||
## API
|
||
|
||
| Méthode | Route | Description |
|
||
|---------|-------|-------------|
|
||
| GET | `/` | Dashboard tous les projets |
|
||
| GET | `/board/{owner}/{repo}` | Kanban board |
|
||
| GET | `/focus` | En cours + En révision, tous projets actifs |
|
||
| POST | `/api/move` | Déplacer une issue (ordre persisté, synchro Gitea) |
|
||
| POST | `/api/issues` | Créer une issue Gitea depuis le board |
|
||
| POST | `/api/notes` | Sauvegarder des notes |
|
||
| GET | `/api/stats` | Statistiques JSON |
|
||
| GET | `/api/projects` | Projets JSON (actifs / inactifs / archivés) |
|
||
| GET | `/api/health` | Liveness (aucune dépendance) |
|
||
| GET | `/api/readiness` | Readiness : teste SQLite + Gitea (503 si KO) |
|
||
|
||
Les POST répondent avec des codes explicites : `400` entrée invalide,
|
||
`403` jeton CSRF manquant/invalide, `413` note trop longue, `502` Gitea
|
||
injoignable.
|
||
|
||
## Tests
|
||
|
||
```bash
|
||
pip install -e ".[dev]"
|
||
pytest
|
||
```
|
||
|
||
La CI (`.gitea/workflows/ci.yml`) lance la même suite à chaque push.
|
||
|
||
## Licence
|
||
|
||
MIT — voir [LICENSE](LICENSE). Historique des versions :
|
||
[CHANGELOG.md](CHANGELOG.md).
|