191 lines
5.2 KiB
Markdown
191 lines
5.2 KiB
Markdown
# 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
|
||

|
||
```
|
||
|
||
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
|
||
```
|
||
|
||
Créer un compte admin dans le conteneur :
|
||
|
||
```bash
|
||
docker compose exec app php scripts/create-admin.php admin
|
||
```
|
||
|
||
Le script te demandera ensuite le mot de passe du compte.
|
||
|
||
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.
|