# 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`
  ```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:**
```dart
// 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:**
```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)
