# INVENTAIRE FONCTIONNEL DE JAMBO API **Projet** : Jambo API CMS **Référence** : CARTOGRAPHIE-FONCTIONNELLE-2026 **Objectif** : Établir la réalité opérationnelle de chaque fonctionnalité revendiquée dans le code et la documentation (`README.md`, `ROADMAP.md`). **Classification des états** : - **Opérationnelle et vérifiée** : Implémentation réelle, complète, testée et fonctionnelle de bout en bout. - **Partiellement opérationnelle** : Logique existante mais incomplète, dépendante de conditions spécifiques ou présentant des failles ciblées. - **Simulée / Factice** : Code de démonstration ou mock renvoyant des données fictives sans réaliser l'action annoncée. - **Défaillante** : Code présent mais bloqué par des erreurs fatales ou des incohérences de configuration. - **Absente** : Fonctionnalité annoncée dans la documentation mais inexistante dans le code source. --- ## TABLEAU RÉCAPITULATIF GLOBAL | ID | Module / Fonctionnalité | Point d'entrée | Dépendances externes | État réel | Problème majeur identifié | | :--- | :--- | :--- | :--- | :--- | :--- | | **MOD-01** | **Authentification Core CMS** | `POST /login`, `/logout` | Session PHP, MySQL | **Opérationnelle et vérifiée** | Requiert un compte préalable ; installation à froid bloquée. | | **MOD-02** | **Annuaire Utilisateurs CMS** | `GET|POST /api/users` | Doctrine ORM | **Défaillante / Faille** | Pas d'authentification sur `GET /api/users` (fuite PII totale). | | **MOD-03** | **Gestion des Rôles & Permissions** | `GET|POST /api/roles` | Doctrine ORM | **Défaillante / Faille** | Pas d'authentification sur `GET /api/roles` ni `/permissions`. | | **MOD-04** | **Assistant d'Installation Web** | `GET|POST /install` | `InstallController` | **Défaillante** | Non exempté de sécurité : redirige vers `/login` à froid. | | **MOD-05** | **Admin API (Tokens PAT)** | `/admin-api/v1/*` | Personal Access Token | **Partiellement opérationnelle** | Droit `VIEW` suffisant pour détruire des collections et projets. | | **MOD-06** | **Isolation Multi-Tenant** | Event `KernelEvents::REQUEST` | `EnsureProjectMemberSubscriber` | **Défaillante** | Biais d'isolation sur routes `{uuid}` au lieu de `{projectUuid}`. | | **MOD-07** | **Studio IA — Streaming Inline** | `POST /admin/api/content-ai/stream` | Provider LLM | **Simulée / Factice** | Découpe le texte client en paquets de 4 mots (`usleep 30ms`). N'appelle aucun LLM. | | **MOD-08** | **Studio IA — Génération Images** | `POST /studio/ai-generate-image` | DALL-E / Gemini | **Partiellement opérationnelle** | Appel `@file_get_contents` non assaini (risque SSRF/LFI). | | **MOD-09** | **Studio IA — Génération Schéma** | `POST /studio/ai-schema` | OpenAI / Anthropic / Gemini | **Opérationnelle et vérifiée** | Génération de structure JSON de collection opérationnelle. | | **MOD-10** | **Provider OAuth2 / IdP** | `/api/v1/projects/{uuid}/oauth/*` | EndUser JWT, PKCE | **Partiellement opérationnelle** | **Pas d'endpoint `/authorize`**. Flux `authorization_code` inutilisable. | | **MOD-11** | **Bac à sable Twig Hermétique** | Moteur Twig | `NativeTwigSecurityPolicy` | **Absente (en production)** | Classe créée mais jamais injectée dans Twig ni Symfony. | | **MOD-12** | **Publication de Sites Statiques** | `POST /studio/publish` | Filesystem local | **Défaillante / Faille P0** | Écriture arbitraire de fichiers via path traversal (`../../public`). | | **MOD-13** | **Serveur MCP (Agents IA)** | `POST /mcp`, `/api/projects/{uuid}/mcp` | Protocole JSON-RPC MCP | **Défaillante / Faille P0** | Accessible anonymement, fuite de tous les EndUsers et projets. | | **MOD-14** | **CDN & Transformation Images** | `GET /cdn/media/{uuid}` | Extension PHP GD | **Défaillante** | Nginx intercepte et renvoie 404 sur images non déjà en cache. | | **MOD-15** | **Répéteurs Relationnels (v1.20)** | Moteur EAV | `ContentFieldGroup` | **Simulée / Factice** | `ContentFieldGroup` non utilisé. L'API lit toujours des JSON blobs. | | **MOD-16** | **Moteur d'Automatisations (Flows)** | Événements `ContentEvent` | FlowInterpreter, Messenger | **Partiellement opérationnelle** | Exécution synchrone bloquante dans la requête HTTP client. | | **MOD-17** | **Recherche Fulltext & Vectorielle** | `GET /api/projects/{uuid}/search` | Index MySQL Fulltext | **Opérationnelle et vérifiée** | Requêtes MATCH AGAINST et filtres par locale opérationnels. | | **MOD-18** | **Génération Sitemap & Redirections** | `GET /{uuid}/sitemap.xml` | Doctrine ORM | **Opérationnelle et vérifiée** | XML conforme et résolution des règles de redirection. | | **MOD-19** | **Téléversement Direct Médias** | `POST /media/upload-url` | AWS S3 / Cloudflare R2 | **Opérationnelle et vérifiée** | Signatures d'URL pré-signées AWS S3 / R2 conformes. | | **MOD-20** | **Migrations Base de Données** | `doctrine:migrations:migrate` | Doctrine Migrations | **Défaillante** | Conflit fatal `Table 'form' already exists` bloquant toute base neuve. | | **MOD-21** | **Conteneurisation Docker** | `docker build .` | Dockerfile, Nginx, PHP-FPM | **Défaillante** | Build Docker échoue (lockfile Composer et warmup cache). | | **MOD-22** | **Script de Déploiement** | `python deploy.py` | SSH Paramiko | **Défaillante** | Simple `git pull` sans `composer install`, ni migrations, ni cache. | | **MOD-23** | **Paramètres Profil & Mot de passe** | `PUT /api/settings/password` | `UserPasswordHasherInterface` | **Défaillante** | Crashe en `TypeError` 500 sur appel non authentifié. | | **MOD-24** | **Pipeline CI/CD Automatisé** | `.github/workflows/*` | GitHub Actions | **Absente** | Annoncé en release `v1.26.0` mais physiquement supprimé du dépôt. | --- ## ANALYSE DÉTAILLÉE PAR MODULE ### 1. Authentification & Gestion des Utilisateurs (MOD-01, MOD-02, MOD-03) - **Objectif métier** : Permettre aux administrateurs de se connecter au back-office, gérer les comptes, créer des rôles et attribuer des permissions granulaires. - **Comportement attendu** : Authentification par formulaire avec hachage bcrypt/argon2id, contrôle d'accès strict sur l'annuaire des utilisateurs. - **Réalité de l'implémentation** : - La connexion par session fonctionne (`SecurityController.php`). - L'annuaire `GET /api/users` et les rôles `GET /api/roles` sont exposés sans authentification en raison de la directive `- { path: ^/api, roles: PUBLIC_ACCESS }` dans `security.yaml` et de l'absence de `#[IsGranted]` dans `UserController.php:26,115`. - **Statut** : **Défaillant / Faille de sécurité critique (SEC-003)**. --- ### 2. Isolation Multi-Tenant (MOD-06) - **Objectif métier** : Cloisonner strictement les projets pour empêcher tout utilisateur d'accéder aux données d'un autre tenant. - **Comportement attendu** : Tout accès à une ressource de projet est filtré par l'appartenance de l'utilisateur ou du token au projet spécifié. - **Réalité de l'implémentation** : - `EnsureProjectMemberSubscriber.php:37` lit `$request->attributes->get('projectUuid')`. - Plus de 15 routes fondamentales (GraphQL, Studio, Search, AI, MCP, EndUsers) déclarent le paramètre `{uuid}`. - `$projectUuid` est `null`, entraînant un `return` immédiat qui désactive le garde-fou. - **Statut** : **Défaillant / Biais d'isolation (SEC-005)**. --- ### 3. Assistant IA en Streaming (MOD-07) - **Objectif métier** : Fournir une assistance à la rédaction en streaming temps-réel (SSE) connectée aux modèles LLM. - **Comportement attendu** : Connexion à l'API OpenAI, Gemini ou Anthropic avec transmission continue des tokens au fur et à mesure de leur génération. - **Réalité de l'implémentation** : - Le contrôleur `src/Controller/Admin/ContentAiStreamController.php:58-79` n'appelle jamais le service IA injecté. - Il effectue `explode(' ', $text)` et `array_chunk($words, 4)` puis émet les mots saisis par l'utilisateur avec un `usleep(30000)`. - **Statut** : **Simulée / Factice (SIM-001)**. --- ### 4. Fournisseur d'Identité OAuth2 (MOD-10) - **Objectif métier** : Permettre aux applications tierces d'authentifier les utilisateurs finaux (EndUsers) via le protocole OAuth2 / OIDC avec PKCE. - **Comportement attendu** : Exposition des endpoints `/authorize`, `/token`, `/userinfo`, `/revoke`. - **Réalité de l'implémentation** : - Seuls `/token`, `/userinfo` et `/revoke` sont présents dans `ProjectOAuthController.php`. - L'endpoint fondamental `/authorize` est totalement absent. - La méthode `ProjectOAuthService::createAuthorizationCode()` n'est appelée que dans les tests unitaires. - **Statut** : **Partiellement opérationnelle / Inutilisable de bout en bout (SIM-003)**. --- ### 5. Publication de Sites Statiques (MOD-12) - **Objectif métier** : Permettre l'exportation et le déploiement d'un site statique généré pour un projet. - **Comportement attendu** : Écriture sécurisée des fichiers HTML/CSS/JS dans le dossier dédié au projet (`/public/sites/{uuid}/`). - **Réalité de l'implémentation** : - `src/Service/PublishedSiteStorage.php:30-35` concatène les chemins de fichiers sans vérifier la traversée de répertoire. - Des chemins contenant `../../` permettent d'écrire n'importe où sur le serveur web. - **Statut** : **Défaillante / Vulnérabilité d'exécution de code arbitraire (SEC-002)**. --- ### 6. Serveur MCP — Model Context Protocol (MOD-13) - **Objectif métier** : Permettre aux assistants IA (Claude Desktop, Cursor, IDEs) d'interagir avec le CMS via le protocole JSON-RPC MCP. - **Comportement attendu** : Authentification stricte via jeton de projet pour exécuter les outils d'inspection et de manipulation de données. - **Réalité de l'implémentation** : - L'URL `/api/projects/{uuid}/mcp` ne valide aucune authentification. - L'outil `list_end_users` exécute la requête Doctrine sans vérifier l'utilisateur dans le contexte. - L'outil `list_projects` sur `/mcp` liste tous les projets multi-tenants sans restriction. - **Statut** : **Défaillante / Faille d'exfiltration de données (SEC-004)**. --- ### 7. CDN & Transformation d'Images (MOD-14) - **Objectif métier** : Redimensionner, recadrer et convertir à la volée les images hébergées (`GET /cdn/media/{uuid}?w=800&fmt=webp`). - **Comportement attendu** : Servir le fichier depuis le cache s'il existe ; sinon, exécuter `ImageTransformController` via PHP pour générer la miniature. - **Réalité de l'implémentation** : - `docker/nginx.conf:24-27` déclare un `alias /app/public/uploads/media/cache/` avec `try_files $uri =404;`. - Nginx ne transfère jamais la requête à PHP si le fichier cache n'existe pas encore. - De plus, `ImageTransformController.php:41` cherche uniquement sur le disque local, rendant le CDN inopérant avec un stockage distant S3. - **Statut** : **Défaillante (OPS-003, OPS-006)**. --- ### 8. Répéteurs Relationnels (MOD-15) - **Objectif métier** : Stocker les champs répéteurs complexes en base relationnelle avec contraintes d'intégrité et clés étrangères. - **Comportement attendu** : Hydratation des entités `ContentFieldGroup` et `ContentFieldValue` reliées aux entrées de contenu. - **Réalité de l'implémentation** : - L'entité existe en base mais n'est manipulée par aucun contrôleur. - `EavDataFormatterService.php:135` lit directement `$fieldValue->jsonValue`. - Le service `ContentEntryService` annoncé n'existe pas. - **Statut** : **Simulée / Factice (SIM-002)**. --- ### 9. Migrations & Déploiement (MOD-20, MOD-21, MOD-22) - **Objectif métier** : Permettre l'installation automatisée et le déploiement continu du CMS. - **Comportement attendu** : Migrations idempotentes, build Docker reproductible, déploiement atomique. - **Réalité de l'implémentation** : - Deux migrations créent les mêmes tables (`Version20260624070523.php` et `Version20260629084616.php`), causant un crash fatal SQL sur base vierge. - `composer.lock` est désynchronisé (`composer install` échoue en non-interactif). - `deploy.py` fait un simple `git pull` sans migrer la base ni vider le cache. - **Statut** : **Défaillante (OPS-001, OPS-002, OPS-005)**.