Application de comptabilite pour association loi 1901 (non-profit). Construite avec Laravel 11, Livewire 4, et Bootstrap 5.
Licence : AGPL-3.0 — vous pouvez utiliser, modifier et redistribuer ce code, y compris pour heberger une instance accessible par reseau, a condition de publier vos modifications sous la meme licence.
Pour installer une instance en production, voir docs/INSTALL.md.
git clone <repo-url> && cd agora-gestion
composer install --no-dev --optimize-autoloader
cp .env.example .env && php artisan key:generate
# éditer .env (DB_*, MAIL_*, APP_URL)
php artisan migrate --forcePuis ouvrir l'URL de l'app dans un navigateur — la page /setup vous accueille pour créer le premier compte super-admin et la première association en un seul formulaire. Le wizard d'asso (8 étapes) prend ensuite le relais.
- PHP 8.4 + extensions standard (
pdo,mbstring,xml,dom,curl,zip,intl,bcmath) - Composer 2.x
- MySQL 8.0 / MariaDB 10.6+ ou SQLite (pour des essais rapides)
- Docker & Docker Compose (optionnel, uniquement si vous utilisez Laravel Sail — voir ci-dessous)
ℹ️ Pas de Node.js / npm requis : Bootstrap 5 et ses icônes sont chargés via CDN, il n'y a pas de build frontend.
git clone <repo-url> && cd agora-gestion
composer install
cp .env.example .env
php artisan key:generateSi vous avez Docker & Docker Compose installés, Sail vous fournit une stack PHP 8.4 + MySQL 8 + Redis prête à l'emploi sans rien installer sur votre machine :
./vendor/bin/sail up -d
./vendor/bin/sail artisan migrate:fresh --seedL'app tourne sur http://localhost.
Avec PHP 8.4 et MySQL/SQLite installés localement, configurez DB_* dans .env puis :
php artisan migrate:fresh --seed
php artisan serveL'app tourne sur http://localhost:8000. Pour le traitement en arrière-plan, lancer dans un autre terminal php artisan queue:listen (utile dès que vous activez la réception mail ou les rappels).
Si vous lancez migrate:fresh --seed, le DatabaseSeeder provisionne deux comptes de test pour explorer rapidement l'app :
| Mot de passe | Rôle | |
|---|---|---|
admin@monasso.fr |
password |
Admin (Marie Dupont) |
jean@monasso.fr |
password |
Utilisateur (Jean Martin) |
Le seeder crée aussi : 3 comptes bancaires, des catégories/sous-catégories, 2 opérations avec séances, des dépenses, recettes, membres, cotisations et dons.
ℹ️ Tester le parcours fresh install (pas de seeder) : lancer
php artisan migrate:fresh(sans--seed), puis ouvrirhttp://localhost→ l'app vous redirige automatiquement vers/setuppour créer le premier super-admin + association via formulaire web. C'est exactement ce qu'un nouvel utilisateur en prod expérimentera. LeDatabaseSeederest par ailleurs bloqué par un garde-fou enAPP_ENV=production.
- Livewire gere le rechargement automatique des composants cote serveur. Les changements dans les classes Livewire (
app/Livewire/) et leurs vues (resources/views/livewire/) sont pris en compte au prochain appel sans redemarrage. - Blade : les vues sont recompilees automatiquement a chaque requete en mode
APP_DEBUG=true. - Pas de build frontend : Bootstrap et Bootstrap Icons sont charges via CDN. Pas de Vite, pas de
npm installnecessaire.
L'exercice va du 1er septembre au 31 aout. L'exercice 2025 = sept 2025 a aout 2026. Toutes les requetes utilisent le scope forExercice(int $annee).
php artisan test # Tous les tests
php artisan test --coverage # Avec couverture
./vendor/bin/pint --test # Verifier le formatage PSR-12Les tests utilisent Pest PHP. Il y a des tests Feature (auth, CRUD), Unit (services), et Livewire (composants).
./vendor/bin/pint # Appliquer Laravel Pint (PSR-12)AgoraGestion expose un endpoint REST pour collecter les inscriptions newsletter envoyées par un site web vitrine. Pas de prestataire tiers : l'asso reste maître de ses données.
Un site appelant héberge un petit shim PHP (fourni dans clients/newsletter-php/) qui signe la requête HMAC-SHA256 et la relaie à AgoraGestion. Le secret HMAC ne quitte jamais le serveur du site appelant. Pas de CORS, pas de Cloudflare, pas de dépendance externe.
Navigateur → site vitrine (POST shim PHP) → AgoraGestion (HMAC verified) → buffer + email confirm
./vendor/bin/sail artisan newsletter:keys:create --association=<id> --label="Site vitrine prod"Le secret est affiché UNE SEULE FOIS lors de la création (stocké chiffré ensuite, irrécupérable).
Le dossier clients/newsletter-php/ contient un shim PHP réutilisable + sa documentation. Voir clients/newsletter-php/README.md.
Toute inscription crée une ligne pending dans newsletter_subscription_requests. Un email de confirmation contient un lien GET /newsletter/confirm/{token} (marque confirmed) et un lien GET /newsletter/unsubscribe/{token} (présent dès le 1er email, conformité RGPD).
L'import des demandes confirmées vers la table tiers (déduplication, fusion) est traité dans une PR ultérieure comme nouvel élément de la Boîte de réception unifiée.
https://github.com/jkurz78/www.soigner-vivre-sourire.fr
./vendor/bin/sail artisan newsletter:forget alice@example.frapp/
├── Enums/ # Valeurs typées PHP 8.2 (TypeTransaction, ModePaiement, StatutReglement, UsageComptable…)
├── Http/
│ ├── Controllers/ # PDFs, exports, auth, portail, pièces jointes
│ └── Requests/ # Validation des formulaires
├── Livewire/ # Composants réactifs (formulaires + listes + onglets)
├── Models/ # Modèles Eloquent (TenantModel pour les modèles multi-tenant)
├── Services/ # Logique métier (DB::transaction)
├── Support/ # Helpers (TenantUrl, LogContext, PdfFooterRenderer…)
├── Tenant/ # TenantContext + TenantScope fail-closed
└── View/Components/ # Composants Blade réutilisables
database/
├── migrations/ # Migrations Laravel + domaine (~100 fichiers)
├── seeders/ # Données de dev réalistes
└── factories/ # Factories pour les tests
resources/views/
├── layouts/ # app.blade.php (navbar Bootstrap)
├── livewire/ # Vues des composants Livewire
└── [modules]/ # Vues par module (tiers, transactions, dons, cotisations, budget…)
Controllers minces, Services epais : les controllers ne font que valider et deleguer aux services. Toute la logique metier vit dans app/Services/.
Requete → Controller (validation) → Service (logique + DB::transaction) → Response
Livewire pour l'interactivite : les formulaires dynamiques (lignes de depense, creation inline de donateur) et les listes avec recherche/filtre sont des composants Livewire full-page.
Route::view('/depenses', 'depenses.index') → <livewire:depense-list />
<livewire:depense-form />
Events Livewire : les composants communiquent par evenements (depense-saved, edit-depense).
Le modèle comptable a été unifié en v2.x autour de Transaction / TransactionLigne (plus de Depense/Recette/Don/Cotisation distincts).
Association (tenant) ──hasMany──→ Tiers, Transaction, NoteDeFrais, Operation, …
Tiers ──hasMany──→ Transaction, Adhesion, Participant, EmailLog, NoteDeFrais
Transaction (TypeTransaction: Depense|Recette) ──hasMany──→ TransactionLigne
TransactionLigne ──belongsTo──→ SousCategorie, Operation, Seance (optionnel)
──hasOne ──→ RecuFiscalEmis (pour les dons)
Categorie ──hasMany──→ SousCategorie
SousCategorie ──belongsToMany──→ UsageComptable (table pivot usages_sous_categories)
Operation ──hasMany──→ Seance, Participant
Participant ──hasMany──→ Reglement, Presence
Participant ──belongsTo──→ Tiers, Operation, refereParTiers, medecinTiers, therapeuteTiers
NoteDeFrais ──hasMany──→ NoteDeFraisLigne (avec strategy pattern par type)
Adhesion ──belongsTo──→ FormuleAdhesion, Tiers, Transaction (lien règlement)
Facture / Devis / RemiseBancaire / Extourne / Provision : modèles dédiés
PHP 8.2 enums dans app/Enums/. Principaux :
| Enum | Rôle |
|---|---|
TypeTransaction |
Depense, Recette |
ModePaiement |
Virement, Cheque, Especes, Cb, Prelevement, Helloasso |
StatutReglement |
Pointe, Recu, EnAttente, Rejete |
UsageComptable |
Don, Cotisation, Adhesion, AbandonCreance, … |
CategorieEmail |
Attestation, Recu, Message, Newsletter, … |
RoleSysteme |
SuperAdmin, Utilisateur |
StatutNoteDeFrais |
Brouillon, Soumise, Validee, Payee, Rejetee |
Voir le dossier complet pour les autres enums (statuts facture, devis, présence, type opération…).
Ce projet est concu pour etre developpe avec un assistant IA (Claude Code). Voici les regles a suivre.
declare(strict_types=1);en haut de chaque fichier PHPfinal classsauf si l'heritage est explicitement necessaire- Type hints sur tous les parametres et retours de methode
- PHP 8.2+ : utiliser readonly, enums, typed properties
- PSR-12 : lancer
./vendor/bin/pintavant chaque commit - Locale
fr: labels, messages de validation, et Faker en francais
- Migration :
php artisan make:migration create_xxx_table— verifier avecphp artisan migrate:status - Model :
php artisan make:model Xxx— ajouter relations, casts, scopes, fillable - Factory + Seeder : pour les donnees de test
- Service : creer
app/Services/XxxService.php— encapsuler la logique dansDB::transaction() - Livewire :
php artisan make:livewire XxxForm/XxxList— formulaire + liste - Vue Blade : creer la page dans
resources/views/xxx/index.blade.phpavec les composants Livewire - Route : ajouter dans
routes/web.phpsous le middlewareauth - Tests : ecrire les tests Pest (Feature + Livewire) — viser >85% de couverture
| Regle | Pourquoi |
|---|---|
| Pas de logique metier dans les controllers | Les controllers valident et delegent, c'est tout |
| Pas de requetes SQL brutes | Utiliser Eloquent + scopes. N+1 = eager loading avec ::with() |
| Transactions pour les ecritures multi-tables | DB::transaction() dans les services |
| SoftDeletes sur les modèles financiers | Transaction, TransactionLigne, NoteDeFrais, Adhesion, Devis, Facture, Operation… — ne jamais supprimer définitivement |
Scope forExercice(int) |
Toute requete liee a une periode doit filtrer par exercice (sept-aout) |
| Validation dans FormRequest | Pas de validation inline dans les controllers |
| Enums PHP pour les types fixes | ModePaiement, TypeCategorie, etc. — pas de strings magiques |
- Bootstrap 5 via CDN — pas de build frontend
- Bootstrap Icons pour les icones (
<i class="bi bi-xxx"></i>) - Livewire 4 pour l'interactivite — pas besoin de JavaScript custom
- Si du JS custom est necessaire, l'ajouter inline avec
@push('scripts')dans la vue
php artisan make:model Xxx -mf # Model + migration + factory
php artisan make:livewire XxxForm # Composant Livewire
php artisan make:request StoreXxxRequest # Form request
php artisan route:list --path=xxx # Verifier les routes
php artisan test --filter=Xxx # Tests cibles
php artisan migrate:fresh --seed # Reset complet
./vendor/bin/pint # Formatage PSR-12L'application peut recevoir automatiquement des documents PDF par email -- en particulier les feuilles d'emargement signees scannees par un copieur multifonction.
-
Extension PHP
imagick(disponible sur la plupart des hebergeurs Laravel, activable via le support ou cPanel si absente) -
Une boite mail dediee sur votre domaine (ex:
emargement@votreasso.fr) -
Le scheduler Laravel active dans cron :
* * * * * cd /chemin/vers/agora-gestion && php artisan schedule:run >> /dev/null 2>&1
- Se connecter en tant qu'admin
- Parametres -> Reception de documents par mail
- Onglet « Configuration IMAP » : saisir les credentials de la boite mail dediee
- Cliquer « Tester la connexion » pour verifier
- Onglet « Expediteurs autorises » : ajouter au moins l'adresse de votre copieur
- Retour onglet Configuration : activer l'ingestion
- Optionnel : lancer manuellement
php artisan incoming-mail:fetchpour un premier test
- Generer la feuille PDF dans l'application (onglet seances d'une operation)
- Imprimer la feuille -- elle contient un QR code unique en haut a droite
- Faire signer en seance
- Scanner la feuille (PDF, page 1 doit etre la feuille avec le QR)
- Envoyer le scan par mail depuis une adresse whitelistee a votre boite dediee
- Dans les 5 minutes, la feuille est automatiquement attachee a la bonne seance
Alternative : upload manuel depuis la vue seance (bouton « Attacher »).
Les PDFs qui n'ont pas de QR code valide (ou pas de QR du tout) atterrissent dans « Documents en attente » (menu principal). Un humain peut les attacher manuellement a la bonne seance.
Si la cle Laravel est rotee, le mot de passe IMAP stocke en base devient illisible. Il faudra le ressaisir dans la page Parametres apres rotation. Cette operation est rare (deja necessaire pour les session cookies, password reset tokens, etc.).