Guidance for AI coding agents and human contributors working in this repository.
This complements CONTRIBUTING.md, STYLE.md, DOCS/CI_CHECKS.md, the ADRs under DOCS/adr/, and the
threat model in security.md.
Angular 22 standalone single-page application — the back-office UI for the Apache Fineract
core banking platform. It communicates with the Fineract REST API; all authorization is
enforced server-side (see security.md).
| Task | Command |
|---|---|
| Dev server | npm start |
| Unit tests | npm test -- --watch=false (Vitest) |
| Lint | npm run lint |
| Format | npm run format |
| Prod build | npm run build |
- Standalone components/directives (no NgModules). Services are
@Injectable({ providedIn: 'root' }). - Signals for reactive state (
signal(),computed(),asReadonly()); seesrc/app/core/services/config.service.tsfor the canonical pattern. - Every source file carries the ASF Apache-2.0 license header.
localStoragekeys are snake*case,fineract*-prefixed.
The UI layer is Ionic (@ionic/angular v8) in mode: 'md'. Angular Material has been
removed and npm run lint blocks any import of it. @angular/cdk is retained for unstyled
primitives. STYLE.md holds the full component mapping — the essentials:
- Import individual components from
@ionic/angular/standaloneinto the component'simportsarray; neverIonicModule. MatSnackBar→NotificationService,MatDialog→DialogService(both insrc/app/core/services/).- Icons are ionicons and must be registered in
src/app/core/icons.ts, whichbootstrap.tsfeeds toaddIcons(). An unregistered name renders blank with no error. - Ionic events carry their payload on
CustomEvent.detail.value; keep atarget.valuefallback because unit tests dispatch plain DOM events. - TestBeds rendering components that use Ionic overlays need
provideIonicTesting()fromsrc/app/testing/ionic-testing.ts, or they fail withNG0201: No provider found for _ModalController. - Theming flows through
src/styles/_ionic-theme.scss, which maps--ion-color-*onto the design tokens in_common.scss. Dark mode is the[data-theme='dark']attribute set byThemeService.
Third-party surfaces the application must be able to replace are reached through
src/app/core/adapters/ — never directly. See DOCS/adr/0003-adapter-boundary.md.
| Token | Use instead of |
|---|---|
I18N |
TranslateService; in templates, | appTranslate |
OVERLAY |
ToastController / ModalController — but prefer NotificationService / DialogService, which sit on top of it |
STORAGE |
localStorage / sessionStorage |
DOWNLOAD |
URL.createObjectURL plus a download anchor |
- Tokens resolve to their default implementation with no provider needed; override in
app.config.tsto swap one. <ion-*>components are not restricted — they are the UI layer. Only Ionic's imperative controllers are.- New keys must be added to
STORAGE_KEYS(core/adapters/storage/storage-keys.ts); the type admits nothing else. npm run lintfails on a new violation. The existing backlog is recorded ineslint-suppressions.jsonand may only shrink.- In specs, use
provideFakeAdapters()fromsrc/app/testing/adapters.tsrather than mocking the library.
A build-time boolean read directly from src/environments/environment.ts,
environment.prod.ts, and environment.sandbox.ts (default: true).
true— the sidebar filters navigation by user permissions and institution config; permission/institution directives enforce their checks.false— the sidebar shows all items and both directives render everything, preserving the pre-RBAC experience for existing deployments so RBAC can be adopted per-environment.
The flag is a UI-visibility control only, never a security boundary. Authorization is always enforced server-side by Fineract. See
security.md§5a and §11.7.
*appHasPermission—src/app/shared/directives/has-permission.directive.ts. Renders its element only ifAuthService.hasPermission(...)passes. Accepts a single permission string or an array; add; matchAll: trueto require all. Short-circuits to "always render" whenrbacEnabled === false.*appInstitutionFeature—src/app/shared/directives/has-institution-feature.directive.ts. Renders its element only ifInstitutionConfigService.isFeatureEnabled(feature)is true for'groups' | 'centers' | 'collection_sheet'. Short-circuits to "always render" whenrbacEnabled === false.
src/app/core/services/institution-config.service.ts. Signal-based service that persists the
institution type ('mfis' | 'cb' | 'cu' | 'universal') to localStorage
(fineract_institution_type, default 'universal') and exposes
isFeatureEnabled(feature), resolved against a per-type feature matrix.
src/app/layout/sidebar.component.ts gates the three institution-feature nav items with
*appInstitutionFeature, and gates high-value groups (Admin, Accounting, Security, Settings,
System) with *appHasPermission. Additional nav items can be gated by adding the appropriate
directive to their <li> — the pattern is intentionally incremental.