feat(sites) : outillage opt-in site-aware (ticket 4/4)

Livre l'infrastructure permettant aux modules metier de declarer leurs
entites comme "scopees par site" via SiteAwareInterface. Strictement
opt-in : aucune entite metier touchee, aucune migration sur tables
existantes.

Composants :
- SiteAwareInterface (Shared/Domain/Contract) : getSite/setSite
- CurrentSiteProvider + interface (Module/Sites/Application) : resolve
  ?Site selon 3 conditions (module actif, user authentifie, currentSite).
  Interface extraite pour mockabilite en tests (implementation reste final).
- SiteScopedQueryExtension : QueryCollection + QueryItem API Platform,
  ajoute WHERE site = :currentSite si resource SiteAware + provider
  non-null + pas sites.bypass_scope.
- SiteAwareInjectionProcessor : decorator de api_platform.doctrine.orm.
  state.persist_processor (#[AsDecorator]). Injecte currentSite sur
  entites SiteAware sans site ; throw 400 si provider null.
- Permission sites.bypass_scope declaree dans SitesModule::permissions().

Tests :
- FakeSiteAwareEntity dans tests/Fixtures/ + mapping when@test dans
  doctrine.yaml. Table creee a la volee via SchemaTool dans setUp.
  schema:update --force ajoute dans test-db-setup pour que fixtures:load
  ne crashe pas au purger.
- 17 tests dedies au ticket 4 (CurrentSiteProvider unitaire, Injection
  Processor unitaire, Extension integration avec 7 cas couvrant filtrage
  collection + item, bypass, no-op, resource non SiteAware).
- SitesModuleTest : verifie le set de 3 permissions + que le decorator
  est bien enregistre sur le persist processor.

Documentation docs/modules/site-aware.md : guide developpeur 8 sections
(quand/ne pas adopter, comment, migration, mode degrade, anti-patterns,
exemple d'adoption Supplier, cascade delete).

Upgrade @malio/layer-ui 1.4.0 → 1.4.2 (bug 1.4.0 : tailwind.config.ts
oublie dans les files publies npm → classe rounded-malio manquante sur
les DataTables). Simplification tailwind.config.ts Coltura : retrait des
colors/fontFamily/borderRadius dupliques, seule la specifique projet
(primary, secondary, tertiary, m.secondary, m.tertiary) est conservee.

Tests : 201/201 avec et sans SitesModule actif (2 skipped en disabled).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 15:11:07 +02:00
parent 03c761eed4
commit 296befe187
18 changed files with 1263 additions and 27 deletions

View File

@@ -7,7 +7,7 @@
"name": "coltura-frontend",
"hasInstallScript": true,
"dependencies": {
"@malio/layer-ui": "^1.4.0",
"@malio/layer-ui": "^1.4.2",
"@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0",
@@ -1820,9 +1820,9 @@
"license": "MIT"
},
"node_modules/@malio/layer-ui": {
"version": "1.4.0",
"resolved": "https://gitea.malio.fr/api/packages/MALIO-DEV/npm/%40malio%2Flayer-ui/-/1.4.0/layer-ui-1.4.0.tgz",
"integrity": "sha512-2LBe/WqOwNw61Y+9y2SDgsB3/JCTS7VOYfQHFLMb6GXOIj1Vmjxqf8GEzQOzre4pGI+n8w2o+VVn6ttQIkBtzA==",
"version": "1.4.2",
"resolved": "https://gitea.malio.fr/api/packages/MALIO-DEV/npm/%40malio%2Flayer-ui/-/1.4.2/layer-ui-1.4.2.tgz",
"integrity": "sha512-H8f5FJXHFH9ZI1Jx4u9XE7w6VlR/d9Zr2encfQyMax1I0UZ3SiGBUjictcL33r0OhgsrgSmPq0J9aF6aab85Nw==",
"dependencies": {
"@nuxt/icon": "^2.2.1",
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -15,7 +15,7 @@
"test:watch": "vitest"
},
"dependencies": {
"@malio/layer-ui": "^1.4.0",
"@malio/layer-ui": "^1.4.2",
"@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -1,13 +1,26 @@
import type {Config} from 'tailwindcss'
/**
* Config Tailwind du projet Coltura.
*
* @nuxtjs/tailwindcss merge automatiquement les configs de chaque layer
* Nuxt declare dans `nuxt.config.ts:extends`. Le layer `@malio/layer-ui`
* apporte deja :
* - borderRadius.malio (var CSS --m-radius)
* - colors.m.{primary,surface,border,text,muted,bg,disabled,danger,
* success,btn-*,site-blue,site-yellow,site-green}
* - fontFamily.sans (Helvetica Neue)
*
* Cette config locale ne redeclare QUE ce qui est specifique a Coltura
* ou absent de la config Malio — evite la duplication et les derives.
*/
export default <Partial<Config>>{
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['"Helvetica Neue"', 'Helvetica', 'Arial', 'sans-serif']
},
colors: {
// Couleurs applicatives Coltura (hors namespace `m` reserve
// au design system Malio partage).
primary: {
500: '#222783',
},
@@ -20,27 +33,10 @@ export default <Partial<Config>>{
blue: {
500: '#056CF2'
},
// Extensions au namespace `m` non couvertes par Malio 1.4.1.
m: {
primary: 'rgb(var(--m-primary) / <alpha-value>)',
secondary: 'rgb(var(--m-secondary, 75 77 237) / <alpha-value>)',
tertiary: 'rgb(var(--m-tertiary, 243 244 248) / <alpha-value>)',
border: 'rgb(var(--m-border) / <alpha-value>)',
text: 'rgb(var(--m-text) / <alpha-value>)',
muted: 'rgb(var(--m-muted) / <alpha-value>)',
bg: 'rgb(var(--m-bg) / <alpha-value>)',
surface: 'rgb(var(--m-surface) / <alpha-value>)',
disabled: 'rgb(var(--m-disabled) / <alpha-value>)',
danger: 'rgb(var(--m-danger) / <alpha-value>)',
success: 'rgb(var(--m-success) / <alpha-value>)',
'btn-primary': 'rgb(var(--m-btn-primary) / <alpha-value>)',
'btn-primary-hover': 'rgb(var(--m-btn-primary-hover) / <alpha-value>)',
'btn-primary-active': 'rgb(var(--m-btn-primary-active) / <alpha-value>)',
'btn-secondary': 'rgb(var(--m-btn-secondary) / <alpha-value>)',
'btn-secondary-hover': 'rgb(var(--m-btn-secondary-hover) / <alpha-value>)',
'btn-secondary-active': 'rgb(var(--m-btn-secondary-active) / <alpha-value>)',
'btn-danger': 'rgb(var(--m-btn-danger) / <alpha-value>)',
'btn-danger-hover': 'rgb(var(--m-btn-danger-hover) / <alpha-value>)',
'btn-danger-active': 'rgb(var(--m-btn-danger-active) / <alpha-value>)',
}
}
}