|
| 1 | +# GitHub Copilot & AI Coding Instructions for `nr-fom` |
| 2 | + |
| 3 | +## Project Architecture & Monorepo Overview |
| 4 | +`nr-fom` (Forest Operations Map) is an npm workspaces monorepo: |
| 5 | +* **`admin/`**: Angular 22 admin portal for Forest Clients and Ministry staff to create, edit, submit, and review FOMs. |
| 6 | +* **`public/`**: Angular 22 public-facing portal for citizens to discover FOMs and submit comments. |
| 7 | +* **`api/`**: NestJS 11 backend service utilizing TypeORM 1.0, PostgreSQL 18 with PostGIS spatial extensions, and Pino logging. |
| 8 | +* **`libs/client/typescript-ng/`**: Auto-generated Angular API client from OpenAPI (`@api-client`). |
| 9 | +* **`libs/utility/`**: Shared security, authentication, and common TypeScript helpers. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## 1. Containerized Execution Invariants (Podman / Docker) |
| 14 | + |
| 15 | +### Never Run Heavy Workloads on Bare Metal |
| 16 | +* **Rule**: Never run test runners (`jest`, `npm run test-unit`), compilations (`ng build`, `nest build`), or migrations directly on the host machine. |
| 17 | +* **Execution**: Always dispatch commands inside Podman containers: |
| 18 | + ```bash |
| 19 | + # Run unit tests inside containers |
| 20 | + podman compose exec admin npm run test:admin |
| 21 | + podman compose exec api npm run test:api |
| 22 | + podman compose exec public npm run test:public |
| 23 | + |
| 24 | + # Database migrations |
| 25 | + podman compose exec api npm run db:migrate-main --workspace=api |
| 26 | + ``` |
| 27 | +* **Worker Concurrency**: Always bound test runner concurrency with `--maxWorkers=2` or `--runInBand` on all Jest scripts (`test-unit`, `test-unit-watch`, `test-e2e`, `test:cov`) to prevent host CPU and memory starvation. |
| 28 | + |
| 29 | +--- |
| 30 | + |
| 31 | +## 2. Frontend Reactive & Null Safety Standards (Angular 22) |
| 32 | + |
| 33 | +### Reactive Resource & Signal Patterns |
| 34 | +* **`rxResource` Resolution**: When consuming an Angular `rxResource`, check `resource.hasValue()` rather than evaluating truthiness (`if (!resource.value())`). |
| 35 | + * A resolved `null` payload (e.g., when a forest client has no historical public notice) is a **resolved valid state**, not an uncompleted loading state. |
| 36 | +* **Signal Un-tracking**: Inside `effect()` blocks, wrap downstream initialization calls (such as `buildForm()`) in `untracked()` if only the primary resource signal should trigger re-computation. |
| 37 | + |
| 38 | +### Form Building & Null Safety |
| 39 | +* **Form Initialization**: Always guard against `null` responses when constructing `@rxweb/reactive-form-validators` models: |
| 40 | + ```typescript |
| 41 | + const formModel = new PublicNoticeForm(this.response ?? undefined); |
| 42 | + this.formGroup = this.formBuilder.formGroup(formModel) as IFormGroup<PublicNoticeForm>; |
| 43 | + ``` |
| 44 | +* **Prohibit Unchecked Type Casting**: Avoid blindly casting to `as Partial<T>` or `as any` to silence TypeScript compiler diagnostics. Check and guard property existence explicitly. |
| 45 | + |
| 46 | +### Authorization & State Gating in UI |
| 47 | +* Always verify project workflow state (`project.workflowState.code === WorkflowStateEnum.INITIAL`) and client permissions (`user.isForestClient && user.isAuthorizedForClientId(...)`) before exposing destructive actions (delete, submit). |
| 48 | +* Distinguish between `isNewForm` (project has no associated record) and `editMode` (route state). |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## 3. Backend API & TypeORM Standards (NestJS 11) |
| 53 | + |
| 54 | +### OpenAPI & DTO Contracts |
| 55 | +* Every nullable or optional field in a DTO must be explicitly annotated with `@ApiPropertyOptional()` so that auto-generated Angular clients accurately reflect the nullable contract. |
| 56 | +* Avoid returning untyped object literals; map entities directly to declared response DTOs. |
| 57 | + |
| 58 | +### Multi-Tenancy & Client Scoping |
| 59 | +* All mutating endpoints must validate the caller's JWT claims against the target entity's `forestClient.id` using `user.isAuthorizedForClientId(clientId)`. |
| 60 | +* Ministry users (`user.isMinistry`) have cross-client read and administrative review capabilities. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## 4. Test Suite Requirements |
| 65 | + |
| 66 | +* **Unit Tests**: Test suites must cover the full lifecycle matrix: |
| 67 | + 1. Unresolved / loading state. |
| 68 | + 2. Resolved `null` / empty state (zero-state scenarios). |
| 69 | + 3. Resolved valid entity state. |
| 70 | + 4. Error states (403, 404, 500). |
| 71 | +* **Mock Realism**: Do not mock services to return only happy-path truthy data. Write explicit regression tests for empty and boundary return values. |
0 commit comments