Refonte qualité (shared / back / front) #1

Open
z3n wants to merge 14 commits from chore/quality-refonte into main

14 Commits

Author SHA1 Message Date
z3n
787d8f32ee back(test): specs validation env + DTO upload (48 -> 59 tests)
- env.validation.spec : config valide/coercion/défauts + rejets (var manquante,
  port hors plage, NODE_ENV inconnu)
- create-api-upload.dto.spec : name requis, emails @ValidateIf (vides OK,
  invalides rejetés), énum convention, MaxLength
- vitest-setup charge reflect-metadata (décorateurs class-validator en test)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:21:36 +00:00
z3n
d2d140640e front: extrait les templates inline vers des fichiers .html
upload (900->427 l.) et api-detail (700->330 l.) : le template inline géant
passe en templateUrl. Aucun changement de comportement (build + eslint a11y
+ runtime OK). Composants bien plus navigables ; les .html sont désormais
lintés par angular-eslint (a11y).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:19:21 +00:00
z3n
f64efda8a3 front: composant <app-breadcrumb> mutualisé (dédup markup DSFR)
Extrait le fil d'Ariane DSFR dupliqué dans browse/api-detail/upload vers un
composant présentationnel piloté par une liste d'items. Chaque page construit
ses items (computed pour browse/api-detail, statique pour upload).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:17:18 +00:00
z3n
15e05cc46c front(upload): garde-fou de taille de fichier (5 Mo)
Rejette les fichiers trop volumineux à la sélection avec un message clair,
avant lecture FileReader/envoi serveur.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 07:06:45 +00:00
z3n
5cdaa7d4a1 back(db): infra migrations TypeORM + migration initiale
- data-source.ts (CLI) + scripts migration:generate/run/revert/show
- migration InitialSchema : schéma complet (categories, api_entries),
  vérifiée en l'appliquant sur une base vierge (crée aussi l'ext uuid-ossp)
- app.module: charge les migrations et migrationsRun en prod uniquement.
  Corrige un trou : la prod avait synchronize:false SANS migrations
  (schéma vide au déploiement). Dev inchangé (synchronize:true).

Bascule de dev vers migrations-only (synchronize:false + baseline de la base
dev existante) = étape ultérieure à faire en supervisé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 07:05:30 +00:00
z3n
f9df2dd1bb front(test): Vitest + premier spec (ErrorService)
- Vitest (cohérent avec le back) pour les tests de logique/services purs ;
  vitest-setup charge @angular/compiler (fallback JIT requis pour importer
  les symboles @angular/* partiellement compilés)
- error.service.spec.ts : 6 cas couvrant toMessage()
- script test -> vitest run (+ test:watch). Tests de composants TestBed =
  plugin Angular dédié, hors périmètre pour l'instant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:17:00 +00:00
z3n
c9fa0cd97b front(lint): ESLint 9 flat config + angular-eslint 19
- eslint.config.js (flat) : recommended TS + angular-eslint (ts + templates
  a11y), règles selectors app + no-unused-vars (^_ ignoré)
- script lint -> 'eslint .' (+ lint:fix), évite la résolution du builder
  Angular sous pnpm
- fix de la seule violation (variable _ inutilisée dans l'effect catalog)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:13:54 +00:00
z3n
cd43c88294 back(test): coverage vitest (@vitest/coverage-v8)
Ajoute le provider de coverage + section coverage dans vitest.config (reporter
text/html/lcov, exclusions modules/entities/dto/main) et un script test:cov.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:11:44 +00:00
z3n
9151932eb6 back(uploads): DTO validé sur l'upload + contraintes de longueur
- CreateApiUploadDto : valide le multipart POST /uploads via ValidationPipe
  (types, @IsIn énums partagés, @IsUUID, @MaxLength(255)). Emails validés
  seulement si renseignés (@ValidateIf) -> n'casse pas les contacts vides.
  Remplace le body inline + les checks manuels du contrôleur.
- create-api-entry.dto: @MaxLength(255) sur name/provider/contacts (matche les
  colonnes entité) + @MaxLength sur emails.

Vérifié: email invalide -> 400 message clair, contacts vides -> 201 OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:08:02 +00:00
z3n
c38adf3a7c front: stoppe les fuites de souscriptions RxJS (takeUntilDestroyed)
Toutes les souscriptions des composants passent par
takeUntilDestroyed(this.destroyRef) : browse, catalog, api-detail, upload,
category-form-modal, category-delete-modal. api-detail abandonne le pattern
manuel Subscription/ngOnDestroy au profit de DestroyRef (ngOnDestroy ne garde
que le clearPoll du setInterval).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:49:11 +00:00
z3n
34a83233f2 front: config env, error interceptor fonctionnel, DSFR en deps, fix build
- src/environments/{environment,environment.prod}.ts + fileReplacements :
  baseUrl API configurable au lieu de '/api' hardcodé dans les services
- ErrorService + errorInterceptor (HttpInterceptorFn) ; app.config passe à
  withInterceptors([...]) (remplace withInterceptorsFromDi legacy)
- @gouvfr/dsfr déplacé en dependencies (chargé au runtime)
- api.service: extrait ValidateResponse (dédup du type inline)
- fix: formValues passe en protected (utilisé dans le template -> build NG1
  cassé, le conteneur servait un ancien bundle)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:43:06 +00:00
z3n
f7f706e1e1 back(uploads): I/O fichiers en async (non bloquant)
readFileSync/existsSync/mkdirSync -> fs/promises (readFile, mkdir recursive
idempotent). detectMainFile devient async. Retire l'import fs sync inutilisé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:02:13 +00:00
z3n
38f6f6ab52 back: validation d'env, transaction setCurrent, fix N+1 catégories, logging
- ConfigModule.forRoot({ validate }) : schéma class-validator des variables
  d'env, l'app refuse de démarrer si une var manque/mal typée ; suppression
  des fallbacks de credentials DB (getOrThrow)
- setCurrent() enveloppé dans une transaction (plus de fenêtre incohérente
  sur isCurrent entre les 2 updates)
- browse() : compteurs de toutes les catégories en 2 requêtes + calcul en
  mémoire au lieu d'un N+1 récursif par enfant
- console.* -> Logger Nest partout (apis, uploads, seeder, bootstrap) ;
  .catch(console.error) -> logger.error avec contexte

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:00:13 +00:00
z3n
558bf763e7 shared: source de vérité unique pour les énums d'API
- API_STATUSES inclut 'NO_YAML' (était manquant alors que le type et le
  code l'utilisent)
- ApiType/ApiStatus/ApiConvention dérivés des constantes (typeof X[number])
  -> plus de double maintenance type <-> tableau
- DTO back réutilisent API_CONVENTIONS/API_TYPES dans @IsIn (fin de la
  triple duplication des valeurs)
- front: déclare la dépendance @datacat/shared (workspace:*)
- shared: exports map + métadonnées + README (double build front/back)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:54:27 +00:00