- Config Spec-Kit pour Spec-Driven Development - CONSTITUTION.md + .specify/memory/constitution.md - Commandes Cursor /speckit.*, règles projet - Mission: associations + mutuelles d'épargne et de financement - .gitignore: versionner config spec-kit unionflow Made-with: Cursor
22 KiB
UnionFlow Project Constitution
Version: 1.0 Date: 2026-02-27 Status: Active Scope: Backend (unionflow-server-impl-quarkus), API (unionflow-server-api), Mobile (unionflow-mobile-apps)
🎯 Mission & Vision
Mission: Fournir une plateforme complète et sécurisée pour la gestion d'associations, clubs et organisations à but non lucratif, et pour la gestion des mutuelles d'épargne et de financement.
Vision: Architecture DDD stricte, séparation claire API/Implementation, conformité RGPD, et qualité industrielle (100% test coverage).
📐 Architecture Principles
1. Domain-Driven Design (DDD) - STRICT
1.1 Layered Architecture
┌─────────────────────────────────────────┐
│ Presentation Layer (Resources/API) │ ← JAX-RS REST endpoints
├─────────────────────────────────────────┤
│ Application Layer (Services) │ ← Business logic, transactions
├─────────────────────────────────────────┤
│ Domain Layer (Entities) │ ← Rich domain models
├─────────────────────────────────────────┤
│ Infrastructure Layer (Repositories) │ ← Data persistence (Panache)
└─────────────────────────────────────────┘
Rules:
- ✅ DO: Resources call Services, Services use Repositories
- ❌ DON'T: Resources directly access Repositories
- ❌ DON'T: Entities contain business logic beyond validation
- ✅ DO: All business logic lives in Services
1.2 Entity Pattern
- Base Class: All entities extend
BaseEntity@MappedSuperclass public abstract class BaseEntity { @Id UUID id; LocalDateTime dateCreation; LocalDateTime dateModification; String creePar; String modifiePar; Long version; // Optimistic locking Boolean actif; // Soft delete } - Lifecycle Hooks:
@PrePersist,@PreUpdatefor audit trail - Immutability: Use Lombok
@Builderfor construction - Validation: Jakarta Bean Validation annotations on fields
1.3 Repository Pattern
- Technology: Hibernate Panache
PanacheRepositoryBase<Entity, UUID> - Naming:
{Entity}Repository(e.g.,MembreRepository) - Custom Queries: Native queries for complex business logic
- Pagination: Use
PageandSortfrom Panache - No Logic: Repositories are ONLY for data access, no business rules
1.4 Service Pattern
- Naming:
{Domain}Service(e.g.,MembreService,CotisationService) - Transactions: All mutating methods MUST be
@Transactional - Logging: Use
Logger.getLogger(...)for all service operations - Error Handling: Throw domain exceptions (
NotFoundException,IllegalArgumentException) - Security: Inject
KeycloakServicefor authorization checks
2. API/Implementation Separation - MANDATORY
2.1 Module Structure
unionflow/
├── unionflow-server-api/ ← Pure Java 17, no dependencies
│ ├── dto/
│ │ ├── request/ ← Java records with validation
│ │ └── response/ ← Java records (immutable DTOs)
│ └── enums/ ← Rich enums with business methods
│
└── unionflow-server-impl-quarkus/ ← Quarkus 3.15.1 implementation
├── entity/ ← JPA entities
├── repository/ ← Panache repositories
├── service/ ← Business logic
├── resource/ ← JAX-RS endpoints
├── mapper/ ← MapStruct mappers
└── security/ ← Security config
2.2 API Module Rules
- ✅ DO: Use Java
recordfor all DTOs (request/response) - ✅ DO: Use
@Builderfrom Lombok for records - ✅ DO: Validation annotations (
@NotNull,@Size,@Pattern, etc.) - ❌ DON'T: Any runtime dependencies (no Quarkus, no JPA)
- ❌ DON'T: Mutable DTOs (records are immutable)
Example Request DTO:
@Builder
public record CreateMembreRequest(
@NotBlank @Size(max = 100) String nom,
@NotBlank @Size(max = 100) String prenom,
@Email String email,
@NotNull LocalDate dateNaissance
) {}
2.3 Impl Module Rules
- ✅ DO: Depend on
unionflow-server-apifor DTOs - ✅ DO: Use MapStruct for Entity ↔ DTO conversion
- ❌ DON'T: Return entities directly from Resources (always map to DTOs)
- ❌ DON'T: Accept entities in Resource methods (use DTOs)
3. Security - NON-NEGOTIABLE
3.1 Authentication & Authorization
- Provider: Keycloak 23+ (OIDC/OAuth2)
- Realm:
unionflow - Client:
unionflow-mobile(confidential) - Token Type: JWT (signed, encrypted)
3.2 JWT Validation Strategy
| Layer | Validation |
|---|---|
| Mobile | Issuer (iss) + Expiry (exp) |
| Backend | Signature verification + Claims extraction |
Rationale: Mobile cannot verify JWT signatures securely (no secret storage), so backend is authoritative for signature validation.
3.3 Role-Based Access Control (RBAC)
Defined Roles (in SecurityConfig.Roles):
ADMIN- Full system accessPRESIDENT- Organization managementVICE_PRESIDENT- Deputy authorityTRESORIER- Financial operationsSECRETAIRE- Administrative operationsGESTIONNAIRE_MEMBRE- Member managementORGANISATEUR_EVENEMENT- Event managementGESTIONNAIRE_SOLIDARITE- Solidarity aid managementAUDITEUR- Read-only audit accessMEMBRE- Basic member access
Permission Checks:
// In Services
if (!keycloakService.hasRole("ADMIN") &&
!keycloakService.hasRole("GESTIONNAIRE_MEMBRE")) {
throw new SecurityException("Insufficient permissions");
}
// In Resources
@RolesAllowed({"ADMIN", "TRESORIER"})
@GET
public Response getFinancialData() { ... }
3.4 RGPD Compliance
- Audit Trail: All entities track
creePar,modifiePar, dates - Soft Delete: Use
actif=falseinstead of hard deletes - Data Minimization: Only collect necessary fields
- Right to be Forgotten: Anonymization service (planned)
- Consent Management: Explicit opt-in for communications
3.5 Transport Security
- HTTPS Only: All external traffic via TLS 1.3+
- Certificate Management: Let's Encrypt + Cert-Manager (K8s)
- Ingress: nginx ingress controller with SSL termination
- Mobile:
network_security_config.xmlblocks cleartext HTTP
4. Data Management
4.1 Database Strategy
- Production: PostgreSQL 15+
- Testing: H2 in-memory
- Schema Management: Flyway migrations
- Connection Pooling: HikariCP (via Quarkus)
4.2 Migration Policy
- Versioning:
V{major}.{minor}__{description}.sql - Current:
V2.0__create_all_37_entities.sql - Rules:
- ❌ NEVER modify existing migrations
- ✅ Always create new migration for schema changes
- ✅ Test migrations on staging before production
- ✅ Migrations must be idempotent where possible
4.3 Primary Keys
- Type:
UUID(UUIDv4) - Generation: Database-generated (
gen_random_uuid()) - Foreign Keys: Always use UUIDs
- Rationale: Distributed system compatibility, no ID enumeration attacks
4.4 Optimistic Locking
- Field:
@Version Long versioninBaseEntity - Behavior: Automatic conflict detection on concurrent updates
- Exception:
OptimisticLockException→ HTTP 409 Conflict
5. Quality Assurance
5.1 Test Coverage Requirements
JaCoCo Thresholds (STRICT - NO EXCEPTIONS):
- ✅ Instructions: 100%
- ✅ Branches: 100%
- ✅ Lines: 100%
- ✅ Methods: 100%
Configuration:
<rules>
<rule><limits>
<limit><counter>INSTRUCTION</counter><minimum>1.00</minimum></limit>
<limit><counter>BRANCH</counter><minimum>1.00</minimum></limit>
<limit><counter>LINE</counter><minimum>1.00</minimum></limit>
<limit><counter>METHOD</counter><minimum>1.00</minimum></limit>
</limits></rule>
</rules>
<haltOnFailure>true</haltOnFailure>
Exclusions: NONE (including mappers, generated code)
5.2 Test Patterns
Service Tests:
@QuarkusTest
class MembreServiceTest {
@Inject MembreService service;
@BeforeEach
void setup() {
// Setup via service calls (own @Transactional)
}
@Test
@TestTransaction // Rollback after test
void testMethod() { ... }
}
Resource Tests:
@QuarkusTest
class MembreResourceTest {
@Test
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
void testEndpoint() {
given()
.when().get("/api/membres")
.then().statusCode(200);
}
}
Entity Tests:
class MembreTest {
@Test
void testPrePersist() {
Membre m = new Membre();
// Invoke @PrePersist via reflection
m.prePersist();
assertThat(m.getDateCreation()).isNotNull();
}
}
5.3 Test Organization
- Location:
src/test/javamirroringsrc/main/javastructure - Naming:
{ClassName}Test.java - DisplayName: French, descriptive (
@DisplayName("crée un membre valide")) - Assertions: AssertJ (
assertThat(...).isNotNull())
6. Configuration Management
6.1 Environment Profiles
| Profile | Purpose | DB | Keycloak | Logs |
|---|---|---|---|---|
| dev | Local development | H2 | localhost:8180 | Console |
| test | Automated tests | H2 | Mock (@TestSecurity) | Suppressed |
| staging | Pre-production | PostgreSQL | staging.lions.dev | File + Console |
| prod | Production | PostgreSQL | security.lions.dev | File only |
6.2 Configuration Hierarchy
1. application.properties (defaults)
2. application-{profile}.properties (overrides)
3. Environment variables (highest priority)
Example:
# application.properties
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/unionflow
# application-prod.properties
quarkus.datasource.jdbc.url=jdbc:postgresql://postgresql-service.postgresql.svc.cluster.local:5432/unionflow
# Environment variable (highest priority)
QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://custom-host:5432/unionflow
6.3 Secrets Management
- ❌ NEVER commit secrets to git
- ✅ Use environment variables for production secrets
- ✅ Use Kubernetes Secrets in K8s deployments
- ✅ Use
.envfiles locally (in.gitignore)
Example Kubernetes Secret:
apiVersion: v1
kind: Secret
metadata:
name: unionflow-secrets
type: Opaque
data:
keycloak-client-secret: <base64>
database-password: <base64>
7. Logging & Monitoring
7.1 Logging Standards
Levels:
ERROR: System failures requiring immediate attentionWARN: Recoverable errors, deprecated usageINFO: Business events (user login, payment, etc.)DEBUG: Detailed diagnostic info (dev/staging only)TRACE: Ultra-verbose (never in production)
Format:
LOG.infof("Membre créé: ID=%s, Email=%s", membre.getId(), membre.getEmail());
LOG.warnf("Tentative d'accès non autorisé: User=%s, Resource=%s", user, resource);
LOG.error("Erreur connexion base de données", exception);
7.2 Production Logging
- File:
/var/log/unionflow/app.log(rotated daily) - Console: Disabled in production
- JSON Format: For log aggregation (ELK stack)
- Sensitive Data: NEVER log passwords, tokens, personal data
7.3 Metrics & Health
- Endpoints:
/q/health- Health check/q/health/live- Liveness probe/q/health/ready- Readiness probe/q/metrics- Prometheus metrics
- K8s Probes: Configured for all 3 health endpoints
8. API Design
8.1 RESTful Conventions
| Method | Path | Purpose | Status |
|---|---|---|---|
GET |
/api/membres |
List all | 200 |
GET |
/api/membres/{id} |
Get one | 200 / 404 |
POST |
/api/membres |
Create | 201 |
PUT |
/api/membres/{id} |
Full update | 200 / 404 |
PATCH |
/api/membres/{id} |
Partial update | 200 / 404 |
DELETE |
/api/membres/{id} |
Soft delete | 204 / 404 |
8.2 Response Formats
Success (200/201):
{
"id": "uuid",
"nom": "Dupont",
"prenom": "Jean",
"email": "jean.dupont@example.com"
}
Error (4xx/5xx):
{
"timestamp": "2026-02-27T10:30:00Z",
"status": 404,
"error": "Not Found",
"message": "Membre non trouvé avec l'ID: {id}",
"path": "/api/membres/{id}"
}
8.3 Pagination
GET /api/membres?page=0&size=20&sort=nom,asc
Response Headers:
X-Total-Count: 150
Link: </api/membres?page=1&size=20>; rel="next"
8.4 Versioning
- Strategy: URL versioning (future)
- Current: No versioning (v1 implicit)
- Future:
/api/v2/membresfor breaking changes
9. Deployment & DevOps
9.1 Container Strategy
- Base Image:
registry.access.redhat.com/ubi9/openjdk-17-runtime:1.20 - Multi-stage Build: Maven build → JVM runtime
- Port: 8080 (internal), 443 (external via ingress)
- Healthcheck:
/q/health/liveevery 30s
9.2 Kubernetes Deployment
Namespace Strategy:
applications- User-facing apps (unionflow-server, lions-user-manager)infrastructure- Supporting services (postgresql, keycloak)monitoring- Observability (prometheus, grafana)
Resource Limits:
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
9.3 Deployment Pipeline (lionsctl)
lionsctl pipeline \
-u https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus \
-b main \
-j 17 \
-e production \
-c k1 \
-p prod
Steps:
- Clone from Gitea
mvn clean package -Pproddocker build -t registry.lions.dev/lionsdev/unionflow-server:{tag}docker push registry.lions.dev/lionsdev/unionflow-server:{tag}kubectl apply -f k8s/deployment.yaml- Health check validation
- Email notification
9.4 Rollback Strategy
- Version Tags: Every build tagged with git commit SHA
- Immutable Images: Never overwrite existing tags
- Rollback:
kubectl rollout undo deployment/unionflow-server
10. Code Conventions
10.1 Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Packages | dev.lions.unionflow.server.{layer} |
dev.lions.unionflow.server.service |
| Classes | PascalCase, singular | MembreService, Cotisation |
| Interfaces | No I prefix |
Repository, not IRepository |
| Methods | camelCase, verb-first | creerMembre(), trouverParId() |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_ATTEMPTS |
| Variables | camelCase | membre, listeMembres |
10.2 Language
- Code: English for technical terms (class names, method names)
- Business Domain: French (
Membre,Cotisation,Adhesion) - Comments/Javadoc: French
- Logs: French
- Git Commits: French
Rationale: Business domain in French for client alignment, technical terms in English for global compatibility.
10.3 Lombok Usage
Allowed:
@Data(entities)@Builder(DTOs, entities)@Getter/@Setter@NoArgsConstructor/@AllArgsConstructor@Slf4j(AVOID - use standard logger)
Forbidden:
@SneakyThrows(hides exceptions)@Cleanup(use try-with-resources)@val(use explicit types)
10.4 Code Formatting
- Indentation: 2 spaces (NOT tabs)
- Line Length: 120 characters max
- Braces: Always use braces, even for single-line if/for
- Import Order: java., javax., jakarta., org., dev.lions.*, (blank), static imports
11. Error Handling
11.1 Exception Hierarchy
RuntimeException
├── IllegalArgumentException (400 Bad Request)
├── NotFoundException (404 Not Found)
├── SecurityException (403 Forbidden)
├── IllegalStateException (409 Conflict)
└── UnsupportedOperationException (501 Not Implemented)
11.2 Exception Mapping
@Provider
public class GlobalExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception e) {
if (e instanceof NotFoundException) {
return Response.status(404).entity(error(e)).build();
}
// ... autres cas
return Response.status(500).entity(error(e)).build();
}
}
11.3 Validation Errors
@POST
public Response create(@Valid CreateMembreRequest request) {
// Validation automatique par Jakarta Bean Validation
// 400 Bad Request si validation échoue
}
12. Performance
12.1 Database Performance
- Indexes: On all foreign keys, frequently queried columns
- N+1 Queries: Use
@EntityGraphor JOIN FETCH - Pagination: ALWAYS paginate large result sets
- Connection Pool: Min 5, Max 20 connections
12.2 Caching Strategy
- Level 1 Cache: Hibernate session cache (automatic)
- Level 2 Cache: Disabled (stateless REST API)
- Application Cache: Caffeine for frequently accessed data (ex: roles, permissions)
- HTTP Cache:
Cache-Controlheaders for static resources
12.3 Query Optimization
// ❌ BAD - N+1 queries
List<Membre> membres = membreRepository.findAll();
membres.forEach(m -> m.getCotisations().size()); // Lazy load
// ✅ GOOD - Single query with JOIN FETCH
@Query("SELECT m FROM Membre m LEFT JOIN FETCH m.cotisations")
List<Membre> findAllWithCotisations();
13. Mobile Integration
13.1 Mobile App Configuration
Flutter Environment:
// lib/config/environment.dart
abstract class AppConfig {
static String get apiBaseUrl => const String.fromEnvironment('API_URL');
static String get keycloakUrl => const String.fromEnvironment('KEYCLOAK_URL');
static bool get enableLogging => const String.fromEnvironment('ENV') != 'prod';
}
Build Command:
flutter build apk \
--dart-define=ENV=prod \
--dart-define=API_URL=https://api.lions.dev \
--dart-define=KEYCLOAK_URL=https://security.lions.dev
13.2 OAuth2 Flow (Mobile)
1. App → Keycloak: Authorization request
2. User authenticates in browser
3. Keycloak → App: Authorization code (via deep link)
4. App → Backend: Exchange code for tokens
5. Backend validates, returns JWT
6. App stores JWT securely (flutter_secure_storage)
13.3 Deep Link Configuration
- Scheme:
dev.lions.unionflow-mobile:// - Callback:
dev.lions.unionflow-mobile://callback - Android: Handled via
network_security_config.xml - iOS: Handled via
Info.plist
14. Change Management
14.1 Git Workflow
- Branches:
main(production),develop(integration),feature/*,fix/* - Commits: Conventional Commits format
type(scope): description [optional body] Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> - Types:
feat,fix,docs,refactor,test,chore - PR Required: All merges to
mainrequire PR + review
14.2 Database Migrations
Process:
- Create migration:
V{version}__{description}.sql - Test locally on H2
- Test on staging PostgreSQL
- Include in PR for review
- Deploy to production with rollback plan
14.3 Breaking Changes
Definition: Changes that break existing API contracts
- ❌ Removing fields from DTOs
- ❌ Changing field types
- ❌ Removing endpoints
- ❌ Changing authentication flow
Mitigation:
- Version the API (
/api/v2/...) - Deprecate old version with 6-month sunset
- Communicate to mobile team 3 months in advance
15. Documentation
15.1 Required Documentation
- ✅ OpenAPI/Swagger: Auto-generated from JAX-RS annotations
- ✅ Javadoc: All public methods in Services
- ✅ README.md: Per-module setup instructions
- ✅ CONSTITUTION.md: This document
- ✅ CHANGELOG.md: Release notes
15.2 API Documentation
Access: https://api.lions.dev/unionflow/q/swagger-ui
Annotations:
@Path("/membres")
@Tag(name = "Membres", description = "Gestion des membres")
public class MembreResource {
@GET
@Operation(summary = "Liste tous les membres")
@APIResponse(responseCode = "200", description = "Succès")
public Response list() { ... }
}
16. Compliance & Governance
16.1 RGPD Requirements
- Data Minimization: Only collect necessary data
- Purpose Limitation: Use data only for stated purposes
- Storage Limitation: Delete data after retention period
- Accuracy: Allow users to update their data
- Integrity: Encrypt data at rest and in transit
- Confidentiality: Role-based access control
16.2 Audit Trail
Tracked Fields:
creePar- User who created the recordmodifiePar- User who last modifieddateCreation- Creation timestampdateModification- Last modification timestamp
Retention: 7 years minimum (legal requirement for associations)
16.3 Data Retention Policy
| Data Type | Retention Period | Action After |
|---|---|---|
| Member Data | Active + 2 years | Anonymize |
| Financial Records | 10 years | Archive |
| Audit Logs | 7 years | Archive |
| Session Tokens | 24 hours | Delete |
🔄 Amendment Process
This constitution is a living document. Amendments require:
- Proposal: Submit PR with changes to
CONSTITUTION.md - Discussion: Team review (minimum 3 business days)
- Approval: Unanimous approval from tech leads
- Implementation: Update dependent documentation
- Communication: Announce changes to all teams
Version History:
- v1.0 (2026-02-27): Initial constitution
📞 Contacts & Resources
- Tech Lead: [À définir]
- Repository:
https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus - Documentation:
https://docs.lions.dev/unionflow - Deployment Tool:
lionsctl(lions-infrastructure-2025/lionsctl/) - Support:
support@lions.dev
Last Updated: 2026-02-27 Next Review: 2026-05-27 (quarterly review)