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
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/24/?title=modularisation&width=400)

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

---

## 📊 Vue d'ensemble

| Statut | Nombre de modules | % du total |
|--------|-------------------|------------|
| ✅ Migré | 1 (ServiceChain) | ~6% |
| ✅ Migré | 4 (ServiceChain, SystemSettings, Project, AdminRole) | ~22% |
| 🚧 En cours | 0 | 0% |
| 📅 Planifié | 17 | ~94% |
| 📅 Planifié | 14 | ~78% |
| ⏳ En attente de cartographie | 0 | 0% |

---
Expand Down Expand Up @@ -48,9 +48,32 @@ 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` |

### SystemSettings — migré le 2026-05-28

Module de gestion des paramètres système.

- **Routes** : 2 (`/api/v1/system/settings/...`)
- **Auth** : Token (`x-dso-token`) + décorateur `@RequireAdminPermission()`
- **Validation** : Schéma Zod `SystemSettingSchema` de `@cpn-console/shared`
- **Tests** : Controller + Service couverts (Vitest)

### SystemConfig — migré le 2026-06-12

Module de gestion de la configuration des plugins (lecture/écriture de la table
`adminPlugin`). Dédié aux routes `/api/v1/system/plugins/...`.

- **Routes** : 2 (`/api/v1/system/plugins`)
- **Auth** : Guards admin (`AdminGuard`) + décorateur `@RequireAdminPermission()`
- **Validation** : Contrats Zod via `pluginUpdateBody` / `pluginSchema` de `@cpn-console/shared`
- **Tests** : Service couvert (Vitest)

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

Module cœur de gestion des projets (CRUD de base).

### 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 Down Expand Up @@ -140,9 +163,9 @@ créés :
### Routes par statut

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

---

Expand All @@ -154,8 +177,10 @@ créés :
| 26/01/2026 | Fin de la cartographie (S2) |
| 27/01/2026 | Début modularisation Auth (S3) |
| 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 |
| 28/05/2026 | Migration du module **ProjectMembers** (4 routes) — membres projet |
| 12/06/2026 | Migration du module **AdminRole** (5 routes) — gestion des rôles admin |
| 12/06/2026 | Migration du module **SystemConfig** (2 routes) — configuration des plugins |
| 06/04/2026 | Fin de modularisation - 100% complété |

---
Expand Down Expand Up @@ -188,6 +213,20 @@ créés :

## 🔄 Historique des changements

### 2026-06-12
- ✅ Migration du module **SystemConfig** — 2 routes : configuration des plugins (list, update)
- ✅ Migration du module **AdminRole** — 5 routes : gestion des rôles admin
- ✅ Mise à jour du contrôleur admin-role pour utiliser `AdminGuard` + `@RequireAdminPermission()`
- ✅ Ajout des utilitaires de mapping `AdminRole` Prisma → `@cpn-console/shared`

### 2026-05-28
- ✅ Migration du module **Project** — 7 routes : CRUD projets, secrets, bulk actions, export CSV
- ✅ Migration du module **ProjectMembers** — 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 All @@ -210,5 +249,5 @@ créés :

---

**Version du fichier** : 1.1
**Version du fichier** : 1.2
**Responsable de mise à jour** : Lead technique backend
12 changes: 2 additions & 10 deletions apps/server-nestjs/src/main.module.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import { Module } from '@nestjs/common'
import { EventEmitterModule } from '@nestjs/event-emitter'
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 { ProjectModule } from './modules/project/project.module'
import { ServiceChainModule } from './modules/service-chain/service-chain.module'
import { SystemConfigModule } from './modules/system-config/system-config.module'
import { SystemSettingsModule } from './modules/system-settings/system-settings.module'
import { VersionModule } from './modules/version/version.module'

@Module({
imports: [
EventEmitterModule.forRoot(),
HealthzModule,
KeycloakModule,
ScheduleModule.forRoot(),
SystemSettingsModule,
ServiceChainModule,
ProjectModule,
DeploymentModule,
SystemConfigModule,
VersionModule,
],
controllers: [],
Expand Down
34 changes: 2 additions & 32 deletions apps/server-nestjs/src/modules/infrastructure/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,16 @@
import { Module } from '@nestjs/common'
import { JwtModule } from '@nestjs/jwt'
import { ConfigurationModule } from '../configuration/configuration.module'
import { ConfigurationService } from '../configuration/configuration.service'
import { DatabaseModule } from '../database/database.module'
import { AuthService } from './auth.service'
import { DsoTokenModule } from './dso-token/dso-token.module'
import { KeycloakJwtModule } from './keycloak-jwt/keycloak-jwt.module'
import { KeycloakJwtService } from './keycloak-jwt/keycloak-jwt.service'

const JwtModuleConfig = JwtModule.registerAsync({
imports: [ConfigurationModule, KeycloakJwtModule],
inject: [ConfigurationService, KeycloakJwtService],
useFactory: (config: ConfigurationService, keycloakJwtService: KeycloakJwtService) => ({
secretOrKeyProvider: async (_requestType, tokenOrPayload) => {
const decoded = keycloakJwtService.decodeJweHeader(tokenOrPayload)
if (!decoded?.kid) throw new Error('Missing kid')
const publicKey = await keycloakJwtService.getPublicKey(decoded.kid)
if (!publicKey) throw new Error('Unknown signing key')
return publicKey
},
verifyOptions: {
algorithms: ['RS256'],
audience: keycloakJwtService.getAudience(),
issuer: config.getKeycloakIssuer(),
},
}),
})

@Module({
imports: [
DsoTokenModule,
ConfigurationModule,
DatabaseModule,
JwtModuleConfig,
KeycloakJwtModule,
],
imports: [DsoTokenModule, KeycloakJwtModule],
providers: [
AuthService,
],
exports: [
AuthService,
JwtModuleConfig,
KeycloakJwtModule,
],
})
export class AuthModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export class AuthService {
return bearerTokenResult
}

throw new UnauthorizedException()
throw new UnauthorizedException('Not authenticated')
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
import type { KeycloakPayload } from './keycloak-jwt.service'
import { generateKeyPairSync } from 'node:crypto'
import { faker } from '@faker-js/faker'
import { KeycloakPayloadSchema } from './keycloak-jwt.service'

export function makeKeycloakPayload(overrides: Partial<KeycloakPayload> = {}) {
return KeycloakPayloadSchema.parse({
sub: faker.string.uuid(),
email: faker.internet.email().toLowerCase(),
given_name: faker.person.firstName(),
family_name: faker.person.lastName(),
groups: Array.from({ length: faker.number.int({ min: 0, max: 3 }) }, () =>
`/${faker.word.noun()}`),
...overrides,
})
}

export function makeMockUser(overrides: Partial<{
id: string
Expand Down Expand Up @@ -58,24 +43,3 @@ export function makeMockAdminRole(overrides: Partial<{
...overrides,
}
}

export function makeJwksResponse(kid: string): Response {
const { publicKey } = generateKeyPairSync('rsa', { modulusLength: 2048 })
const jwk = publicKey.export({ format: 'jwk' })
return new Response(JSON.stringify({
keys: [
{
kid,
kty: 'RSA',
use: 'sig',
n: jwk.n,
e: jwk.e,
},
],
}), {
status: 200,
headers: {
'content-type': 'application/json',
},
})
}
Loading