Code conventions

The governing principle, stated in the repository’s own README: the code should be as transparent as possible, following Clean Code, SOLID, DRY and YAGNI. In practice the operative rule is narrower — find the nearest existing pattern and follow it.

Inherited standards

The repository declares that it follows the W3C JavaScript best practices and inherits most TypeScript conventions from the Airbnb style guide, with the exceptions below.

No Hungarian notation

Except on interfaces and types.

// bad
let sName: string;
let iYears: number;
let oConfig = { … };

// good
let name: string;
let years: number;
let config = { … };

Interfaces and types do carry a prefix in places — IEnvironment, IBalanceApproval, IResult, IPaymentGateway, ISupplierDetailsDTO. Newer files tend to drop it (EmailPreference, CardBase, AirwallexCardholderStatus). Both exist; match the neighbouring file.

Constant naming

UPPERCASE for constants — especially genuinely immutable ones. When unsure, prefer UPPERCASE.

Test- and mock-only constants are wrapped in double underscores:

const SOME_PRODUCTION_CONSTANT = 'some value';
const __SOME_MOCKED_CONSTANT__ = 'some value';

This is a real convention, followed in feature-flags.service.spec.ts (TEST_DISABLED_FLAGS, TEST_PAYLOAD). See testing.

TypeScript and Angular rules

Enforced by ESLint (.eslintrc.js, generated from an earlier TSLint config).

Rule Setting

@angular-eslint/component-selector

Element selector, app prefix, kebab-case — app-supplier-general.

@angular-eslint/directive-selector

Attribute selector, app prefix, camelCase — appEnabledByFeatureFlag.

@angular-eslint/component-class-suffix / directive-class-suffix

…Component / …Directive.

@angular-eslint/use-lifecycle-interface

Implement OnInit etc., don’t just declare the method.

@angular-eslint/use-pipe-transform-interface

Pipes implement PipeTransform.

@typescript-eslint/member-ordering

Enforced ordering of class members.

@typescript-eslint/no-explicit-any

Off. any is permitted and widespread in older code — new code should still be typed.

@typescript-eslint/ban-types

Warns on Object and Function.

simple-import-sort/imports and /exports

Import ordering is enforced. Do not hand-order imports; run npm run lint:fix.

unused-imports/no-unused-imports-ts

Unused imports are removed by --fix.

unused-imports/no-unused-vars-ts

Unused variables warn; -prefixed names are exempt (varsIgnorePattern/argsIgnorePattern of ^).

max-len

140 columns, with ^import .* lines exempt.

no-console

Warns, but allows a long list including log, warn, error, group, groupEnd, dir — which is why console.log appears in shipped code.

complexity

Off.

@typescript-eslint/naming-convention

Present but commented out in the config.

Almost every rule is set to warn, not error — so npm run lint can pass with warnings. Do not add new warnings; the signal is already noisy.

Prettier

Prettier is authoritative for formatting. .prettierrc:

{
  "printWidth": 140,
  "singleQuote": true,
  "useTabs": false,
  "tabWidth": 2,
  "semi": true,
  "bracketSpacing": true,
  "trailingComma": "all",
  "jsxBracketSameLine": true
}

Run npm run format before finishing. .prettierignore excludes dist/, coverage/, node_modules/, .vscode/, .idea/, package-lock.json and package.json.

.editorconfig matches: UTF-8, spaces, indent 2, final newline, trim trailing whitespace (except in Markdown).

TypeScript compiler options

tsconfig.json — note what is not enabled:

{
  "target": "es2015", "module": "es2020", "lib": ["es2017", "dom"],
  "experimentalDecorators": true, "emitDecoratorMetadata": true,
  "resolveJsonModule": true, "allowSyntheticDefaultImports": true,
  "downlevelIteration": true, "importHelpers": true,
  "skipLibCheck": true, "noStrictGenericChecks": true,
  "paths": { "payment": ["../node_modules/payment"] }
}

There is no strict, strictNullChecks, noImplicitAny or strictPropertyInitialization. noStrictGenericChecks is explicitly on, relaxing generic assignability. Turning any of these on is a repository-wide change, not a per-file one.

Structure

The repository’s stated position, worth reading in full because it deliberately diverges from Angular’s own guide:

  • "The blindly and dogmatically applied 'as flat as possible' principle leads to designs that are very difficult to maintain and modify."

  • Folder structure "should logically reflect the technological and business structure of the project and the intention of its creators."

  • Subcomponents go in a folder with their main component; more than a few helpers (constants, utils, interfaces) get their own folder.

  • If a project follows an organisational framework, the structure should reflect that one framework — do not mix (for example atomic design with fractal structure).

  • Component selectors should match the component name.

  • Use a component as an element, never as an attribute.

