Orientation for new developers
First hour
-
Read what the application does so that domain words (supplier, marketplace, advance, opt-in, reserve, batch) mean something.
-
Get it running: local development. The single most common first-run failure is forgetting the environment generation step.
-
Log in against a dev environment and click through: supplier list → open a supplier → walk the tabs. The tab strip is the domain model.
-
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 |
|---|---|
|
The composition root: every eagerly loaded module, the reducer map, the effects list, and every application-level provider and DI substitution. |
|
Aggregates all feature route tables under |
|
The complete |
|
The navigation tree with its permission and feature-flag conditions; the clearest single statement of "what exists and who can see it". |
|
Every externally configurable value, and therefore every backend the app talks to. |
|
The permission vocabulary. |
|
The feature-flag vocabulary. |
Things that will surprise you
- Hash routing
-
useHash: trueinapp-routes.module.ts. URLs look like//suppliers/list. Redirect and deep-link handling — including the post-login redirect stored insessionStorage— strips the. See routing. - Compiled
.jsand.js.mapfiles are checked in -
Many folders contain stale
.js/.js.mapsiblings next to the.tssource (for exampleauth.effects.js). They are build residue from an earlier toolchain, not inputs. Always edit the.ts. Ignore the.jsin searches — grepping without excluding them produces duplicate hits. utilimports in application code-
isUndefined,isNull,isString,isArray,isNullOrUndefinedare imported from Node’sutilmodule throughout the reducers and effects. It works because of the webpack Node polyfill; it is not a pattern to extend. rxjs-compatand deep RxJS imports-
Both
rxjs/operatorspipe 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.tssibling, and several have an-abstract.service.tsbase with the concrete class injected by token inapp.module.ts. This is the seam used by unit tests. See service abstractions. - Two
processesroute prefixes -
/processesand the misspelled/procesesboth exist and both resolve; the sidebar links to/proceses/approvalfor 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’ssnake_caseand the app’scamelCase. 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:
-
Find the nearest existing pattern and copy it. Consistency beats improvement here.
-
Keep the diff small enough to review in one sitting.
-
npm run lintandnpm run test-singlemust pass. Husky enforces lint on commit and tests on push — do not bypass with--no-verify. -
npm run formatbefore finishing; Prettier is authoritative (single quotes, semicolons, 2-space indent,printWidth140, trailing commas). -
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.
-
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/createActionstyle into the NgRx 4 store. -
Do not hardcode a base URL. Read it from
AppConfigService. -
Do not re-implement authentication in a service;
AuthInterceptorhandles it. -
Do not add a store slice for state that one component owns.