Files
veye-lalwa/README.md
T
Cyber MawonajandClaude Opus 5 34d81c66a8 Phases 6 et 7 : application SvelteKit, PWA, systemd, documentation
Application — rendu serveur sur adapter-node, conforme au §3bis :
- tableau de bord, recherche à facettes, fiche détaillée, calendrier
- /a-propos et /methode prérendues ; tout le reste en rendu serveur
- API JSON ouverte : /api/textes, /api/textes/[slug], /api/echeances
- recherche FTS5 avec surlignage et classement bm25 pondéré (le titre pèse
  dix fois plus que les points clés)
- facettes recalculées sur le résultat filtré par les AUTRES facettes : cocher
  un thème doit recompter les statuts encore disponibles, sinon les compteurs
  mentent

Identité OKI sobrifiée : tokens en CSS vanilla, thème sombre par défaut et
clair opt-in, or comme seule couleur d'action, flag-bar une fois par écran,
polices Archivo/Inter auto-hébergées. Politique de sécurité de contenu
interdisant toute requête tierce. Les statuts ne reposent jamais sur la seule
couleur : libellé en toutes lettres et pastille de forme distincte.

Budget respecté très largement : 6,6 Ko de JavaScript sur l'accueil (3 Ko
compressés) pour un plafond de 100 Ko. Les faits clés — AFD à 500 €, saisine
2026-915 DC, statut — sont lisibles sans JavaScript.

Trois défauts trouvés en testant l'application, pas en relisant le code :
- v_textes est une vue, et une vue SQLite n'a pas de rowid : la jointure avec
  l'index plein texte échouait (migration 005)
- ppl-montagne remontait en « pertinence forte » alors que le corpus dit
  « sans portée pour la Guadeloupe » — la cotation comptait le mot sans lire
  la négation. Idem pour pjl-logement et accord-globe. Corrigé par une lecture
  du voisinage, avec quatre tests de non-régression.
- les libellés d'affichage étaient importés depuis /server dans un
  composant, ce que SvelteKit interdit à raison

PWA : service worker réseau-d'abord pour les pages, cache-d'abord pour le
coffre du build. Une veille législative ne doit pas servir une page périmée
quand le réseau répond — une date de promulgation change tout. Les réponses
issues du cache portent un en-tête qui le dit.

systemd : timer du pipeline (6 h, 18 h, dimanche 9 h, avec dispersion et
rattrapage), application activée par socket avec mise en sommeil à 300 s.
Unités durcies, validées par systemd-analyze.

Documentation : README d'installation sur Debian/Ubuntu vierge,
README-pipeline avec le piège des deux couples d'identifiants PISTE, et
scripts/verifier-conformite.sh qui contrôle mécaniquement le §3bis et le §8.

172 tests, npm run check à 0 erreur, make verifier au vert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 22:34:22 -04:00

260 lines
8.0 KiB
Markdown

