Merci de l'intérêt que vous portez à Puna ! Ce guide explique comment contribuer au projet, que ce soit pour signaler un bug, proposer une fonctionnalité ou soumettre du code.
Avant tout, veuillez lire notre Code de Conduite. Toute participation implique d'en respecter les termes.
- Par où commencer ?
- Prérequis
- Installation pour le développement
- Architecture du projet
- Conventions de code
- Workflow Git
- Signaler un bug
- Proposer une fonctionnalité
- Soumettre une Pull Request
- Tests
- Scripts utilitaires
- Licence
Le projet est encore jeune et les issues taguées good first issue n'existent pas encore, elles apparaîtront naturellement au fil du temps.
En attendant, voici ce que vous pouvez faire dès maintenant :
- Tester l'installation sur votre environnement (natif ou Docker) et signaler tout ce qui coince
- Lire la documentation et ouvrir une issue si quelque chose est peu clair ou manquant
- Signaler un bug via le template d'issue prévu à cet effet
- Lire le code et poser des questions - une bonne question peut devenir une amélioration de doc
Si vous souhaitez contribuer du code sans savoir par où commencer, ouvrez une issue pour en discuter avant de vous lancer. C'est le meilleur moyen d'éviter un travail qui ne pourrait pas être mergé.
- Node.js 24+
- MariaDB 11+
- npm 10+
- Git
# 1. Forker le dépôt sur GitHub, puis cloner votre fork
git clone https://github.com/<votre-pseudo>/Puna.git
cd Puna
# 2. Générer le fichier .env (script interactif, aucune dépendance requise)
npm run setup
# 3. Installer les dépendances
npm install
# 4. Lancer le serveur en mode développement (rechargement automatique)
npm run devLe serveur démarre sur http://localhost:3022 (ou le port configuré dans votre .env).
npm run setup # Sélectionner le mode Docker quand demandé
docker compose up -dPuna est une application Node.js (ESM) avec Express 5, Sequelize (MariaDB) et des vues Handlebars.
graph TB
subgraph Client
Browser[Navigateur Web]
ExtApp[Application Externe]
AI[Agent IA]
end
subgraph Puna
direction TB
subgraph Web["Surface Web - SSR"]
Routes["Routes auto-chargées<br/>src/routes/*.routes.js"]
Controllers[Controllers]
Views[Vues Handlebars]
end
subgraph API["Surface API REST"]
ApiRoutes["Routes API auto-chargées<br/>src/api/v1/*.api.js"]
ApiMiddlewares["Pipeline Upload<br/>+ Auth 3 couches"]
end
subgraph MCP["Surface MCP"]
McpServer["Serveur MCP<br/>src/mcp/"]
end
Services["Services<br/>Logique métier"]
Models["Modèles Sequelize<br/>Déclaratifs JSON"]
end
subgraph Infra
DB[( MariaDB )]
Storage["storage/uploads/"]
ClamAV["ClamAV - Optionnel"]
SMTP["Serveur SMTP - Optionnel"]
end
Browser -->|Session + CSRF| Web
ExtApp -->|"X-KEY-PUNA + JWT"| API
AI -->|MCP Protocol| McpServer
Web --> Services
API --> Services
McpServer --> Services
Services --> Models
Models --> DB
Services --> Storage
ApiMiddlewares --> ClamAV
Services --> SMTP
helmet → cors(/api) → session → passport → flash → injectUserRole → csrfProtection → sanitize
| Surface | Préfixe | Auth |
|---|---|---|
| Web (SSR) | / |
Session + Passport |
| API public | /api/v1/… |
X-KEY-PUNA + Bearer JWT |
| Server MCP | /mcp/… |
Bearer JWT |
- Routes web : chaque fichier
src/routes/*.routes.jsest monté automatiquement. - Routes API : chaque fichier
src/api/v1/*.api.jsest monté sous/api/v1/<nom>. - Modèles : chaque
src/models/*.models.jsest chargé parsrc/models/index.js.
- Controllers (
src/controllers/) : gèrent le HTTP - lisentreq, appellent les services, redirigent ou rendent les vues. - Services (
src/services/) : contiennent toute la logique métier et les requêtes Sequelize. Ils retournent du JSON (model.toJSON()), jamais des instances Sequelize brutes.
Les modèles sont définis via des fichiers JSON, pas du code Sequelize manuel :
src/models/attributes/form.attributes.json ← définition des colonnes
src/models/relations/form.relations.json ← associations
src/models/form.models.js ← appelle le builder
Ne jamais écrire DataTypes.STRING directement dans un fichier de modèle.
- ESM uniquement (
import/export) - pas derequire()ni de CommonJS - Pas de
dotenv- les variables d'environnement sont chargées vianode --env-file=.env - Les fichiers sont servis directement, sans étape de build
npm run lint:fix # ESLint 9 flat config - corrige automatiquement
npm run format # Prettier (JS/JSON) + formateur HBS personnaliséLe projet utilise ESLint 9 avec une configuration eslint.config.js (flat config). Les règles sont déjà configurées - ne pas les modifier sans discussion préalable.
Tous les messages visibles par l'utilisateur doivent utiliser le système i18n :
- Dans les controllers/middlewares :
req.__('clé')oures.__('clé') - Dans les vues HBS :
{{__ "clé"}} - Les clés sont définies dans
src/locales/fr.json
Ne pas ajouter de chaînes françaises directement dans le code.
- Les clés cryptographiques viennent exclusivement des variables d'environnement
- Les accès aux données sont scopés via
getSiteWhereCondition()depuissrc/services/access.service.js- ne jamais hardcoder des conditions WHERE pour le contrôle d'accès - Les permissions sont définies dans
src/config/permissions.js
main → branche stable, protégée (merge via PR uniquement)
develop → branche de travail quotidien
feature/* → nouvelles fonctionnalités (créées depuis develop)
fix/* → corrections de bugs (créées depuis develop)
docs/* → documentation (créée depuis develop)
release/* → préparation d'une release (merge dans main + tag)
# 1. Se placer sur develop et mettre à jour
git checkout develop
git pull origin develop
# 2. Créer une branche
git checkout -b feature/ma-fonctionnalite
# 3. Développer, commiter (voir conventions ci-dessous)
git add .
git commit -m "feat(scope): description courte"
# 4. Pousser et ouvrir une PR vers develop
git push origin feature/ma-fonctionnaliteFormat : <type>(<scope>): <description>
| Type | Usage |
|---|---|
feat |
Nouvelle fonctionnalité |
fix |
Correction de bug |
docs |
Documentation uniquement |
test |
Ajout ou modification de tests |
chore |
Maintenance (dépendances, CI, config) |
refactor |
Refactoring sans changement fonctionnel |
style |
Formatage, espaces, points-virgules |
Exemples :
feat(auth): ajouter la validation du mot de passe fort
fix(site): corriger la vérification d'unicité du domaine
docs: mettre à jour le guide d'installation
test(service): ajouter les tests unitaires pour twoFactor
chore(deps): mettre à jour express vers 5.1.0
Règles :
- Description en minuscules, sans point final
- Temps présent à l'infinitif : "ajouter", "corriger", "mettre à jour"
- Longueur max de la ligne de sujet : 72 caractères
Utiliser le template d'issue "Bug report" sur GitHub. Remplir tous les champs obligatoires :
- Description claire et concise du problème
- Étapes de reproduction précises
- Comportement attendu vs comportement observé
- Mode d'installation (Docker ou natif), version de Node.js, OS
- Logs ou messages d'erreur le cas échéant
⚠️ Ne jamais signaler de faille de sécurité via une issue publique. Consulter SECURITY.md pour la procédure de divulgation responsable.
Utiliser le template d'issue "Demande de fonctionnalité" sur GitHub. Décrire :
- Le problème ou le besoin concret que la feature résoudrait
- La solution envisagée
- Les alternatives considérées et pourquoi elles ont été écartées
Les demandes sans contexte ou sans justification claire seront fermées.
Une CI automatique (lint + tests) se déclenche à l'ouverture de toute PR vers develop ou main.
Pour éviter des allers-retours inutiles, vérifiez en local au préalable :
npm run lint
npm run format:check
npm run test- La branche part de
developet la PR cibledevelop(jamaismaindirectement) -
npm run lintne remonte aucune erreur -
npm run format:checkne remonte aucune erreur -
npm run testpasse sans erreur - Les nouveaux messages utilisent i18n (pas de chaînes françaises en dur)
- Des tests sont ajoutés pour toute nouvelle fonctionnalité ou correction
- Utiliser le template de PR pré-rempli
- Lier l'issue correspondante avec
Closes #<numéro> - Décrire clairement les changements apportés
- Ajouter des captures d'écran pour les changements visuels
Les PRs nécessitent au moins une validation avant d'être mergées. La CI (lint + tests) doit être verte.
En tant que mainteneur solo, je m'efforce de répondre aux PRs dans un délai de 7 jours et de traiter les demandes de modification sous 30 jours. Ces délais sont donnés à titre indicatif et peuvent être dépassés selon les disponibilités. Les PRs sans réponse au-delà de 30 jours seront fermées mais pourront être rouvertes sur demande.
npm test # Exécution unique (Vitest)
npm run test:watch # Mode interactif
npm run test:coverage # Avec rapport de couverturetests/
├── unit/ # Tests unitaires (utils, services, helpers)
├── integration/ # Tests d'intégration (routes, pipeline API)
├── middlewares/ # Tests des middlewares
└── e2e/ # Tests end-to-end (Playwright)
- Framework : Vitest avec
globals: true - Toujours mocker ces trois modules dans les tests unitaires :
vi.mock('../../../src/config/logger.js', () => ({
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
}));
vi.mock('../../../src/models/index.js', () => ({
default: { MonModele: { findByPk: vi.fn() } },
}));
vi.mock('../../../src/utils/crypto.js', () => ({
encryptString: vi.fn((s) => `enc:${s}`),
decryptString: vi.fn((s) => s.replace('enc:', '')),
}));- Fichier de référence :
tests/unit/services/twoFactor.service.test.js - Les tests ne doivent pas dépendre d'une base de données réelle (utiliser des mocks Sequelize)
| Commande | Description |
|---|---|
npm run dev |
Démarrage avec rechargement automatique (--watch) |
npm start |
Démarrage en production |
npm run setup |
Génération interactive du fichier .env |
npm run prepare |
Installation des hooks Husky (git hooks) |
| Commande | Description |
|---|---|
npm run lint |
Vérification ESLint |
npm run lint:fix |
Correction automatique ESLint |
npm run format |
Formatage Prettier (JS, JSON) + HBS |
npm run format:hbs |
Formatage HBS uniquement |
npm run format:check |
Vérification du formatage (CI) |
| Commande | Description |
|---|---|
npm run logs:rotate |
Rotation manuelle des logs |
npm run logs:clean |
Nettoyage des archives de logs |
npm run logs:stats |
Statistiques et analyse des logs |
| Commande | Description |
|---|---|
npm run test:e2e:seed |
Seed de la base de test (Playwright) |
npm run test:coverage:badges |
Couverture + mise à jour des badges du README |
En contribuant à ce projet, vous acceptez que vos contributions soient publiées sous les termes de la licence GNU Affero General Public License v3.0 (AGPLv3) qui régit ce projet.