d962be838a
## Summary
First step of the admin track per ADR-0020. Scaffold the second Angular SPA in the workspace alongside `portal-shell`, with the architectural decisions from the v1 ADRs already wired so subsequent feature PRs can drop straight into modules.
## What lands
- **App generated** via `nx g @nx/angular:application` (with the matching e2e project skeleton). Standalone, zoneless-ready, prefix `app`, scss component styles, css root stylesheet, no SSR.
- **Tags** `scope:portal-admin, type:app` — module-boundary lint now treats `portal-admin` distinctly from `portal-shell` and lets it depend only on `scope:portal-admin` + `scope:shared` libs.
- **Tailwind v4 + brand tokens**: `.postcssrc.json`, `@import 'tailwindcss'`, class-based dark variant, and `@import '../../../libs/shared/tokens/src/brand-tokens.css'` — identical visual baseline to portal-shell.
- **i18n config mirrors portal-shell** (per ADR-0019): sourceLocale `en`, target `fr`, baseHref `/{locale}/` per locale, `@angular/localize/init` polyfill, `localize: ["en", "fr"]` on production, `i18nMissingTranslation: "error"` so CI blocks any PR that adds a marker without translating it. Seed [`messages.fr.xlf`](apps/portal-admin/src/locale/messages.fr.xlf) carries the four marked strings used today.
- **Budgets** relaxed to **500 KB gzip initial** per ADR-0020 §"Performance budgets" (vs 300 KB for portal-shell).
- **Skeleton home page** at `/` — `<h1>` + intro paragraph + "Skeleton — coming soon" chip in the brand-accent palette. All marked for i18n.
- **Skip-link landmark** (WCAG 2.4.1) with the same component-scoped scss as portal-shell.
- **Wildcard catch-all route** → bounces unknown paths to home (same defensive pattern as PR #96 on portal-shell).
- **Dev server on port 4300** (vs 4200 for portal-shell) — both can run in parallel.
- **`serve-static` target without `spa: true`** — locale-prefixed routing in production is handled by the reverse proxy (per ADR-0019), same as portal-shell since PR #92.
## CLAUDE.md
Picked up the second app in the **Naming** entry and the **Commands** snippet (`<app>` is now one of `portal-shell`, `portal-admin`, `portal-bff`).
## Verification
- `pnpm exec nx run-many -t lint test build --projects=portal-shell,portal-admin,shared-ui,shared-state,shared-tokens` — green.
- `portal-admin` test: 1 spec (skip-link + main landmark present).
- Production build of `portal-admin`: **62 KB gzip initial per locale** (vs 500 KB budget — plenty of headroom for the upcoming modules).
- Both `dist/apps/portal-admin/browser/{en,fr}/` emit with the right `<html lang>` and `<base href>`. FR bundle contains `"Administration"` / `"Squelette"` / `"bientôt disponible"` — translations applied.
- portal-shell production build unchanged.
## Out of scope (each its own follow-up PR)
- Admin app shell (header / sidebar / footer with "Admin" badge — likely sharing graduated primitives plus admin-specific bits).
- OpenTelemetry tracing setup (`service.name=portal-admin` per ADR-0012).
- `environment.ts` wiring (per ADR-0018) for admin-specific endpoints.
- BFF `AdminModule` + `AdminRoleGuard` + smoke `/api/admin/me` (per ADR-0020 §"Auth").
- First functional module — CMS / menu / users / audit viewer.
## Test plan
- [x] Lint + test + build green across the workspace.
- [x] Per-locale production build emits both folders with correct metadata.
- [ ] Manual: `pnpm exec nx serve portal-admin` boots on `:4300`, smoke page renders.
- [ ] Manual: prod build + `pnpm exec nx run portal-admin:serve-static` → `http://localhost:4300/en/` and `/fr/` show the placeholder with the matching language.
---------
Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #100
124 lines
3.1 KiB
JSON
124 lines
3.1 KiB
JSON
{
|
|
"name": "portal-admin",
|
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
"projectType": "application",
|
|
"prefix": "app",
|
|
"sourceRoot": "apps/portal-admin/src",
|
|
"tags": ["scope:portal-admin", "type:app"],
|
|
"i18n": {
|
|
"sourceLocale": {
|
|
"code": "en",
|
|
"baseHref": "/en/"
|
|
},
|
|
"locales": {
|
|
"fr": {
|
|
"translation": "apps/portal-admin/src/locale/messages.fr.xlf",
|
|
"baseHref": "/fr/"
|
|
}
|
|
}
|
|
},
|
|
"targets": {
|
|
"build": {
|
|
"executor": "@angular/build:application",
|
|
"outputs": ["{options.outputPath}"],
|
|
"options": {
|
|
"outputPath": "dist/apps/portal-admin",
|
|
"browser": "apps/portal-admin/src/main.ts",
|
|
"polyfills": ["@angular/localize/init"],
|
|
"tsConfig": "apps/portal-admin/tsconfig.app.json",
|
|
"inlineStyleLanguage": "scss",
|
|
"assets": [
|
|
{
|
|
"glob": "**/*",
|
|
"input": "apps/portal-admin/public"
|
|
}
|
|
],
|
|
"styles": ["apps/portal-admin/src/styles.css"]
|
|
},
|
|
"configurations": {
|
|
"production": {
|
|
"localize": ["en", "fr"],
|
|
"i18nMissingTranslation": "error",
|
|
"budgets": [
|
|
{
|
|
"type": "initial",
|
|
"maximumWarning": "1.5mb",
|
|
"maximumError": "1.5mb"
|
|
},
|
|
{
|
|
"type": "anyScript",
|
|
"maximumWarning": "500kb",
|
|
"maximumError": "500kb"
|
|
},
|
|
{
|
|
"type": "anyComponentStyle",
|
|
"maximumWarning": "5kb",
|
|
"maximumError": "6kb"
|
|
},
|
|
{
|
|
"type": "bundle",
|
|
"name": "styles",
|
|
"maximumWarning": "150kb",
|
|
"maximumError": "150kb"
|
|
}
|
|
],
|
|
"outputHashing": "all"
|
|
},
|
|
"development": {
|
|
"optimization": false,
|
|
"extractLicenses": false,
|
|
"sourceMap": true
|
|
}
|
|
},
|
|
"defaultConfiguration": "production"
|
|
},
|
|
"extract-i18n": {
|
|
"executor": "@angular/build:extract-i18n",
|
|
"options": {
|
|
"buildTarget": "portal-admin:build",
|
|
"outputPath": "apps/portal-admin/src/locale",
|
|
"outFile": "messages.xlf"
|
|
}
|
|
},
|
|
"serve": {
|
|
"continuous": true,
|
|
"executor": "@angular/build:dev-server",
|
|
"options": {
|
|
"port": 4300
|
|
},
|
|
"configurations": {
|
|
"production": {
|
|
"buildTarget": "portal-admin:build:production"
|
|
},
|
|
"development": {
|
|
"buildTarget": "portal-admin:build:development"
|
|
}
|
|
},
|
|
"defaultConfiguration": "development"
|
|
},
|
|
"lint": {
|
|
"executor": "@nx/eslint:lint"
|
|
},
|
|
"test": {
|
|
"executor": "@angular/build:unit-test",
|
|
"options": {
|
|
"watch": false
|
|
},
|
|
"configurations": {
|
|
"watch": {
|
|
"watch": true
|
|
}
|
|
}
|
|
},
|
|
"serve-static": {
|
|
"continuous": true,
|
|
"executor": "@nx/web:file-server",
|
|
"options": {
|
|
"buildTarget": "portal-admin:build",
|
|
"port": 4300,
|
|
"staticFilePath": "dist/apps/portal-admin/browser"
|
|
}
|
|
}
|
|
}
|
|
}
|