Files
julien 69cf4548d2 refactor(naming): harmonize service file names and API domain prefixes
- Rename hwclan.service.ts → hw-clan.service.ts, hwmember.service.ts → hw-member.service.ts (Angular Style Guide kebab-case)
- Replace _apiVersion (/v1, /v2) with _apiDomain (/skydive, /cms, /herowars) across all feature services
- Update herowars barrel to reference renamed files
- Update CLAUDE.md to reflect corrected path examples
2026-04-26 00:39:03 +02:00

6.0 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

  • npm start — dev server (production config) on port 4200
  • npm run dev — dev server with APP_ENV=development on port 4300, uses environment.development.ts
  • npm run local — dev server with APP_ENV=local on port 4400, uses environment.local.ts
  • npm run serve — alias for local config on port 4201
  • npm run build — production build to dist/adastra_angular/
  • npm run watch — incremental build in development configuration
  • npm run lint — angular-eslint over src/**/*.ts and src/**/*.html
  • npm test — Karma + Jasmine (single spec: ng test --include src/path/to/file.spec.ts)

Node engines: ^18.19.1 || ^20.11.1. Angular 18, TypeScript 5.5, strict mode with strictTemplates.

Environments

src/environments/environment.ts is the default (production). environment.development.ts and environment.local.ts are swapped in via fileReplacements in angular.json for their respective configurations. environment.example.ts documents the expected shape (apiBaseUrl, apiKey, useApiKey, refreshInterval, googleMapApiKey). Never commit real keys to the development/local files — the production environment.ts currently has real keys checked in; be mindful.

Architecture

Standalone Angular 18 app (no NgModules) wired up in src/app/app.config.ts. It provides the router with withViewTransitions(), three HTTP interceptors, charts, French locale (fr-FR), and an APP_INITIALIZER that eagerly fetches the current user when a JWT is present in localStorage.

Routing split

Routes are composed in src/app/app.routes.ts from two arrays:

  • src/app/routes/auth.routes.tsauthGuard-protected routes. Skydive admin sections (aeronefs, canopies, dashboard, dropzones, jumps) additionally require adminGuard.
  • src/app/routes/noauth.routes.ts — public pages and auth-entry routes (login, register) gated by noauthGuard (blocks entry when already authenticated).

Resolvers under src/app/core/resolvers/ pre-fetch data for each route — new route components should generally follow this pattern rather than fetching in ngOnInit.

HTTP pipeline

Three interceptors chained in order (src/app/core/interceptors/):

  1. apiInterceptor — prepends environment.apiBaseUrl to every request URL. Consequence: services call relative paths like /cms/user, never absolute URLs.
  2. tokenInterceptor — attaches Authorization: Token <jwt> when a token exists.
  3. errorInterceptor — unwraps err.error and rethrows.

ApiService (api.service.ts) is a thin HttpClient wrapper; most feature services call it with a versioned prefix (e.g., _apiDomain = '/skydive' or /cms). The API version is per-service, not global.

Auth flow

JwtService stores the token in localStorage['jwtToken']. UserService exposes currentUser (BehaviorSubject) and isAuthenticated (ReplaySubject) observables consumed by guards and the layout. The APP_INITIALIZER in app.config.ts calls userService.getCurrentUser() if a token exists, so guards can rely on isAuthenticated being populated on first navigation. Admin role check is currentUser.role === 'Admin'.

Layout

AppComponent renders only FullComponent (src/app/components/shared/layout/full.component.ts), which owns the Material sidenav + toolbar shell and swaps menu items between MENUITEMS and MENUITEMSADMIN defined in src/app/components/shared/menu-items.ts based on role. Route changes render inside its <router-outlet>.

Feature areas

The app spans four mostly-independent feature domains, mirroring the backend's route grouping:

  • E-commerceproducts, product/:slug, products/:category (public + auth variants). Categories are baked into menu items, not dynamic. Backend counterpart: /api/ecommerce/*.
  • CMSpages, page/:slug, home, profiles, articles. Backend counterpart: /api/cms/*.
  • Skydiveskydive/* routes, services in src/app/core/services/skydive/, QCM exam data in src/app/components/qcm/*.json and src/qcm-bpa.json. Backend counterpart: /api/skydive/*.
  • Hero Wars — analytics for a game guild, services in src/app/core/services/herowars/, weekly data snapshots in src/files-data/ (Week_XX folders and hw-*.json files are static data shipped as assets). Backend counterpart: /api/herowars/*.

Path aliases

Configured in tsconfig.json and used everywhere — prefer them over relative paths: @components, @services, @models, @guards, @interceptors, @resolvers, @viewmodels, @interfaces, @constants, @core/*, @environments/*, @data/* (→ src/files-data/*), @assets/*, @styles/*.

Each alias points at an index.ts barrel — when adding a new component/service/model, also export it from the appropriate barrel or it won't be importable via the alias.

Styling

SCSS with includePaths: ["src/styles"] so imports like @use 'variables' resolve. Global Chartist styles are registered in angular.json build options. Material 18 with French date locale and DD/MM/YYYY format configured in AppComponent's providers.

The backend API lives in a sibling repo at /Users/julien/Sites/adastra_api (Express + Sequelize, additional working directory). Routes are grouped under src/routes/api/ into the same four domains as the frontend: skydive, cms, ecommerce, herowars. The v1, v2, v3 folders alongside them are legacy backups slated for removal — ignore them. When a task spans both repos (e.g., adding an endpoint + consumer), check there as well.