Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"run",
"integ"
],
"envFile": "${workspaceFolder}/apps/server/.integ.env",
"console": "integratedTerminal",
"restart": true,
"presentation": {
Expand All @@ -38,6 +39,7 @@
"run",
"dev"
],
"envFile": "${workspaceFolder}/apps/server/.env",
"console": "integratedTerminal",
"restart": true,
"presentation": {
Expand Down Expand Up @@ -100,6 +102,7 @@
"run",
"start:dev"
],
"envFile": "${workspaceFolder}/apps/server-nestjs/.integ.env",
"console": "integratedTerminal",
"restart": true,
"presentation": {
Expand All @@ -122,6 +125,7 @@
"run",
"start:dev"
],
"envFile": "${workspaceFolder}/apps/server-nestjs/.env",
"console": "integratedTerminal",
"restart": true,
"presentation": {
Expand Down Expand Up @@ -164,16 +168,14 @@
"8080",
"--strictPort"
],
"envFile": "${workspaceFolder}/apps/client/.integ.env",
"console": "integratedTerminal",
"restart": true,
"serverReadyAction": {
"pattern": "Local:.*(http://localhost:[0-9]+)",
"action": "startDebugging",
"name": "Launch Client (Chrome)"
},
"env": {
"SERVER_PORT": "4001"
},
"presentation": {
"hidden": true
}
Expand All @@ -194,6 +196,7 @@
"8080",
"--strictPort"
],
"envFile": "${workspaceFolder}/apps/client/.env",
"console": "integratedTerminal",
"restart": true,
"serverReadyAction": {
Expand Down Expand Up @@ -221,6 +224,7 @@
"8080",
"--strictPort"
],
"envFile": "${workspaceFolder}/apps/client/.integ.env",
"console": "integratedTerminal",
"restart": true,
"serverReadyAction": {
Expand Down Expand Up @@ -248,6 +252,7 @@
"8080",
"--strictPort"
],
"envFile": "${workspaceFolder}/apps/client/.env",
"console": "integratedTerminal",
"restart": true,
"serverReadyAction": {
Expand Down
9 changes: 9 additions & 0 deletions apps/client/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if [ "$INTEGRATION" = true ]; then
dotenv .env.integ
elif [ "$DOCKER" = true ]; then
dotenv .env.docker
else
dotenv
fi

source_up
12 changes: 6 additions & 6 deletions apps/client/src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
export const serverHost: string = process.env.SERVER_HOST ?? 'dso-server-host'

export const serverPort: string = process.env.SERVER_PORT ?? 'dso-server-port'
export const serverPort: string = '4001'

export const clientPort: string = process.env.CLIENT_PORT ?? 'dso-client-port'

export const keycloakProtocol: string = process.env.KEYCLOAK_PROTOCOL ?? 'dso-keycloak-protocol'
export const keycloakProtocol: string = 'https'

export const keycloakDomain: string = process.env.KEYCLOAK_DOMAIN ?? 'dso-keycloak-domain'
export const keycloakDomain: string = 'keycloak.dso.cpin-hp.numerique-interieur.fr'

export const keycloakRealm: string = process.env.KEYCLOAK_REALM ?? 'dso-keycloak-realm'
export const keycloakRealm: string = 'dso'

export const keycloakClientId: string = process.env.KEYCLOAK_CLIENT_ID ?? 'dso-keycloak-client-id'
export const keycloakClientId: string = 'console-frontend'

export const keycloakRedirectUri: string = process.env.KEYCLOAK_REDIRECT_URI ?? 'dso-keycloak-redirect-uri'
export const keycloakRedirectUri: string = 'http://localhost:8080'

export const contactEmail: string = process.env.CONTACT_EMAIL ?? 'cloudpinative-relations@interieur.gouv.fr'

Expand Down
9 changes: 9 additions & 0 deletions apps/nginx-strangler/conf.d/routing.conf
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api/v1/projects {
proxy_pass http://server-nestjs;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# ── Routes par défaut (pour l'instant dans le legacy) ─────────────────────────
location /api/ {
proxy_pass http://server-legacy;
Expand Down
9 changes: 9 additions & 0 deletions apps/server-nestjs/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if [ "$INTEGRATION" = true ]; then
dotenv .env.integ
elif [ "$DOCKER" = true ]; then
dotenv .env.docker
else
dotenv
fi

source_up
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ Plus le score est eleve, plus le module est prioritaire.
| 13 | zone | Metier | 6.4 | V2 | S6 | |
| 14 | environment | Metier | 6.3 | V3 | S7 | |
| 15 | admin-role | Metier | 6.1 | V2 | S5 | |
| 16 | project-core | Metier | 5.8 | V4 | S9 | |
| 17 | service-chain | Metier | 5.9 | V3 | S8 | ✅ MIGRE |
| 16 | project-core | Metier | 5.8 | V4 | S9 | ✅ MIGRÉ (2026-05-28) |
| 17 | service-chain | Metier | 5.9 | V3 | S8 | ✅ MIGRÉ (2026-04-09) |
| 18 | repository | Metier | 5.8 | V3 | S7-S8 | |
| 19 | cluster | Metier | 5.7 | V3 | S7 | |
| 20 | harbor (encapsulation) | Plugin | 5.6 | V4 | S9-S10 | ✅ MIGRE |
Expand All @@ -206,8 +206,8 @@ Plus le score est eleve, plus le module est prioritaire.
| 23 | project-role | Metier | 5.2 | V3 | S7-S8 | |
| 24 | nexus (encapsulation) | Plugin | 5.1 | V4 | S10 | ✅ MIGRE |
| 25 | project-member | Metier | 4.7 | V3 | S8 | |
| 26 | project-secrets | Metier | 4.6 | V4 | S9 | |
| 27 | project-bulk | Metier | 4.2 | V4 | S9-S10 | |
| 26 | project-secrets | Metier | 4.6 | V4 | S9 | ✅ MIGRÉ (2026-05-28, fusionné dans project-core) |
| 27 | project-bulk | Metier | 4.2 | V4 | S9-S10 | ✅ MIGRÉ (2026-05-28, fusionné dans project-core) |
| 28 | sonarqube (encapsulation) | Plugin | 4.2 | V5 | S11 | |

**Note** : Le score brut ne dicte pas directement l'ordre de migration.
Expand Down Expand Up @@ -825,7 +825,7 @@ Encapsuler les plugins intermediaires.
**Livrable fin S10** : 75 routes migrees (100% des routes metier) + plugins
vault, keycloak, gitlab, harbor, nexus encapsules

### 19. project-core
### 19. project-core — ✅ MIGRÉ (2026-05-28)

| Attribut | Valeur |
|----------|--------|
Expand Down Expand Up @@ -857,7 +857,7 @@ vault, keycloak, gitlab, harbor, nexus encapsules

---

### 20. project-secrets
### 20. project-secrets — ✅ MIGRÉ (2026-05-28, fusionné dans project-core)

| Attribut | Valeur |
|----------|--------|
Expand All @@ -882,10 +882,12 @@ vault, keycloak, gitlab, harbor, nexus encapsules

---

### 21. project-bulk
### 21. project-bulk — ✅ MIGRÉ (2026-05-28, fusionné dans project-core)

| Attribut | Valeur |
|----------|--------|
| **Routes** | 2 (bulk action + export CSV) |
| **Note** | La route `POST /api/v1/projects/:projectId/replay-hooks` n'est pas encore migrée |
| **Routes** | 3 |
| **Score** | 4.2 |
| **Sprint** | S9-S10 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

## 🎯 Progression globale

![Progress](https://progress-bar.dev/7/?title=modularisation&width=400)
![Progress](https://progress-bar.dev/21/?title=modularisation&width=400)

**~7%** complété (1/18 modules métier migrés, 5/75 routes)
**~21%** complété (3/18 modules métier migrés, 16/75 routes)

---

## 📊 Vue d'ensemble

| Statut | Nombre de modules | % du total |
|--------|-------------------|------------|
| ✅ Migré | 1 (ServiceChain) | ~6% |
| ✅ Migré | 3 (ServiceChain, Project, ProjectMember) | ~17% |
| 🚧 En cours | 0 | 0% |
| 📅 Planifié | 17 | ~94% |
| 📅 Planifié | 15 | ~83% |
| ⏳ En attente de cartographie | 0 | 0% |

---
Expand Down Expand Up @@ -48,9 +48,45 @@ profitant de son isolement complet vis-à-vis du reste du codebase.
| `POST` | `/api/v1/service-chains/:id/retry` | `ManageSystem` |
| `POST` | `/api/v1/service-chains/validate/:id` | `ManageSystem` |

### Project — migrés le 2026-05-28

#### Project

Module cœur de gestion des projets (CRUD, secrets, bulk actions, export CSV).
Regroupe les sous-modules `project-core`, `project-secrets` et `project-bulk`
découpés dans la cartographie Vague 4, implémités ici en un seul module
unifié pour accélérer la migration.

- **Routes** : 7 (`/api/v1/projects/...`)
- **Auth** : Token (`x-dso-token`) + guards projet (`ProjectContextGuard`, `ProjectStatusGuard`, `ProjectLockedGuard`)
- **Validation** : Contrats Zod via `projectContract` de `@cpn-console/shared` avec `ZodValidationPipe`
- **Tests** : Controller + Service couverts (Vitest)

| Méthode | Route | Permission |
|---------|-------|------------|
| `GET` | `/api/v1/projects/data` | `Manage` (admin) |
| `GET` | `/api/v1/projects` | Authentifié |
| `POST` | `/api/v1/projects` | `ManageProjects` (admin) + type `human` |
| `POST` | `/api/v1/projects-bulk` | `Manage` (admin) |
| `GET` | `/api/v1/projects/:projectId` | Authentifié + projet |
| `GET` | `/api/v1/projects/:projectId/secrets` | Authentifié + projet (statut ≠ archived) |
| `PUT` | `/api/v1/projects/:projectId` | Authentifié + projet (statut ≠ archived) |

**Infrastructure créée/mise à jour** :
- `ProjectContextGuard` + `Project` decorator : chargement du projet par id/slug, résolution des permissions via bitmask
- `ProjectStatusGuard` + `@RequireProjectStatus()` : filtrage par statut du projet
- `ProjectLockedGuard` : protection contre les modifications de projets verrouillés
- `UserGuard` + `User` decorator : authentification token + injection du contexte utilisateur

**Différences avec le legacy** :
- Utilisation de `projectContract` de `@cpn-console/shared` pour les schemas de validation (cohérence client/serveur)
- ZodValidationPipe au lieu de la validation ts-rest implicite
- Les routes `secrets` et `bulk` sont fusiongées dans le module Project (pas de sous-modules séparés)
- Pas de `DELETE /api/v1/projects/:projectId` (archivage) dans cette version initiale

### Infrastructure transverse déployée

En support de cette migration, les éléments d'infrastructure suivants ont été
En support de ces migrations, les éléments d'infrastructure suivants ont été
créés :

- **AuthModule** (`infrastructure/auth/`) : `AuthService` (validation token
Expand All @@ -68,6 +104,31 @@ créés :
> mais les usages côté contrôleurs restent encore à homogénéiser au fil des
> modules migrés.

#### ProjectMember

Module de gestion des membres projet (ajout, modification, suppression, liste).
Dédié aux routes `/api/v1/projects/:projectId/members/...`.

- **Routes** : 4 (`/api/v1/projects/:projectId/members/...`)
- **Auth** : Token (`x-dso-token`) + guards projet (`ProjectContextGuard`, `ProjectStatusGuard`, `ProjectLockedGuard`)
- **Validation** : Contrats Zod via `projectMemberContract` de `@cpn-console/shared`

| Méthode | Route | Permission |
|---------|-------|------------|
| `GET` | `/api/v1/projects/:projectId/members` | `ListMembers` (admin) |
| `POST` | `/api/v1/projects/:projectId/members` | `ManageMembers` (admin) + statut non archivé |
| `PATCH` | `/api/v1/projects/:projectId/members` | `ManageMembers` (admin) + statut non archivé |
| `DELETE` | `/api/v1/projects/:projectId/members/:userId` | `ManageMembers` (admin) ou auto-suppression + statut non archivé |

**Fichiers** :
- `src/modules/project/project-member.controller.ts`
- Méthodes ajoutées dans `src/modules/project/project.service.ts`

**Différences avec le legacy** :
- Recherche par email non disponible (nécessite le hook Keycloak `user.retrieveUserByEmail`, non migré)
- Retour de la liste complète des membres après chaque mutation (cohérence avec le legacy)
- Événements `projectMember.upsert` et `projectMember.delete` via EventEmitter (remplacement du hook `projectMember.upsert`/`projectMember.delete`)

---

## 🚧 En cours de modularisation
Expand Down Expand Up @@ -140,9 +201,9 @@ créés :
### Routes par statut

- **Total** : ~75 routes métier
- **Migrés** : 5 (~7%)
- **Migrés** : 16 (~21%)
- **En cours** : 0 (0%)
- **Restants** : ~70 (~93%)
- **Restants** : ~59 (~79%)

---

Expand All @@ -156,6 +217,7 @@ créés :
| 09/02/2026 | Fin modularisation Auth (S4) - 20% complété |
| 09/03/2026 | Point mi-parcours - 60% complété |
| 26/03/2026 | Migration ServiceChain (OpenCDS) finalisée — 1er module métier migré |
| 28/05/2026 | Migration du module **Project** (7 routes) — CRUD + secrets + bulk |
| 06/04/2026 | Fin de modularisation - 100% complété |

---
Expand Down Expand Up @@ -188,6 +250,14 @@ créés :

## 🔄 Historique des changements

### 2026-05-28
- ✅ Migration du module **Project** — 7 routes : CRUD projets, secrets, bulk actions, export CSV
- ✅ Migration du module **ProjectMember** — 4 routes : membres projet (list, add, patch, delete)
- ✅ Création des guards projet : `ProjectContextGuard`, `ProjectStatusGuard`, `ProjectLockedGuard`
- ✅ Création des décorateurs `@Project()` et `@RequireProjectStatus()`
- ✅ Utilisation de `projectContract` de `@cpn-console/shared` pour la validation Zod
- ✅ Build et lint verts (server-nestjs)

### 2026-04-09
- ✅ Migration du module **ServiceChain (OpenCDS)** — 5 routes, proxy HTTP vers API externe
- ✅ Création de l'**AuthModule** (infrastructure/auth/) : auth par token `x-dso-token`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ Ce dossier contient toute la documentation nécessaire pour mener à bien la mod

**Bonne modularisation ! 🚀**

*Version 1.0 - Dernière mise à jour : 2026-01-07*
*Version 1.0 - Dernière mise à jour : 2026-05-28*
2 changes: 1 addition & 1 deletion apps/server-nestjs/src/__mocks__/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { PrismaClient } from '@prisma/client'
import { beforeEach, vi } from 'vitest'
import { mockDeep, mockReset } from 'vitest-mock-extended'

vi.mock('../prisma.js')
vi.mock('../prisma')

const prisma = mockDeep<PrismaClient>()

Expand Down
2 changes: 2 additions & 0 deletions apps/server-nestjs/src/main.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ScheduleModule } from '@nestjs/schedule'
import { DeploymentModule } from './modules/deployment/deployment.module'
import { HealthzModule } from './modules/healthz/healthz.module'
import { KeycloakModule } from './modules/keycloak/keycloak.module'
import { ProjectMembersModule } from './modules/project-members/project-members.module'
import { ProjectModule } from './modules/project/project.module'
import { ServiceChainModule } from './modules/service-chain/service-chain.module'
import { SystemSettingsModule } from './modules/system-settings/system-settings.module'
Expand All @@ -18,6 +19,7 @@ import { VersionModule } from './modules/version/version.module'
SystemSettingsModule,
ServiceChainModule,
ProjectModule,
ProjectMembersModule,
DeploymentModule,
VersionModule,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ describe('deploymentController', () => {
name: 'dev',
projectId: '11111111-1111-1111-1111-111111111111',
environmentId: '22222222-2222-2222-2222-222222222222',
cpu: 1,
gpu: 0,
memory: 512,
autosync: true,
deploymentSources: [
{
Expand Down
Loading
Loading