feat: initial API skeleton — routes, controllers, migrations, deploy docs

Implements the JSON API for Le Donut Infolab per INSTRUCTIONS.md.

Schema (migrations/001-002):
  - 8 tables: categories, members, projects, project_members, roadmap_steps,
    discussions, resources, activity_log
  - 6 categories seeded with colors / dimensions (social, ecologique, transversal)
  - FK contraintes + soft delete sur projects, CHECK sur progress_percent

Bare PHP framework (src/):
  - Front controller public/index.php + router :params + auth flag par route
  - PSR-4 autoload sans Composer (bootstrap.php)
  - Database PDO singleton + helpers fetchOne/All/insert/update/delete
  - Validator fluent -> 422 {error: validation_failed, fields: {...}}
  - Bearer token admin (hash_equals) sur POST/PATCH/DELETE
  - Slugger avec unicité (suffixe -2, -3...) via intl Transliterator
  - ActivityLogger best-effort sur activity_log
  - Erreurs uniformes : 400/401/404/405/409/422/500 + CORS configurable

10 contrôleurs (Health, Categories, Members, Projects, ProjectMembers,
Roadmap, Discussions, Resources, Activity, Stats). Transitions de statut
loggées (created_project, completed_step, joined, etc.).

Cible prod :
  - Dockerfile (php:8.3-apache + pdo_mysql + intl + opcache)
  - docker-compose.yml sur réseau donut-net, bind 127.0.0.1:8003
  - caddy.conf pour infolab.ledonut-marseille.org
  - migrations/apply.sh idempotent (table schema_migrations)
  - DEPLOY.md avec commandes SSH exactes

Tests :
  - tests/smoke.sh exerce 10 endpoints clés, body envoyé via stdin
    (--data-binary @-) pour gérer l UTF-8 sous Git Bash Windows.

Vérifié localement sous Laragon Apache + MySQL 8.4 : 10/10 OK + cas
négatifs (401, 404, 405, 409, 422) conformes au contrat.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 19:53:50 +02:00
parent 6679fa8b30
commit 3a32e93ab1
32 changed files with 3994 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
INSERT INTO categories (slug, name, description, color_hex, icon, dimension, sort_order) VALUES
('data-open-data', 'Data & Open Data', 'Projets autour de la donnée ouverte, de la médiation et de la littératie des données.', '#3B82F6', 'database', 'transversal', 10),
('democratie-citoyennete','Démocratie & Citoyenneté', 'Projets favorisant la participation citoyenne, la transparence et la gouvernance ouverte.', '#EF4444', 'users', 'social', 20),
('habitat-solidarite', 'Habitat & Solidarité', 'Projets autour du logement, de la fracture numérique et de la solidarité.', '#14B8A6', 'home', 'social', 30),
('territoire-urbanisme', 'Territoire & Urbanisme', 'Projets liés à l''aménagement du territoire, la renaturation et la vie locale.', '#F97316', 'map', 'transversal', 40),
('ecologie-biodiversite', 'Écologie & Biodiversité', 'Projets liés aux enjeux écologiques, à la biodiversité et à la nature en ville.', '#22C55E', 'leaf', 'ecologique', 50),
('education-ecoles', 'Éducation & Écoles', 'Projets autour de l''école publique, de la formation et de l''éducation aux données.', '#A855F7', 'graduation-cap','social', 60);