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>
35 lines
1.6 KiB
SQL
35 lines
1.6 KiB
SQL
-- ============================================================================
|
|
-- Migration 005 — exposer le rowid dans la vue de consultation
|
|
--
|
|
-- L'index FTS5 est à contenu externe : il se joint à la table `textes` par
|
|
-- `rowid`. Or une vue SQLite n'a pas de rowid propre, et `v_textes.rowid`
|
|
-- échoue avec « no such column ».
|
|
--
|
|
-- Sans cette colonne, l'application ne peut pas à la fois filtrer sur les
|
|
-- champs dérivés de la vue (`devant_cc`) et joindre l'index plein texte — soit
|
|
-- exactement ce que demande la recherche à facettes.
|
|
-- ============================================================================
|
|
|
|
DROP VIEW v_textes;
|
|
|
|
CREATE VIEW v_textes AS
|
|
SELECT
|
|
t.rowid AS rowid,
|
|
t.*,
|
|
(SELECT COUNT(*) FROM sources s WHERE s.texte_id = t.id) AS nb_sources,
|
|
(SELECT COUNT(*) FROM evenements e WHERE e.texte_id = t.id) AS nb_evenements,
|
|
CASE
|
|
WHEN t.statut = 'saisie_cc' THEN 1
|
|
WHEN EXISTS (SELECT 1 FROM decisions_cc d
|
|
WHERE d.texte_id = t.id
|
|
AND d.date_decision IS NULL
|
|
AND COALESCE(d.resultat, 'en_instance') = 'en_instance') THEN 1
|
|
WHEN EXISTS (SELECT 1 FROM evenements e
|
|
WHERE e.texte_id = t.id AND e.type_etape = 'saisine_cc')
|
|
AND NOT EXISTS (SELECT 1 FROM evenements e
|
|
WHERE e.texte_id = t.id AND e.type_etape = 'decision_cc')
|
|
AND t.statut <> 'promulguee' THEN 1
|
|
ELSE 0
|
|
END AS devant_cc
|
|
FROM textes t;
|