The concrete shape is fractal architecture: model/, services/, store/, shared/ recur at each level, and placement is decided by scope. See the module map.

Deviations exist "rather by mistake, not by design" — the README says so. Both service/ and services/ folder spellings occur; match the module you are in.

SCSS naming — ABEM without prefixes

For new code: camelCase BEM with separately-applied modifiers — described in the README as "ABEM without atomic prefixes", because the app is not atomic.

<div class="someLongNameOfBlock__someElementName -modifier -modifier2">…</div>

<section class="uwCard__subtitle -active -selected -primary -green -small">…</section>

So: camelCase inside blocks and elements, __ between block and element, and modifiers as separate classes prefixed with - rather than appended to the element class.

The README is candid that the existing CSS is "vague and incoherent" in places, and that most of it is some BEM mutation. Use ABEM for new code; do not rewrite old selectors while doing something else.

Global styles are the eight SCSS entry points in angular.json (styles, bootstrap, font-awesome, layout, loader, material2-theme, theme, ui), with src/assets on the include path. Avoid ViewEncapsulation.None unless the styles genuinely must be global — see shared library.

Service and state conventions

Summarised here; the detail is in HTTP layer and services and state management.

  • Services are thin HttpClient wrappers. Base URLs come from AppConfigService (appConfig.env.<key>) — never hardcoded.

  • Return Observable<T>; map the response shape inside the service.

  • Auth is transparent: AuthInterceptor attaches the session token. Do not re-implement it.

  • Models are plain interfaces or cerialize-decorated classes in model/, one concept per file.

  • Reach for NgRx only where the feature already uses it. Feature-local state stays in the component.

  • Extend SubscriberComponent and push into this.subscriptions for cleanup.

Git conventions

Branch names have three slash-separated parts:

{e-mail identifier (part before @)} / {TICKET-ID} / {short-ticket-description}

piotrk/NEW-11/very-important-task
olek/IA-69/even-more-important-task
michael/GAR-2051/email-preference

Contractors prefix the identifier with a lowercase c and capitalise the name:

cElvis/NEW-42/ultimate-question-of-life-the-universe-and-everything
cVika/IA-4242/most-important-task

Ticket ids are UPPERCASE, as in Jira. Projects seen in this repository: GAR, TS, DREAM (historically also IA, NEW, APPS, OPS).

Commit messages are short and imperative.

develop is the integration branch; production is released by pull request to release. See build and deployment.

Pull requests

Fill in .github/PULL_REQUEST_TEMPLATE.md. Its sections:

  1. Description — summary, motivation, context, dependencies.

  2. Jira ticket(s) — a link.

  3. Type of change — hot fix / bug fix / new feature / breaking change, plus a "This change requires a documentation update" checkbox.

  4. How has this been tested? — the tests you ran and how to reproduce.

  5. Checklist — self-review; follows the Change Management Policy and style guidelines; comments added in hard-to-understand areas; corresponding changes to the documentation have been added; tests added; unit tests pass; dependent changes merged.

  6. QA sign off.

Two of those items are about documentation, and this repository’s documentation is the Antora component in docs/. Use the docs-writer agent/skill (phase 5) to satisfy them — see the spec-driven workflow.

Hooks

Hook Runs

pre-commit

npm run lint:staged (eslint --fix on staged *.ts) then npm run format:staged (pretty-quick --staged).

pre-push

npm run test-single.

Never bypass with --no-verify.

What not to do

  • Do not bump dependencies, change the Angular version, introduce a second state library, or swap the test runner. See decisions and constraints.

  • Do not hardcode a base URL.

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

  • Do not edit src/environments/environment.ts — it is generated. See environments.

  • Do not edit the committed .js / .js.map build residue that sits beside .ts sources; edit the .ts.

  • Do not "fix" load-bearing misspellings without checking. 'analitics', WALLMART_MARKETPLACE_KEY, /proceses, UDPATE_SUPPLIER_PAYMENT_CONFIGS and superceded are on the wire or in live URLs.

  • Do not rewrite an unrelated file’s formatting or selectors while making a change.

A general preference that does not apply here

The developer’s general preference is Next.js / Python tooling. That does not apply to this repository — it is Angular, and Angular conventions win here. Stated explicitly in CLAUDE.md.