This file provides guidance to AI agents when working with code in this repository.
Abzu is a stop place register frontend for managing public transport stop places in Norway. It communicates with the Tiamat GraphQL API backend for all stop place data operations. The application manages stop places, quays, accessibility information, parking, equipment, and groupings of stop places.
# Install dependencies
npm install
# Development server (port 9000 by default)
npm start
# Development with local Tiamat backend
npm run dev-local
# Build for production
npm run build
# Preview production build
npm serve
# Run tests (watch mode)
npm test
# Run tests with coverage report
npm test:coverage
# Format code with Prettier
npm run format
# Check code formatting
npm run check
# Analyze bundle size
npm run analyze
# Fetch GraphQL schema from Tiamat backend
npm run fetch-schemaPORT- Override development port (default: 9000)VITE_REACT_APP_TIAMAT_BASE_URL- Override GraphQL endpoint URL for development
- Build System: Vite with TypeScript and React
- UI Framework: React 19 with Material-UI (MUI) v7
- State Management: Redux Toolkit with redux-first-history for routing integration
- GraphQL: Apollo Client connecting to Tiamat backend
- Maps: Leaflet and react-leaflet
- Authentication: OIDC (oidc-client-ts) - provider agnostic
- Error Tracking: Sentry
- Internationalization: react-intl with 5 languages (en, nb, fi, fr, sv)
- Testing: Vitest with Testing Library
Application configuration is loaded from /bootstrap.json at runtime. For local development, place this file in public/bootstrap.json. See src/config/ConfigContext.ts for the full configuration schema.
Key configuration includes:
tiamatBaseUrl- GraphQL endpointoidcConfig- OIDC authentication settingsfeatureFlags- Feature togglesmapConfig- Map tiles and default viewlocaleConfig- Language settingsextPath- Path to company-specific extensions under/src/ext
Uses Redux Toolkit with traditional actions/reducers pattern (not fully migrated to RTK slices):
- Store:
src/store/store.ts- Configures store with redux-first-history and Sentry integration - Reducers:
src/reducers/- Domain-specific reducers (stopPlace, user, map, zones, etc.) - Actions:
src/actions/- Action creators organized by domain (StopPlaceActions, TiamatActions, UserActions) - Router Integration: Uses redux-first-history to sync routing with Redux state
Two Apollo clients managed in src/graphql/clients.js:
- Tiamat Client - Main backend for stop place data (queries/mutations in
src/graphql/Tiamat/) - OTP Client - Optional client for journey planning data
GraphQL operations are organized in:
fragments.js- Reusable GraphQL fragmentsqueries.js- Query operationsmutations.js- Mutation operations
The schema introspection is stored in schema.json and can be refreshed via npm run fetch-schema.
Domain models in src/models/ define the shape of entities and provide utility functions:
StopPlace.js- Main stop place entityQuay.js- Platform/boarding area within a stop placeParentStopPlace.js- Grouping of related stop placesGroupOfStopPlaces.js- Purpose-based groupingsAccessibilityLimitation.ts,Equipments.ts- Equipment and accessibility dataParking.js,PathLink.js- Associated infrastructure- Various enum models for types and categories
- Pages:
src/containers/- Route-level container components (App, StopPlaces, StopPlace, GroupOfStopPlaces, ReportPage) - UI Components:
src/components/organized by feature area:EditStopPage/- Stop place editing interfaceEditParentStopPage/- Parent stop place editingGroupOfStopPlaces/- Group managementMap/- Leaflet-based map componentsMainPage/- Search and listingDialogs/- Modal dialogsZones/- Fare and tariff zone management
- Extensions:
src/ext/- Company-specific toggleable components loaded based onextPathconfig
Uses react-router-dom v7 with redux-first-history integration. Routes defined in src/routes/ and instantiated in src/index.js:
/- Main stop places listing/stop-place/:stopId- Individual stop place editor/group-of-stop-places/:groupId- Group editor/report- Reporting interface
Translations in src/static/lang/ with 5 language files: en.json, nb.json, fi.json, fr.json, sv.json.
When adding translations for new backend enum types (e.g., purpose of grouping types), follow the pattern documented in docs/PURPOSE_OF_GROUPING_TRANSLATIONS.md:
- Add key with format
{category}_type_{value}to all 5 language files - The
valuemust match the GraphQL APIname.valuefield - System automatically falls back to API value if translation missing
Uses @entur/react-component-toggle to enable/disable components based on configuration. Company-specific features are placed in src/ext/{companyName}/ and loaded via extPath configuration. See src/ext/README.md for documentation.
Tests use Vitest with jsdom environment. Test files located in src/test/ with .spec.js extension. Configuration in vite.config.mts under the test key.
Run single test file:
npx vitest run src/test/mapUtils.spec.js- Formatting: Prettier with
prettier-plugin-organize-imports(auto-organizes imports) - Pre-commit: Husky runs
lint-stagedto format staged files before commit - TypeScript: Gradual migration - both
.jsand.tsfiles present (strict mode enabled)
Note these patterns when working with the codebase:
- Mix of
.jsand.tsfiles - TypeScript migration in progress - Traditional Redux pattern with action creators (not fully migrated to RTK slices)
- Some class components may still exist alongside functional components
- Material-UI usage mixes older patterns with newer MUI v7 patterns
- Add GraphQL fragment to
src/graphql/Tiamat/fragments.js - Update queries/mutations in
src/graphql/Tiamat/queries.jsormutations.js - Add field to model in
src/models/StopPlace.js - Update reducer logic in
src/reducers/stopPlaceReducer.js - Add UI components in
src/components/EditStopPage/ - Add translations to all language files
- Add tests in
src/test/
When the Tiamat backend schema changes:
- Ensure
public/bootstrap.jsonpoints to correct backend - Run
npm run fetch-schemato updatesrc/graphql/Tiamat/schema.json - Update fragments, queries, or mutations as needed
- TypeScript types may need manual updates
Always add new translation keys to all 5 language files in src/static/lang/:
en.jsonnb.jsonfi.jsonfr.jsonsv.json
For enum-type translations from backend, follow the pattern in docs/PURPOSE_OF_GROUPING_TRANSLATIONS.md.