Update _apiDomain in UserService (/cms → /auth) and ApplicationsService (/skydive → /auth) following the backend route reorganization. fix(calculator): use nullish coalescing for currentUser.poids to preserve default weight when no skydiver profile exists docs: update README
AdAstra App
Frontend of the AdAstra platform — a multi-domain Angular application covering e-commerce, CMS, skydive club management, and Hero Wars guild analytics.
Tech stack
| Layer | Choice |
|---|---|
| Framework | Angular 21 (standalone components, no NgModules) |
| Language | TypeScript 5.9 — strict mode + strictTemplates |
| UI | Angular Material 21, Bootstrap 5 |
| Charts | Chart.js 4 (ng2-charts), Chartist |
| HTTP | Angular HttpClient with three interceptors (base URL, JWT, errors) |
| Tests | Karma + Jasmine |
| Linting | angular-eslint + Prettier (enforced via lint-staged) |
| Node | ^20.19.0 || ^22.12.0 |
Related repository
The backend API lives in adastra_api — an Express + Sequelize stack, routes grouped under /api/ecommerce, /api/cms, /api/skydive, /api/herowars.
Getting started
npm install
npm run local # dev server on :4400, uses environment.local.ts
Copy and configure your local environment:
cp src/environments/environment.example.ts src/environments/environment.local.ts
# fill in: apiBaseUrl, apiKey, googleMapApiKey, …
Commands
| Command | Description |
|---|---|
npm start |
Dev server on :4200 with production config |
npm run dev |
Dev server on :4300 with environment.development.ts |
npm run local |
Dev server on :4400 with environment.local.ts |
npm run build |
Production build → dist/adastra_angular/ |
npm run watch |
Incremental build in development configuration |
npm run lint |
angular-eslint on **/*.ts and **/*.html |
npm test |
Karma + Jasmine unit tests |
Run a single spec:
ng test --include src/path/to/file.spec.ts
Architecture
Bootstrap
AppComponent renders a single FullComponent shell (Material sidenav + toolbar). Routes are split into two arrays in app.routes.ts:
auth.routes.ts— protected byauthGuard; admin sections additionally requireadminGuardnoauth.routes.ts— public pages and auth entry points, blocked bynoauthGuardwhen already authenticated
Data is pre-fetched by resolvers under src/app/core/resolvers/ — new route components should follow this pattern rather than fetching in ngOnInit.
HTTP pipeline
Three interceptors applied in order:
apiInterceptor— prependsenvironment.apiBaseUrlto every request. Services use relative paths (/cms/user,/skydive/jumps, …), never absolute URLs.tokenInterceptor— attachesAuthorization: Token <jwt>when a token exists inlocalStorage['jwtToken'].errorInterceptor— unwrapserr.errorand rethrows.
Feature domains
| Domain | Routes | Backend prefix |
|---|---|---|
| E-commerce | products, product/:slug, products/:category |
/api/ecommerce |
| CMS | pages, page/:slug, home, profiles, articles |
/api/cms |
| Skydive | skydive/* — aeronefs, canopies, dropzones, jumps |
/api/skydive |
| Hero Wars | Guild analytics, weekly snapshots in src/files-data/ |
/api/herowars |
Path aliases
Defined in tsconfig.json; always prefer them over relative imports:
@components @services @models @guards
@interceptors @resolvers @viewmodels @interfaces
@constants @core/* @environments/*
@data/* @assets/* @styles/*
When adding a new file, export it from the appropriate index.ts barrel so the alias resolves correctly.
Styling
SCSS with includePaths: ["src/styles"] — imports like @use 'variables' resolve globally. Material date locale is set to fr-FR with DD/MM/YYYY format.