# F3 Simple Blog Blog simple construit avec Fat-Free Framework et SQLite. Le projet vise un blog léger, lisible et facile à déployer, avec un petit back-office d’administration, une médiathèque locale et un rendu Markdown sécurisé. ## Fonctionnalités - listing public des articles avec pagination ; - page article ; - authentification admin ; - création, modification et suppression d’articles ; - médiathèque locale avec upload, texte alternatif, copie de la syntaxe Markdown et suppression ; - vignette de carte dérivée de la première image du contenu ; - rendu Markdown avec images locales `media:...` ; - stockage des images en **JPG/PNG bruts** sans transformation. ## Structure ```text project/ ├── app/ │ ├── bootstrap.php │ ├── config.ini │ ├── helpers.php │ ├── Controllers/ │ ├── Models/ │ ├── Services/ │ └── Views/ ├── db/ ├── logs/ ├── public/ │ ├── assets/ │ └── uploads/media/ ├── docker/ ├── scripts/ │ ├── bootstrap.php │ ├── install.php │ └── create-admin.php └── tmp/uploads/ ``` ## Architecture Le backend s’appuie sur un petit noyau : - `SiteController` : pages publiques ; - `AuthController` : connexion / déconnexion ; - `AdminController` : back-office articles et médiathèque ; - `Controller` : rendu, session courante, flash, CSRF ; - `Post`, `Media`, `User` : modèles `DB\SQL\Mapper` ; - `MarkdownService` : compilation et sanitation du contenu Markdown. ## Intégration F3 Le projet utilise directement les briques natives du framework : - routes et aliases dans `app/config.ini` ; - `DB\SQL\Mapper` pour les tables principales ; - `Auth` pour la connexion ; - `Session` pour la session ; - `Template` pour le rendu ; - `Web::receive()` pour la réception des uploads ; - `Markdown` pour le parsing Markdown ; - `Web::slug()` pour les slugs. ## Contenu et médiathèque Les articles ne possèdent pas de champ “image de couverture”. Les images vivent dans le corps Markdown, et la première image rendue dans `body_html` sert de vignette dans les cartes d’article. Les images du contenu utilisent la syntaxe : ```md ![Texte alternatif](media:nom-de-fichier.jpg) ``` La médiathèque : - accepte uniquement **JPG** et **PNG** ; - vérifie que le fichier reçu est bien une image ; - conserve le fichier tel quel, sans réencodage ; - stocke en base le nom du fichier, le texte alternatif, la largeur, la hauteur et la date de création. ## Contrat Markdown Le rendu Markdown suit les règles suivantes : - le HTML brut saisi par l’auteur n’est pas rendu ; - les liens sont filtrés avant rendu ; - seules les images locales en `media:...` sont rendues ; - les images externes ne sont pas affichées ; - avec le parseur Markdown de F3, il faut laisser une ligne vide entre deux blocs (titre, liste, citation, image, code) pour un rendu fiable. ## Sécurité Le projet inclut : - session d’administration ; - jeton CSRF sur les formulaires ; - rotation du jeton CSRF après connexion et déconnexion ; - sanitation du HTML produit à partir du Markdown ; - validation des uploads image ; - cookies `httponly` et `samesite=Lax`. ## Pré-requis ### Développement local - PHP 8.3+ - Composer - extensions PHP : `pdo_sqlite`, `mbstring`, `intl`, `dom` ### Déploiement Docker - Docker - Docker Compose ## Démarrage local ```bash composer install cp config.local.ini.example config.local.ini php scripts/install.php php -S 127.0.0.1:8080 -t public ``` Puis ouvrir `http://127.0.0.1:8080`. Créer un compte admin : ```bash php scripts/create-admin.php admin ``` ## Configuration Le fichier `app/config.ini` contient les valeurs par défaut. Tu peux les surcharger dans `config.local.ini`. Exemple minimal en production : ```ini [globals] app.env=prod app.timezone=Europe/Paris ``` Le paramètre `app.env` doit être forcé à `prod` sur un déploiement réel. ## Déploiement Docker derrière Caddy Le projet est prévu pour un déploiement simple : - Apache sert `public/` dans le conteneur ; - `compose.yaml` expose l’application sur `127.0.0.1:8888` par défaut ; - Caddy termine TLS et reverse-proxy vers cette cible ; - SQLite, les logs et les uploads sont montés sur des volumes persistants. Exemple : ```bash cp config.local.ini.example config.local.ini # édite config.local.ini : app.env=prod docker compose up -d --build ``` Le `Caddyfile.example` fournit une base de reverse proxy. En production, il faut exposer publiquement **Caddy uniquement**. L’application Apache/PHP ne doit pas être accessible directement depuis Internet. ## Sauvegarde Pour sauvegarder le blog, il faut au minimum conserver : - `db/app.sqlite` - `public/uploads/media/` Les logs peuvent aussi être conservés si tu veux garder l’historique d’erreurs. ## Limites assumées - base SQLite ; - instance applicative unique ; - pas de système de migrations automatique ; - en cas de changement de schéma, une migration manuelle ou une base recréée sera nécessaire.