- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
731 lines
23 KiB
Markdown
731 lines
23 KiB
Markdown
# UnionFlow Project Constitution
|
||
|
||
> **Version:** 1.0
|
||
> **Date:** 2026-03-08
|
||
> **Status:** Active
|
||
> **Scope:** Backend (unionflow-server-impl-quarkus), API (unionflow-server-api), Mobile (unionflow-mobile-apps)
|
||
> **Référence inventaire:** `.specify/memory/inventaire-code.md` — liste exacte des packages, migrations et features (à utiliser pour ne pas halluciner). **En cas de divergence entre ce document et le code source, le code fait foi** ; l’inventaire et la constitution doivent être mis à jour pour refléter l’état réel du dépôt.
|
||
|
||
---
|
||
|
||
## 🎯 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`
|
||
```java
|
||
@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`, `@PreUpdate` for audit trail
|
||
- **Immutability**: Use Lombok `@Builder` for 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 `Page` and `Sort` from 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 `KeycloakService` for 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 `record` for all DTOs (request/response)
|
||
- ✅ **DO**: Use `@Builder` from 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:**
|
||
```java
|
||
@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-api` for 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`):
|
||
1. `ADMIN` - Full system access
|
||
2. `PRESIDENT` - Organization management
|
||
3. `VICE_PRESIDENT` - Deputy authority
|
||
4. `TRESORIER` - Financial operations
|
||
5. `SECRETAIRE` - Administrative operations
|
||
6. `GESTIONNAIRE_MEMBRE` - Member management
|
||
7. `ORGANISATEUR_EVENEMENT` - Event management
|
||
8. `GESTIONNAIRE_SOLIDARITE` - Solidarity aid management
|
||
9. `AUDITEUR` - Read-only audit access
|
||
10. `MEMBRE` - Basic member access
|
||
|
||
**Permission Checks**:
|
||
```java
|
||
// 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=false` instead 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.xml` blocks 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 version` in `BaseEntity`
|
||
- **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:**
|
||
```xml
|
||
<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:**
|
||
```java
|
||
@QuarkusTest
|
||
class MembreServiceTest {
|
||
@Inject MembreService service;
|
||
|
||
@BeforeEach
|
||
void setup() {
|
||
// Setup via service calls (own @Transactional)
|
||
}
|
||
|
||
@Test
|
||
@TestTransaction // Rollback after test
|
||
void testMethod() { ... }
|
||
}
|
||
```
|
||
|
||
**Resource Tests:**
|
||
```java
|
||
@QuarkusTest
|
||
class MembreResourceTest {
|
||
@Test
|
||
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||
void testEndpoint() {
|
||
given()
|
||
.when().get("/api/membres")
|
||
.then().statusCode(200);
|
||
}
|
||
}
|
||
```
|
||
|
||
**Entity Tests:**
|
||
```java
|
||
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/java` mirroring `src/main/java` structure
|
||
- **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:**
|
||
```properties
|
||
# 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 `.env` files locally (in `.gitignore`)
|
||
|
||
**Example Kubernetes Secret:**
|
||
```yaml
|
||
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 attention
|
||
- `WARN`: Recoverable errors, deprecated usage
|
||
- `INFO`: Business events (user login, payment, etc.)
|
||
- `DEBUG`: Detailed diagnostic info (dev/staging only)
|
||
- `TRACE`: Ultra-verbose (never in production)
|
||
|
||
**Format:**
|
||
```java
|
||
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):**
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"nom": "Dupont",
|
||
"prenom": "Jean",
|
||
"email": "jean.dupont@example.com"
|
||
}
|
||
```
|
||
|
||
**Error (4xx/5xx):**
|
||
```json
|
||
{
|
||
"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/membres` for 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/live` every 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:**
|
||
```yaml
|
||
resources:
|
||
requests:
|
||
memory: "512Mi"
|
||
cpu: "250m"
|
||
limits:
|
||
memory: "1Gi"
|
||
cpu: "1000m"
|
||
```
|
||
|
||
#### 9.3 Deployment Pipeline (lionsctl)
|
||
```bash
|
||
lionsctl pipeline \
|
||
-u https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus \
|
||
-b main \
|
||
-j 17 \
|
||
-e production \
|
||
-c k1 \
|
||
-p prod
|
||
```
|
||
|
||
**Steps:**
|
||
1. Clone from Gitea
|
||
2. `mvn clean package -Pprod`
|
||
3. `docker build -t registry.lions.dev/lionsdev/unionflow-server:{tag}`
|
||
4. `docker push registry.lions.dev/lionsdev/unionflow-server:{tag}`
|
||
5. `kubectl apply -f k8s/deployment.yaml`
|
||
6. Health check validation
|
||
7. 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
|
||
```java
|
||
@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
|
||
```java
|
||
@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 `@EntityGraph` or 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-Control` headers for static resources
|
||
|
||
#### 12.3 Query Optimization
|
||
```java
|
||
// ❌ 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:** Configuration centralisée dans `unionflow-mobile-apps/lib/core/config/environment.dart`. `AppConfig.initialize()` appelé dans `main()` ; `Environment` (dev, staging, prod) ; propriétés : `apiBaseUrl`, `keycloakBaseUrl`, `wsBaseUrl`, `enableLogging`, `keycloakRealmUrl`, `keycloakTokenUrl`, `wsDashboardUrl`. Valeurs par défaut selon l’environnement (dev : localhost:8085 / 8180, prod : api.lions.dev / security.lions.dev).
|
||
|
||
**Build Command:**
|
||
```bash
|
||
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 `main` require PR + review
|
||
|
||
#### 14.2 Database Migrations
|
||
**Process:**
|
||
1. Create migration: `V{version}__{description}.sql`
|
||
2. Test locally on H2
|
||
3. Test on staging PostgreSQL
|
||
4. Include in PR for review
|
||
5. 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:**
|
||
1. Version the API (`/api/v2/...`)
|
||
2. Deprecate old version with 6-month sunset
|
||
3. 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:**
|
||
```java
|
||
@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 record
|
||
- `modifiePar` - User who last modified
|
||
- `dateCreation` - Creation timestamp
|
||
- `dateModification` - 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:
|
||
|
||
1. **Proposal**: Submit PR with changes to `CONSTITUTION.md`
|
||
2. **Discussion**: Team review (minimum 3 business days)
|
||
3. **Approval**: Unanimous approval from tech leads
|
||
4. **Implementation**: Update dependent documentation
|
||
5. **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)
|