Commit Graph
20 Commits
Author SHA1 Message Date
billisdeadandClaude Sonnet 4.6 219292ea6c Fix dark mode on synthesis panel and static pages
- Synthesis column: bg-[#F9F7F1] → dark:bg-card; noise overlay
  mix-blend-multiply → dark:mix-blend-overlay (avoids darkening an
  already dark background)
- Mobile tab button active synthesis state: same bg fix
- Submission alert (error): add dark:bg-amber-950/40 dark:text-amber-200
  dark:border-amber-800/50
- not-found.tsx: bg-gray-50 → dark:bg-background; text colors use
  semantic tokens (text-foreground, text-muted-foreground)
- flyer.tsx: control bar bg-white → dark:bg-card; printable flyer
  stays white intentionally

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 17:30:10 +02:00
billisdeadandClaude Sonnet 4.6 2ab561f61e Refine synthesis prompt for honesty and faithfulness
- Require exact counts ("une contribution", "X sur Y") — forbid vague
  "des citoyens" or "plusieurs" without numerical basis
- Prohibit paraphrasing that softens or amplifies a concrete demand
- Require explicit mention of contradictions (no artificial consensus)
- Catch-all sentence for contributions that fit no identified theme,
  rather than silently dropping them
- Grouping by theme conditional on ≥2 contributions covering it
- Cap raised to 5 themes to avoid forced merging on heterogeneous sets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:59:35 +02:00
billisdeadandClaude Sonnet 4.6 b6471de51b Improve mobile responsiveness on home page and navbar
- Navbar: hide Fonctionnement and Flyer QR on mobile (hidden sm:inline),
  preventing overflow on small screens
- Home: add mobile tab bar (Proposer / Synthèse) replacing the broken
  two-column stacked layout that was constrained to h-[calc(100vh-5rem)]
- Grid: md:h-[calc(100vh-9rem)] (desktop only); columns show/hide via
  mobileTab state
- Countdown: visible in synthesis tab label on mobile, in header on md+
- Textarea: 90px min-height on mobile, 120px on sm+

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:53:15 +02:00
billisdeadandClaude Sonnet 4.6 f2d51fe21a Add synthesis refresh countdown display
Show a live countdown (15→0s) in the synthesis header indicating when the
next auto-refresh will occur. Resets on every successful synthesis fetch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:47:45 +02:00
billisdeadandClaude Sonnet 4.6 b25fd5da49 Show API error message to user instead of generic fallback
- Export ApiError from api-client-react package
- home.tsx onError: extract error.data.message from ApiError and display it
  (cooldown, rate limit, consent_required, validation messages are now visible)
- Differentiate alert title: "Contribution non retenue" for AI rejection
  (has a reason), "Envoi impossible" for technical errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:34:35 +02:00
billisdeadandClaude Sonnet 4.6 9553115d8c Fix 10 bugs found in general code review
Backend (app.py / database.py / ai_agent.py):
- [Critique] Autoclose loop: add pg_try_advisory_lock so only one Gunicorn
  worker runs the check per 60s cycle; add random startup jitter
- [Critique] admin_delete_idea: pass consultation_id to
  _update_synthesis_background so the right synthesis is regenerated
- [Majeur] admin_login: return HMAC-signed session token instead of raw
  ADMIN_SECRET; require_admin verifies the signature (TTL 8h)
- [Majeur] bulk_delete: replace str.isdigit() (Unicode-unsafe) with
  try/except int() to prevent crash on Unicode digit characters
- [Majeur] create_consultation: force UTC timezone on naive datetime from
  fromisoformat() to prevent TypeError when comparing with UTC-aware now()
- [Majeur] ai_agent.py: fix 'raw' in dir() -> 'raw' in locals() so the
  JSON parse error log actually shows the raw response
- [Mineur] export print: use datetime.now(UTC) instead of datetime.now()

Frontend (React):
- [Majeur] consultation.tsx: show startsAt (not endsAt) for upcoming
  consultations; add startsAt variable
- [Majeur] consultations-list.tsx: same fix for the list view
- [Mineur] home.tsx: guard new Date(idea.createdAt) against null
- [Mineur] admin.tsx: check HTTP status in exportCsv XHR before creating
  download link; show error toast on non-200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:26:52 +02:00
billisdeadandClaude Sonnet 4.6 18bb0efc30 Fix consent token not set before submission
- home.tsx: extract postConsent() helper; make onSubmit async and await it
  before doActualSubmit (returning users); await it in handleConsentConfirm
  before doActualSubmit (new users, was fire-and-forget)
- consultation.tsx: same fix on returning-user path in onSubmit

Without this, returning users (consent_v1 in localStorage) never called
/api/consent so the _ct cookie was never set, causing all submissions to
return 403 consent_required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:15:43 +02:00
billisdeadandClaude Sonnet 4.6 e31c268d54 Enforce consent token on submission, reduce default cooldown
- Require signed _ct cookie (set by POST /api/consent) before accepting any
  submission. Direct API calls without a prior consent flow are rejected 403.
- Add _sign_consent_token / _verify_consent_token (HMAC-SHA256, 24h TTL).
- Lower default CONTRIBUTION_COOLDOWN_SECONDS from 3600 to 240 (4 min).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 16:08:11 +02:00
billisdeadandClaude Sonnet 4.6 1d180acf15 Fix init_db not called under Gunicorn
init_db() was only called inside if __name__ == "__main__", which Gunicorn
never executes. Tables were never created, causing every request to fail.
Move the call to module level so it runs on import, before the autoclose
thread starts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 15:57:52 +02:00
billisdeadandClaude Sonnet 4.6 a43e9717a8 Remove all Replit artifacts and references
- Delete artifacts/mockup-sandbox/ (Replit UI preview sandbox, unused)
- Delete artifacts/voix-du-peuple/.replit-artifact/ (Replit metadata)
- Delete .replit and .replitignore (Replit deployment config)
- Delete .agents/ (Replit agent session tracking)
- Fix scripts/push-gitea.sh: remove mentions of "Replit Secrets"
- Regenerate pnpm-lock.yaml (mockup-sandbox removed from workspace)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 15:48:30 +02:00
billisdeadandClaude Sonnet 4.6 37904839aa Remove stale Replit catalog deps from mockup-sandbox
@replit/vite-plugin-cartographer and @replit/vite-plugin-runtime-error-modal
were removed from the workspace catalog during de-Replit-isation but remained
in mockup-sandbox/package.json, breaking pnpm install. Lockfile regenerated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 15:38:15 +02:00
billisdeadandClaude Sonnet 4.6 c70d594292 CONTRIBUTING : procédure formalisée + README : soutien remonté
- CONTRIBUTING.md : section "Proposer une contribution" réécrite avec
  tableaux Markdown, blocs de code inline (convention branches, commits,
  template PR), règles backend/frontend détaillées
- README.md : mention financement déplacée juste après la présentation,
  avant la section Fonctionnalités ; section Soutenir le projet supprimée
  en fin de fichier

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:50:34 +02:00
billisdeadandClaude Sonnet 4.6 e1620aa3c8 README complet + CONTRIBUTING.md
- README réécrit à partir du code : fonctionnalités réelles, stack,
  installation (dev local, build, prod), variables d'environnement
  documentées avec leur effet, références aux docs existants
- CONTRIBUTING.md créé : signalement de bug, procédure de PR,
  mention que GitHub est un miroir public du dépôt Gitea source

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:43:19 +02:00
billisdeadandClaude Sonnet 4.6 be507cb229 dev-local.sh : installation automatique des prérequis
- Venv Python : création automatique si absent (détecte python3.11,
  python3, python >= 3.9 ; erreur guidée si introuvable)
- Dépendances pip : pip install -r requirements.txt à chaque lancement
  (no-op si rien n'a changé, garantit la cohérence après un pull)
- pnpm : installation automatique via corepack (si dispo) ou npm
- Node.js : non installable sans root — message d'erreur avec commandes
  exactes pour Rocky/RHEL, Debian/Ubuntu et nvm

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:33:40 +02:00
billisdeadandClaude Sonnet 4.6 8f531d2e0e Procédure de développement local + tunnel SSH
- Nouveau script scripts/dev-local.sh : lance Flask (port 8080) et le
  serveur Vite dev (port 5173) en parallèle avec nettoyage propre
  (trap EXIT/INT/TERM). VITE_API_URL est injecté pour pointer vers
  Flask local, accessible depuis le client via tunnel SSH.
- docs/INSTALL_ROCKY.md : nouvelle section 16 avec schéma ASCII,
  procédure pas-à-pas et commande tunnel SSH exacte.
- docs/INSTALL_ROCKY.md : corrige les deux références cassées à
  vite.config.selfhost.ts (sections 9 et 15.1) supprimé lors de la
  dé-Replit-isation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:17:06 +02:00
billisdeadandClaude Sonnet 4.6 cf81ffa35e Suggestions : .env.example complet, page /consultations, fix set-domain.sh
- .env.example : variables à jour (Mistral, SECRET_KEY, ADMIN_SECRET, Redis,
  hCaptcha, anti-abus) — l'ancienne version référençait encore OpenAI uniquement
- Nouveau set-domain.sh : supprime la référence à vite.config.selfhost.ts supprimé
- Nouvelle page /consultations : index public des consultations actives/clôturées,
  toggle "afficher les clôturées", lien dans le footer
- App.tsx : route /consultations + lien footer Consultations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:02:00 +02:00
billisdeadandClaude Sonnet 4.6 fbc1fad8b9 P5 — Mode consultation ciblée (Option B, implémentation complète)
Backend :
- Nouvelle table `consultations` (slug unique, fenêtre temporelle, webhook, logo)
- `ideas.consultation_id` FK nullable (NULL = contexte global home)
- `synthesis.consultation_id` FK nullable (synthèse par contexte)
- Boucle auto-fermeture (thread daemon, 60 s) — ferme + webhook à l'échéance
- Webhook de clôture : POST JSON (synthèse + métadonnées) via urllib.request
- Routes publiques : GET/POST /api/consultations/<slug>, synthèse, contributions, export/print
- Routes admin : list, create, close (+ webhook), delete (cascade explicite)
- CSP ajustée sur /export/print pour autoriser window.print()

Frontend :
- Nouvelle page /consultation/:slug — formulaire, synthèse live, contributions paginées, PDF
- Admin panel : onglet Consultations — liste, formulaire création, fermeture, suppression

Docs : DAT.md v1.5, DEX.md v1.7 (section P5, tables, routes, webhook)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:00:39 +02:00
billisdeadandClaude Sonnet 4.6 bc6bd3f9d7 Dé-Replit-isation complète du projet
Supprimés :
- replit.md — doc Replit obsolète
- docs/GITEA_TUTO.md — tuto push Replit → Gitea (obsolète)
- artifacts/api-server/ — serveur TypeScript mort, remplacé par Flask
- artifacts/voix-du-peuple/vite.config.selfhost.ts — fusionné dans vite.config.ts

Nettoyés :
- ai_agent.py — fallback Replit AI supprimé (Mistral + OpenAI-compatible suffisent)
- vite.config.ts — plugins @replit/* retirés, PORT optionnel (défaut 5173)
- package.json + pnpm-workspace.yaml — @replit/* retirés du catalog et des deps
- badge.tsx + button.tsx — commentaires // @replit supprimés
- README.md, DEPLOIEMENT.md, DAT.md, DEX.md, WIKI.md — références Replit remplacées

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 22:41:06 +02:00
billisdeadandClaude Sonnet 4.6 a7b7684e87 Conformité RGPD (P3) + transparence éditoriale (P4)
P3 — RGPD :
- Table `consents` + `POST /api/consent` (art. 7.1 — preuve du consentement)
- Dialogue de consentement explicite avant la première contribution (art. 9.2.a)
- Pages `/mentions-legales` et `/politique-confidentialite`
- `docs/RGPD.md` — registre des traitements, bases légales, sous-traitants
- `getVisitorId()` exporté depuis l'API client React

P4 — Transparence éditoriale :
- Page `/contributions-brutes` avec pagination et export JSON/CSV
- `GET /api/contributions`, `GET /api/contributions/export/{json,csv}`
- `GET /api/stats/public` — stats publiques sans données de rejet
- Label de transparence IA sur la colonne de synthèse
- Compteurs (acceptées / soumises) dans le bandeau d'intro
- `docs/PROMPTS_IA.md` — prompts intégraux publiés + analyse des biais
- Pied de page avec liens légaux et transparence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 22:30:30 +02:00
billisdeadandClaude Sonnet 4.6 45edc1fa77 Licence EUPL-1.2 + hardening anti-abus
P1 — Licence :
- Ajout du fichier LICENSE (EUPL-1.2 complet)
- README mis à jour : section licence, table docs, vars d'environnement
- En-têtes EUPL ajoutés dans les fichiers sources principaux (Flask, React)

P2 — Hardening anti-abus :
- Rate limiting Redis-ready (REDIS_URL) avec clé fingerprint + IP
- Honeypot anti-bot : champ caché côté client + vérification serveur
- Fingerprinting non-PII via FingerprintJS (hash SHA-256, colonne ideas.fingerprint_hash)
- Cooldown session : cookie httpOnly signé HMAC-SHA256 (SECRET_KEY requis)
- Détection de flood : alerte WARNING si > FLOOD_THRESHOLD soumissions / 5 min
- hCaptcha stub : intégré, activable via HCAPTCHA_SECRET_KEY + VITE_HCAPTCHA_SITE_KEY
- Nouvelles dépendances : redis (backend), @fingerprintjs/fingerprintjs + @hcaptcha/react-hcaptcha (frontend)
- docs/SECURITE_ANTI_ABUS.md : documentation complète des seuils et de la configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:05:46 +02:00