Orientation for new developers

First hour

  1. Read what the application does so that domain words (supplier, marketplace, advance, opt-in, reserve, batch) mean something.

  2. Get it running: local development. The single most common first-run failure is forgetting the environment generation step.

  3. Log in against a dev environment and click through: supplier list → open a supplier → walk the tabs. The tab strip is the domain model.

  4. Open Redux DevTools. Every meaningful state transition is a named action; the action log is the fastest way to learn how a screen is wired.

How to locate code

The repository is organised by feature, not by file type. Start from the URL.

URL                                   Route table                         Feature module
/#/suppliers/<key>/advances     →  suppliers/suppliers-routing.routes.ts  →  suppliers/supplier/supplier-advances/
/#/manage/event-rules           →  manage/manage-routing.routes.ts        →  manage/event-rules/
/#/processes/list               →  processes/processes-routing.routes.ts  →  processes/process-list/
/#/reports/<name>               →  reports/reports-routing.routes.ts      →  reports/report-table/

All top-level route tables are aggregated in src/app/app-routes.module.ts; the catalogue is here.

Within a feature module the conventional layout is:

<feature>/
├── model/                  interfaces and DTO classes, one concept per file
├── services/               @Injectable HTTP wrappers
├── store/                  NgRx actions / reducers / effects (only if stateful)
├── shared/                 code shared *within* this module
├── <sub-feature>/          component .ts / .html / .scss / .spec.ts
└── <feature>.module.ts     declarations and providers

Useful entry points:

File Why it matters

src/app/app.module.ts

The composition root: every eagerly loaded module, the reducer map, the effects list, and every application-level provider and DI substitution.

src/app/app-routes.module.ts

Aggregates all feature route tables under MainLayoutComponent.

src/app/store/app.reducers.ts

The complete AppState shape — 12 slices, nothing hidden.

src/app/shared/sidenav/sidenav-menu/sidenav-menu.component.html

The navigation tree with its permission and feature-flag conditions; the clearest single statement of "what exists and who can see it".

src/environments/environment.interface.ts

Every externally configurable value, and therefore every backend the app talks to.

src/app/shared/users/user-permissions.enum.ts

The permission vocabulary.

src/app/shared/feature-flags/feature-flags.const.ts

The feature-flag vocabulary.

Things that will surprise you

Hash routing

useHash: true in app-routes.module.ts. URLs look like //suppliers/list. Redirect and deep-link handling — including the post-login redirect stored in sessionStorage — strips the . See routing.

Compiled .js and .js.map files are checked in

Many folders contain stale .js / .js.map siblings next to the .ts source (for example auth.effects.js). They are build residue from an earlier toolchain, not inputs. Always edit the .ts. Ignore the .js in searches — grepping without excluding them produces duplicate hits.

util imports in application code

isUndefined, isNull, isString, isArray, isNullOrUndefined are imported from Node’s util module throughout the reducers and effects. It works because of the webpack Node polyfill; it is not a pattern to extend.

rxjs-compat and deep RxJS imports

Both rxjs/operators pipe style and legacy deep imports (rxjs/observable/forkJoin, rxjs/observable/ErrorObservable) appear. New code uses the pipe style.

Mock services everywhere

Almost every service has a -mock.service.ts sibling, and several have an -abstract.service.ts base with the concrete class injected by token in app.module.ts. This is the seam used by unit tests. See service abstractions.

Two processes route prefixes

/processes and the misspelled /proceses both exist and both resolve; the sidebar links to /proceses/approval for Balance Approval. Do not "fix" it without checking bookmarks and the batches deep links.

Serialisation decorators

Models use cerialize (@autoserialize, Deserialize, SerializeKeysTo) to translate between the API’s snake_case and the app’s camelCase. The key casing is set globally at call time, which makes ordering significant. See data modelling.

Making your first change

The repository runs a spec-first workflow with four agent phases (planner → plan reviewer → implementer → implementation reviewer). Specs live in .specs/. For anything beyond a trivial fix, write or update the spec first — see the spec-driven workflow.

Practical checklist for a change:

  1. Find the nearest existing pattern and copy it. Consistency beats improvement here.

  2. Keep the diff small enough to review in one sitting.

  3. npm run lint and npm run test-single must pass. Husky enforces lint on commit and tests on push — do not bypass with --no-verify.

  4. npm run format before finishing; Prettier is authoritative (single quotes, semicolons, 2-space indent, printWidth 140, trailing commas).

  5. Add a unit test for new behaviour; add a Cypress test only for user-facing flows, and note that the Cypress suite is currently not maintained.

  6. Guard new modules and routes with a feature flag by default — see feature flags.

What not to do

  • Do not upgrade Angular, NgRx, RxJS, AG Grid or the test runner. The versions are pinned deliberately; see decisions and constraints.

  • Do not introduce a second state library, or @ngrx/entity/createAction style into the NgRx 4 store.

  • Do not hardcode a base URL. Read it from AppConfigService.

  • Do not re-implement authentication in a service; AuthInterceptor handles it.

  • Do not add a store slice for state that one component owns.