# PersoNotes REST API Documentation Version: **v1** Base URL: `http://localhost:8080/api/v1` ## Table des matières - [Vue d'ensemble](#vue-densemble) - [Commandes CLI](#commandes-cli) - [Authentification](#authentification) - [Formats de données](#formats-de-données) - [Endpoints](#endpoints) - [Lister les notes](#lister-les-notes) - [Récupérer une note](#récupérer-une-note) - [Créer/Mettre à jour une note](#créermettre-à-jour-une-note) - [Supprimer une note](#supprimer-une-note) - [Lister les notes publiques](#lister-les-notes-publiques) - [Basculer le statut public d'une note](#basculer-le-statut-public-dune-note) - [Notes publiques](#notes-publiques) - [Codes de statut HTTP](#codes-de-statut-http) - [Exemples d'utilisation](#exemples-dutilisation) --- ## Vue d'ensemble L'API REST de PersoNotes permet de gérer vos notes Markdown via HTTP. Elle supporte : - **Listage** : Récupérer la liste de toutes les notes avec métadonnées - **Lecture** : Télécharger une note en JSON ou Markdown brut - **Écriture** : Créer ou mettre à jour une note - **Suppression** : Supprimer une note définitivement ### Caractéristiques - ✅ **Versionnée** : `/api/v1` pour assurer la compatibilité future - ✅ **Content Negotiation** : Support JSON et Markdown selon le header `Accept` - ✅ **Idempotence** : PUT crée ou met à jour (idempotent) - ✅ **Automatisation** : Front matter géré automatiquement - ✅ **Ré-indexation** : Recherche mise à jour automatiquement après chaque modification - ✅ **Support sous-dossiers** : Organisation hiérarchique native --- ## Commandes CLI Le serveur inclut des commandes CLI intégrées pour gérer les notes publiques sans avoir à lancer le serveur HTTP. ### Lister les notes publiques Affiche toutes les notes qui ont été exportées en HTML public. **Commande** : ```bash ./server list-public [notes-dir] ``` **Arguments** : - `notes-dir` (optionnel) : Chemin vers le répertoire des notes (défaut: `./notes`) **Exemple de sortie** : ``` 📚 Notes publiques (4): • 2025 Learning Goals Source: personal/learning-goals.md Public: public/learning-goals.html Date: 2025-11-13 20:06:21 • AI Writing Assistant Source: archive/ai-assistant.md Public: public/ai-assistant.html Date: 2025-11-13 19:43:28 • API Endpoints Reference Source: documentation/api/endpoints.md Public: public/endpoints.html Date: 2025-11-13 19:36:57 • Product Backlog Source: tasks/backlog.md Public: public/backlog.html Date: 2025-11-13 20:13:05 ``` **Cas particuliers** : - Si aucune note n'est publique : affiche "Aucune note publique." - Si le fichier `.public.json` n'existe pas : affiche "Aucune note publique trouvée." - Erreur si le répertoire n'existe pas **Utilisation typique** : ```bash # Lister les notes publiques ./server list-public # Avec un répertoire personnalisé ./server list-public /path/to/notes # Compter les notes publiques (Linux/macOS) ./server list-public | grep -c "^•" # Exporter la liste dans un fichier ./server list-public > public-notes-list.txt ``` --- ## Authentification **Version actuelle : Aucune authentification requise** ⚠️ **IMPORTANT** : L'API n'a pas d'authentification. Si vous exposez le serveur publiquement : 1. Utilisez un reverse proxy (nginx, Caddy) avec authentification 2. Implémentez Basic Auth ou API Key 3. Utilisez un VPN ou tunnel SSH --- ## Formats de données ### Note complète (NoteResponse) ```json { "path": "projet/backend.md", "title": "Backend API", "content": "---\ntitle: Backend API\n...\n---\n\n# Content", "body": "\n# Content", "frontMatter": { "title": "Backend API", "date": "10-11-2025", "last_modified": "10-11-2025:14:30", "tags": ["projet", "backend"] }, "lastModified": "10-11-2025:14:30", "size": 1024 } ``` ### Métadonnées de note (NoteMetadata) ```json { "path": "projet/backend.md", "title": "Backend API", "tags": ["projet", "backend"], "lastModified": "10-11-2025:14:30", "date": "10-11-2025", "size": 1024 } ``` ### Requête de création/modification (NoteRequest) Deux options : **Option 1 : Content complet** (recommandé pour migration) ```json { "content": "---\ntitle: Ma note\ntags: [test]\n---\n\n# Contenu" } ``` **Option 2 : Body + FrontMatter séparés** (recommandé pour création) ```json { "body": "\n# Mon contenu\n\nTexte ici...", "frontMatter": { "title": "Ma note", "tags": ["test", "exemple"] } } ``` ### Erreur (ErrorResponse) ```json { "error": "Bad Request", "message": "Invalid path", "code": 400 } ``` --- ## Endpoints ### Lister les notes Récupère la liste de toutes les notes avec leurs métadonnées. **Endpoint** : `GET /api/v1/notes` **Paramètres** : Aucun **Réponse** : `200 OK` ```json { "notes": [ { "path": "projet/backend.md", "title": "Backend API", "tags": ["projet", "backend"], "lastModified": "10-11-2025:14:30", "date": "10-11-2025", "size": 1024 }, { "path": "daily/2025-11-10.md", "title": "Notes du 10 novembre", "tags": ["daily"], "lastModified": "10-11-2025:09:15", "date": "10-11-2025", "size": 2048 } ], "total": 2 } ``` **Exemple curl** : ```bash curl http://localhost:8080/api/v1/notes ``` --- ### Récupérer une note Télécharge une note spécifique. Le format dépend du header `Accept`. **Endpoint** : `GET /api/v1/notes/{path}` **Paramètres** : - `{path}` : Chemin relatif de la note (ex: `projet/backend.md`) **Headers** : - `Accept: application/json` (défaut) : Retourne JSON avec métadonnées - `Accept: text/markdown` : Retourne Markdown brut - `Accept: text/plain` : Retourne Markdown brut **Réponse JSON** : `200 OK` ```json { "path": "projet/backend.md", "title": "Backend API", "content": "---\ntitle: Backend API\ndate: 10-11-2025\nlast_modified: 10-11-2025:14:30\ntags:\n - projet\n - backend\n---\n\n# Backend API\n\nContenu de la note...", "body": "\n# Backend API\n\nContenu de la note...", "frontMatter": { "title": "Backend API", "date": "10-11-2025", "last_modified": "10-11-2025:14:30", "tags": ["projet", "backend"] }, "lastModified": "10-11-2025:14:30", "size": 1024 } ``` **Réponse Markdown** : `200 OK` ```markdown --- title: Backend API date: 10-11-2025 last_modified: 10-11-2025:14:30 tags: - projet - backend --- # Backend API Contenu de la note... ``` **Erreurs** : - `404 Not Found` : Note inexistante **Exemples curl** : ```bash # Récupérer en JSON curl http://localhost:8080/api/v1/notes/projet/backend.md \ -H "Accept: application/json" # Récupérer en Markdown brut curl http://localhost:8080/api/v1/notes/projet/backend.md \ -H "Accept: text/markdown" # Sauvegarder dans un fichier curl http://localhost:8080/api/v1/notes/projet/backend.md \ -H "Accept: text/markdown" \ -o backend.md ``` --- ### Créer/Mettre à jour une note Crée une nouvelle note ou met à jour une note existante (idempotent). **Endpoint** : `PUT /api/v1/notes/{path}` **Paramètres** : - `{path}` : Chemin relatif de la note (ex: `projet/nouvelle-note.md`) **Headers** : - `Content-Type: application/json` : Envoyer du JSON - `Content-Type: text/markdown` : Envoyer du Markdown brut **Body JSON** : ```json { "body": "\n# Ma nouvelle note\n\nContenu ici...", "frontMatter": { "title": "Ma nouvelle note", "tags": ["test", "exemple"] } } ``` Ou avec `content` complet : ```json { "content": "---\ntitle: Ma note\ntags: [test]\n---\n\n# Contenu" } ``` **Body Markdown brut** : ```markdown # Ma nouvelle note Contenu ici... ``` **Réponse** : `201 Created` (nouvelle note) ou `200 OK` (mise à jour) ```json { "path": "projet/nouvelle-note.md", "title": "Ma nouvelle note", "content": "---\ntitle: Ma nouvelle note\n...", "body": "\n# Ma nouvelle note\n\nContenu ici...", "frontMatter": { "title": "Ma nouvelle note", "date": "10-11-2025", "last_modified": "10-11-2025:14:35", "tags": ["test", "exemple"] }, "lastModified": "10-11-2025:14:35", "size": 256 } ``` **Comportement** : - ✅ Crée automatiquement les dossiers parents - ✅ Génère le front matter si absent - ✅ Met à jour `last_modified` automatiquement - ✅ Préserve `date` pour notes existantes - ✅ Ré-indexe automatiquement pour la recherche **Erreurs** : - `400 Bad Request` : Chemin invalide ou JSON malformé - `415 Unsupported Media Type` : Content-Type non supporté - `500 Internal Server Error` : Erreur d'écriture **Exemples curl** : ```bash # Créer avec JSON curl -X PUT http://localhost:8080/api/v1/notes/projet/test.md \ -H "Content-Type: application/json" \ -d '{ "body": "\n# Test\n\nCeci est un test.", "frontMatter": { "title": "Note de test", "tags": ["test"] } }' # Créer avec Markdown brut curl -X PUT http://localhost:8080/api/v1/notes/projet/simple.md \ -H "Content-Type: text/markdown" \ -d "# Simple note Contenu simple sans front matter." # Upload depuis un fichier curl -X PUT http://localhost:8080/api/v1/notes/projet/from-file.md \ -H "Content-Type: text/markdown" \ --data-binary @local-file.md ``` --- ### Supprimer une note Supprime définitivement une note. **Endpoint** : `DELETE /api/v1/notes/{path}` **Paramètres** : - `{path}` : Chemin relatif de la note (ex: `projet/old-note.md`) **Réponse** : `200 OK` ```json { "message": "Note deleted successfully", "path": "projet/old-note.md" } ``` **Erreurs** : - `404 Not Found` : Note inexistante - `500 Internal Server Error` : Erreur de suppression **Exemple curl** : ```bash curl -X DELETE http://localhost:8080/api/v1/notes/projet/old-note.md ``` --- ### Lister les notes publiques Récupère la liste des notes qui ont été publiées dans l'espace public. **Endpoint** : `GET /api/public/list` **Paramètres** : Aucun **Réponse** : `200 OK` ```json { "notes": [ { "path": "projet/backend.md", "title": "Backend API", "published_at": "2025-11-13T14:30:00Z" }, { "path": "personal/guide.md", "title": "Guide d'utilisation", "published_at": "2025-11-13T10:15:00Z" } ] } ``` **Champs retournés** : - `path` : Chemin relatif de la note source - `title` : Titre de la note - `published_at` : Date/heure de publication (format ISO 8601) **Notes** : - Les notes sont triées par date de publication (plus récentes d'abord) - Les fichiers HTML générés se trouvent dans `public/{nom-de-la-note}.html` - Liste vide si aucune note n'est publique **Exemple curl** : ```bash # Lister toutes les notes publiques curl http://localhost:8080/api/public/list # Avec formatage jq curl -s http://localhost:8080/api/public/list | jq '.notes[] | "\(.title) -> public/\(.path | split("/")[-1] | sub(".md$"; ".html"))"' ``` **Exemple de sortie formatée** : ```bash $ curl -s http://localhost:8080/api/public/list | jq '.notes[] | .title' "Backend API" "Guide d'utilisation" "Documentation projet" ``` **Compter les notes publiques** : ```bash curl -s http://localhost:8080/api/public/list | jq '.notes | length' ``` --- ### Basculer le statut public d'une note Publie ou retire une note de l'espace public. Génère automatiquement un fichier HTML statique exportable. **Endpoint** : `POST /api/public/toggle` **Content-Type** : `application/x-www-form-urlencoded` **Paramètres** : - `path` (form) : Chemin relatif de la note (ex: `projet/backend.md`) **Réponse** : `200 OK` ```json { "status": "public", "path": "projet/backend.md" } ``` Valeurs possibles pour `status` : - `"public"` : La note est maintenant publique (HTML généré) - `"private"` : La note est maintenant privée (HTML supprimé) **Comportement** : - ✅ **Génère du HTML statique** dans `public/nom-de-la-note.html` - ✅ **Copie les CSS** nécessaires dans `public/static/` - ✅ **Met à jour l'index** dans `public/index.html` - ✅ **Structure plate** : Tous les fichiers dans `public/`, pas de sous-dossiers - ✅ **Portable** : Les fichiers HTML peuvent être copiés sur n'importe quel serveur web **Fichiers générés** : ``` public/ ├── index.html # Liste de toutes les notes publiques ├── backend.md.html # Note convertie en HTML standalone ├── autre-note.html └── static/ ├── theme.css # Styles copiés └── themes.css ``` **Erreurs** : - `400 Bad Request` : Chemin manquant ou invalide - `404 Not Found` : Note inexistante - `405 Method Not Allowed` : Méthode autre que POST - `500 Internal Server Error` : Erreur de génération HTML **Exemple curl** : ```bash # Publier une note curl -X POST http://localhost:8080/api/public/toggle \ -d "path=projet/backend.md" # La note est maintenant accessible à : # http://localhost:8080/public/backend.html ``` **Exemple JavaScript** : ```javascript // Publier une note const response = await fetch('/api/public/toggle', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ path: 'projet/backend.md' }), }); const data = await response.json(); console.log(data.status); // "public" ou "private" ``` **Scripts utiles** : ```bash #!/bin/bash # Lister les notes publiques avec leurs URLs echo "📚 Notes publiques:" curl -s http://localhost:8080/api/public/list | jq -r '.notes[] | "• \(.title)\n → http://localhost:8080/public/\(.path | split("/")[-1] | sub(".md$"; ".html"))\n"' ``` ```bash #!/bin/bash # Exporter toutes les notes en HTML public echo "Exporting all notes to public HTML..." curl -s http://localhost:8080/api/v1/notes | jq -r '.notes[].path' | while read path; do curl -X POST http://localhost:8080/api/public/toggle -d "path=$path" > /dev/null 2>&1 echo "✓ Published: $path" done echo "" echo "✅ Export terminé!" echo "📊 Total: $(curl -s http://localhost:8080/api/public/list | jq '.notes | length') notes publiques" ``` ```bash #!/bin/bash # Retirer toutes les notes du public echo "Unpublishing all public notes..." curl -s http://localhost:8080/api/public/list | jq -r '.notes[].path' | while read path; do curl -X POST http://localhost:8080/api/public/toggle -d "path=$path" > /dev/null 2>&1 echo "✓ Unpublished: $path" done echo "✅ Toutes les notes sont maintenant privées" ``` --- ## Notes publiques Le système de notes publiques génère des fichiers HTML statiques exportables. Cette section explique comment utiliser ces fichiers. ### Accès aux notes publiques **Sur le serveur Personotes** : ``` http://localhost:8080/public/ ``` **Fichiers générés** : - `public/index.html` : Liste de toutes les notes publiques - `public/*.html` : Notes converties en HTML standalone - `public/static/` : CSS et assets ### Déploiement Les fichiers HTML sont complètement autonomes et peuvent être déployés sur : #### 1. Serveur web classique ```bash # Copier sur un serveur Apache/Nginx scp -r public/ user@server.com:/var/www/html/notes/ # Ou avec rsync rsync -av public/ user@server.com:/var/www/html/notes/ ``` **Configuration Nginx** : ```nginx server { listen 80; server_name notes.example.com; root /var/www/html/notes; index index.html; } ``` **Configuration Apache** : ```apache ServerName notes.example.com DocumentRoot /var/www/html/notes ``` #### 2. GitHub Pages (gratuit) ```bash cd public/ git init git add . git commit -m "Public notes" git remote add origin https://github.com/username/notes-public.git git push -u origin main # Activer GitHub Pages dans Settings → Pages → main branch # Vos notes seront accessibles à : # https://username.github.io/notes-public/ ``` #### 3. Netlify Drop 1. Allez sur https://app.netlify.com/drop 2. Glissez-déposez le dossier `public/` 3. Netlify génère automatiquement une URL #### 4. Vercel ```bash cd public/ npx vercel ``` ### Automatisation de l'export **Script de synchronisation** : ```bash #!/bin/bash # sync-public.sh - Synchroniser les notes publiques vers un serveur REMOTE_USER="user" REMOTE_HOST="server.com" REMOTE_PATH="/var/www/html/notes" rsync -av --delete public/ ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH} echo "✅ Notes publiques synchronisées !" ``` **Git Hook automatique** : ```bash # .git/hooks/post-commit #!/bin/bash # Si le dossier public/ a changé, synchroniser if git diff --name-only HEAD~1 | grep -q "^public/"; then ./sync-public.sh fi ``` ### Avantages - ✅ **Performance** : HTML pré-généré = chargement instantané - ✅ **Sécurité** : Fichiers statiques = surface d'attaque minimale - ✅ **Portabilité** : Fonctionne sur n'importe quel serveur web - ✅ **Gratuit** : Hébergement possible sur GitHub Pages, Netlify - ✅ **SEO** : HTML pré-rendu = indexation optimale par Google - ✅ **Pas de backend** : Pas besoin de Go sur le serveur de destination ### Limitations - ⚠️ **Noms uniques** : Si deux notes dans différents dossiers ont le même nom (ex: `personal/test.md` et `work/test.md`), elles s'écraseront car la structure est plate - ⚠️ **Republication manuelle** : Si vous modifiez une note déjà publique, vous devez la republier pour régénérer le HTML - ⚠️ **Pas de recherche** : Les fichiers HTML n'incluent pas de fonction de recherche (uniquement consultables) ### Documentation complète Pour plus d'informations sur l'export des notes publiques : - **QUICK_START_PUBLIC.md** : Guide de démarrage rapide - **EXPORT_GUIDE.md** : Guide complet de déploiement --- ## Codes de statut HTTP | Code | Signification | Description | |------|---------------|-------------| | `200` | OK | Requête réussie | | `201` | Created | Note créée avec succès | | `400` | Bad Request | Requête invalide (chemin, JSON, etc.) | | `404` | Not Found | Note inexistante | | `405` | Method Not Allowed | Méthode HTTP non supportée | | `415` | Unsupported Media Type | Content-Type non supporté | | `500` | Internal Server Error | Erreur serveur | --- ## Exemples d'utilisation ### Synchronisation de notes **Télécharger toutes les notes** : ```bash #!/bin/bash # Télécharger toutes les notes localement mkdir -p notes-backup # Récupérer la liste curl -s http://localhost:8080/api/v1/notes | jq -r '.notes[].path' | while read path; do # Créer les dossiers parents mkdir -p "notes-backup/$(dirname "$path")" # Télécharger la note curl -s http://localhost:8080/api/v1/notes/"$path" \ -H "Accept: text/markdown" \ -o "notes-backup/$path" echo "✓ Downloaded: $path" done echo "Backup terminé!" ``` **Uploader un dossier de notes** : ```bash #!/bin/bash # Uploader toutes les notes .md d'un dossier find ./my-notes -name "*.md" | while read file; do # Calculer le chemin relatif relpath="${file#./my-notes/}" # Upload curl -X PUT http://localhost:8080/api/v1/notes/"$relpath" \ -H "Content-Type: text/markdown" \ --data-binary @"$file" echo "✓ Uploaded: $relpath" done echo "Upload terminé!" ``` ### Recherche et filtrage **Lister toutes les notes avec un tag spécifique** : ```bash curl -s http://localhost:8080/api/v1/notes | \ jq '.notes[] | select(.tags | contains(["projet"])) | .path' ``` **Compter les notes par dossier** : ```bash curl -s http://localhost:8080/api/v1/notes | \ jq -r '.notes[].path' | \ xargs -n1 dirname | \ sort | uniq -c ``` ### Création automatique de notes **Note quotidienne** : ```bash #!/bin/bash # Créer une note quotidienne TODAY=$(date +%Y-%m-%d) TITLE="Notes du $(date +%d/%m/%Y)" curl -X PUT http://localhost:8080/api/v1/notes/daily/${TODAY}.md \ -H "Content-Type: application/json" \ -d "{ \"body\": \"\\n# ${TITLE}\\n\\n## Tasks\\n- [ ] TODO\\n\\n## Notes\\n\", \"frontMatter\": { \"title\": \"${TITLE}\", \"tags\": [\"daily\"] } }" echo "Note quotidienne créée: daily/${TODAY}.md" ``` ### Intégration avec d'autres outils **Exporter en HTML avec Pandoc** : ```bash curl -s http://localhost:8080/api/v1/notes/projet/doc.md \ -H "Accept: text/markdown" | \ pandoc -f markdown -t html -o doc.html echo "Exporté en HTML: doc.html" ``` **Recherche full-text avec jq** : ```bash # Chercher "API" dans tous les titres curl -s http://localhost:8080/api/v1/notes | \ jq '.notes[] | select(.title | contains("API"))' ``` ### Script de maintenance **Vérifier les notes sans tags** : ```bash curl -s http://localhost:8080/api/v1/notes | \ jq -r '.notes[] | select(.tags | length == 0) | .path' ``` **Statistiques** : ```bash #!/bin/bash # Afficher des statistiques sur les notes STATS=$(curl -s http://localhost:8080/api/v1/notes) TOTAL=$(echo "$STATS" | jq '.total') TOTAL_SIZE=$(echo "$STATS" | jq '[.notes[].size] | add') AVG_SIZE=$(echo "$STATS" | jq '[.notes[].size] | add / length | floor') echo "📊 Statistiques des notes" echo "========================" echo "Total de notes: $TOTAL" echo "Taille totale: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE)" echo "Taille moyenne: $(numfmt --to=iec-i --suffix=B $AVG_SIZE)" echo "" echo "Top 5 tags:" echo "$STATS" | jq -r '.notes[].tags[]' | sort | uniq -c | sort -rn | head -5 ``` --- ## Bonnes pratiques ### Sécurité 1. **Ne pas exposer publiquement sans authentification** 2. **Utiliser HTTPS en production** 3. **Valider les chemins côté client** (éviter `../` malveillants) 4. **Limiter la taille des uploads** (si nécessaire, ajouter un middleware) ### Performance 1. **Pagination** : L'API liste ne pagine pas actuellement (toutes les notes en une requête). Pour beaucoup de notes (>1000), envisager d'ajouter `?limit=` et `?offset=` 2. **Cache** : Utiliser un proxy cache (Varnish, nginx) pour GET 3. **Compression** : Activer gzip sur le reverse proxy ### Workflow recommandé 1. **Backup régulier** : Script cron qui télécharge toutes les notes 2. **Versioning Git** : Synchroniser le dossier de notes avec Git 3. **CI/CD** : Valider le format Markdown avec des linters 4. **Monitoring** : Logger les accès API pour audit --- ## Support et contribution - **Issues** : Rapporter les bugs sur GitHub - **Documentation** : Ce fichier (`API.md`) - **Code source** : `internal/api/rest_handler.go` --- ## Changelog ### v1 (2025-11-13) - ✨ Première version de l'API REST - ✅ Endpoints: LIST, GET, PUT, DELETE - ✅ Content negotiation JSON/Markdown - ✅ Support sous-dossiers - ✅ Gestion automatique du front matter - ✅ Ré-indexation automatique - ✅ Export de notes publiques en HTML statique (POST /api/public/toggle) --- **Note** : Cette API coexiste avec l'interface web HTML. Les deux peuvent être utilisées simultanément sans conflit.