# Veille législative Gwadloup
Plateforme de veille sur la production législative française — lois, projets et
propositions de loi, ordonnances, décisions du Conseil constitutionnel — lue
sous l'angle des **libertés des individus, des associations et des
entreprises**, avec un zoom Guadeloupe et outre-mer.
> **Aucune donnée législative n'est inventée.** Chaque fait porte sa source
> (adresse, date, extrait verbatim), son niveau de confiance et son fichier
> d'origine. Ce qui n'est pas établi est marqué « à vérifier », avec son motif
> affiché sur la fiche.
---
## Ce que contient la base
| | |
|---|---|
| Textes législatifs | **52** — 27 promulgués, 7 devant le Conseil constitutionnel, 10 en navette, 5 déposés, 2 annoncés, 1 validé |
| Sources vérifiables | **360**, toutes avec adresse — aucun texte sans lien |
| Événements de parcours | 83 |
| Affaires du Conseil constitutionnel | 12 |
| Analyses transversales | 7 |
| Échéances de calendrier | 9 |
| Marqueurs de citation résolus | **100 %** (332/332), dont 93 % avec un lien |
Les valeurs déduites — 16 cotations Guadeloupe, 17 ventilations d'impact — sont
signalées comme telles, avec leur motif.
---
## Architecture
```
veille_legislative_971/
├── data/input/ corpus de recherche — LECTURE SEULE, jamais modifié
├── pipeline/ Python 3.12 : parseurs, collecteurs, run de veille
├── web/ SvelteKit 2 + Svelte 5, rendu serveur sur adapter-node
├── systemd/ 4 unités : timer du pipeline, socket + service de l'app
├── tests/ pytest, fixtures HTML figées — aucun test ne va au réseau
└── scripts/ contrôles de conformité
```
Une seule base SQLite, `data/veille.db`. La recherche plein texte est assurée
par SQLite lui-même (FTS5). Aucun service externe n'est nécessaire au
fonctionnement : ni moteur de recherche, ni réseau de diffusion, ni traceur.
---
## Installation sur Debian ou Ubuntu vierge
Testé sur Debian 13 et Ubuntu 24.04.
### 1. Dépendances système
```bash
sudo apt update
sudo apt install -y git curl build-essential sqlite3 ca-certificates
```
### 2. Node.js ≥ 20.6
La version 20.6 est le minimum : l'application utilise `node --env-file`, qui
n'existe pas avant.
```bash
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version # doit afficher v20.6 ou plus
```
### 3. Python 3.12 et uv
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv python install 3.12
```
### 4. Le projet
```bash
sudo mkdir -p /opt/veille-legislative
sudo chown "$USER:$USER" /opt/veille-legislative
git clone <adresse-du-depot> /opt/veille-legislative
cd /opt/veille-legislative
make install # environnement Python + dépendances npm
cp .env.example .env
$EDITOR .env # renseigner les identifiants PISTE — voir README-pipeline.md
```
### 5. Remplir la base et construire l'application
```bash
make seed # → 52 textes, 360 sources
cd web && npm run polices && cd .. # copie les polices depuis npm
make build
make verifier # contrôles de conformité
```
### 6. Vérifier localement
```bash
cd web
HOST=127.0.0.1 PORT=3971 VEILLE_DB=/opt/veille-legislative/data/veille.db node build
```
Puis, dans un autre terminal :
```bash
curl -sI http://127.0.0.1:3971/ | head -1 # HTTP/1.1 200 OK
curl -s http://127.0.0.1:3971/api/textes | head -c 200
```
---
## Mise en service
### Compte dédié
```bash
sudo useradd --system --home /opt/veille-legislative --shell /usr/sbin/nologin veille
sudo chown -R veille:veille /opt/veille-legislative
sudo chmod 600 /opt/veille-legislative/.env
```
### Unités systemd
```bash
sudo cp systemd/*.service systemd/*.timer systemd/*.socket /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now veille-web.socket # l'app se réveille à la demande
sudo systemctl enable --now veille-legislative.timer # collecte 6 h, 18 h, dimanche 9 h
```
L'application est **activée par socket** : systemd tient le port ouvert et ne
démarre Node qu'à la première requête ; sans trafic pendant `IDLE_TIMEOUT`
(300 s), elle s'arrête. Sur un site de veille peu fréquenté, l'empreinte mémoire
tombe à zéro entre deux visites — ce qui compte sur un serveur à 5 € par mois.
Avant de démarrer, ajustez `ORIGIN` dans `veille-web.service` : sans lui, les
soumissions de formulaire sont refusées derrière un reverse proxy.
### Reverse proxy
**Caddy** (le plus court, HTTPS automatique) :
```caddy
veille.example.org {
encode gzip zstd
reverse_proxy 127.0.0.1:3971
}
```
**nginx** :
```nginx
server {
listen 443 ssl http2;
server_name veille.example.org;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
location / {
proxy_pass http://127.0.0.1:3971;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
}
}
```
Avec nginx, remplacez `ORIGIN` par `PROTOCOL_HEADER=x-forwarded-proto` et
`HOST_HEADER=x-forwarded-host` dans le service.
### Vérifier
```bash
systemctl status veille-web.socket
systemctl list-timers veille-legislative.timer
journalctl -u veille-legislative -n 40
```
---
## Commandes
```
make install installe pipeline Python et application web
make seed remplit la base depuis data/input/
make reseed repart d'une base vierge
make update-dry collecte réelle, aucune écriture, rapport des écarts
make update collecte et applique
make test pytest avec couverture
make lint ruff
make dev serveur de développement (port 5971)
make build build de production
make check vérification TypeScript
make verifier contrôles de conformité au cahier des charges
```
---
## Dégradations documentées
| Situation | Conséquence |
|---|---|
| Sans identifiants PISTE | Le collecteur Légifrance se désactive et l'annonce dans le rapport. Le Sénat et le Conseil constitutionnel prennent le relais : les promulgations et les décisions restent suivies. Voir `README-pipeline.md` §3. |
| Une source indisponible | Le collecteur concerné échoue seul ; les autres poursuivent. L'erreur figure au rapport de run. |
| Réseau coupé | `make update --hors-ligne` travaille sur le cache HTTP. Côté navigateur, le service worker sert les pages déjà consultées, en signalant qu'elles peuvent être périmées. |
| Base absente | L'application refuse de démarrer avec un message indiquant les emplacements essayés. |
**Deux adresses du cahier des charges sont mortes** et ont été remplacées :
`senat.fr/lois/index.html` et
`assemblee-nationale.fr/dyn/actualites-accueil/promulgations-de-lois` renvoient
toutes deux 404. La liste `senat.fr/dossiers-legislatifs/lois-promulguees.html`
couvre l'ensemble des promulgations et tient lieu de source unique.
---
## Sauvegarde
La base est un fichier unique :
```bash
sqlite3 data/veille.db ".backup /sauvegardes/veille-$(date +%F).db"
```
Ne copiez jamais le fichier pendant un passage du pipeline : le mode WAL laisse
des fichiers annexes. `.backup` s'en charge correctement.
---
## Interface de programmation
Ouverte, sans clé :
| Route | Objet |
|---|---|
| `GET /api/textes` | liste filtrable — `q`, `statut`, `theme`, `type`, `impact`, `guadeloupe`, `confiance`, `from`, `to`, `tri`, `page` |
| `GET /api/textes/[identifiant]` | fiche complète, sources et parcours compris |
| `GET /api/echeances` | calendrier, avec `?jours=N` en option |
```bash
curl -s 'https://veille.example.org/api/textes?statut=saisie_cc&guadeloupe=forte' | jq '.total'
```
---
## Licence
AGPL-3.0-or-later. Le corpus de `data/input/` reste la propriété de ses auteurs.
Si vous réutilisez ces données, citez la source primaire — Journal officiel,
assemblées, Conseil constitutionnel — plutôt que cette plateforme : elle n'est
qu'un intermédiaire.