Skip to content

Commit bbbd78b

Browse files
mishraompCopilot
andauthored
feat: tenant onboarding portal (#145)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bdb0bae commit bbbd78b

File tree

122 files changed

+27828
-404
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+27828
-404
lines changed

.github/copilot-instructions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ Use when creating, modifying, or debugging integration tests.
6161
- Test helpers, config loading, and assertion patterns
6262
- Retry logic, skip guards, and async polling
6363

64+
### [Tenant Onboarding Portal](./skills/tenant-onboarding-portal/SKILL.md)
65+
Use when modifying the tenant onboarding portal application.
66+
- NestJS backend under `tenant-onboarding-portal/backend/src/`
67+
- React/Vite frontend under `tenant-onboarding-portal/frontend/src/`
68+
- Mock auth, Keycloak integration, Azure Table Storage, and Playwright E2E tests
69+
- Local tooling, portal deployment workflow, and portal-specific docs
70+
6471
### [Network](./skills/network/SKILL.md)
6572
Use when adding or modifying subnets, CIDR allocation, NSG rules, or delegation in the network module.
6673
- Explicit `subnet_allocation` model (`map(map(string))`) in `infra-ai-hub/modules/network/locals.tf`
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
name: tenant-onboarding-portal
3+
description: Guidance for modifying the tenant onboarding portal in ai-hub-tracking. Use when changing the NestJS backend, React/Vite frontend, mock auth or Keycloak integration, Azure Table Storage behavior, or Playwright end-to-end coverage for tenant onboarding workflows.
4+
---
5+
6+
# Tenant Onboarding Portal
7+
8+
Use this skill when working in `tenant-onboarding-portal/`.
9+
10+
## Scope
11+
12+
- Backend: `tenant-onboarding-portal/backend/src/`
13+
- Frontend: `tenant-onboarding-portal/frontend/src/`
14+
- Local run tooling: `tenant-onboarding-portal/backend/run-local.sh`
15+
- Tests: `tenant-onboarding-portal/backend/tests/`
16+
- Portal infra and deployment wiring: `tenant-onboarding-portal/infra/`, `.github/workflows/`
17+
18+
## Architecture
19+
20+
The portal is a NestJS backend that serves a built React SPA.
21+
22+
- The backend owns API routes, auth validation, Azure Table Storage access, and tfvars generation.
23+
- The frontend authenticates through `/api/auth/config` and `/api/session`, then calls `/api/...` routes with bearer tokens.
24+
- Built frontend assets are copied into `tenant-onboarding-portal/backend/frontend-dist/` for deployment and E2E runs.
25+
26+
## Auth Model
27+
28+
- Production-style auth uses Keycloak bearer-token validation.
29+
- Local and E2E runs can use `PORTAL_AUTH_MODE=mock`.
30+
- Mock auth should preserve the same authorization boundaries as real auth:
31+
- authenticated user session
32+
- admin role checks via `oidc_admin_role`
33+
34+
Prefer adding behavior inside the auth abstraction rather than bypassing route guards or hardcoding UI shortcuts.
35+
36+
## Testing Guidance
37+
38+
- Backend tests use Vitest and Supertest.
39+
- E2E tests use Playwright against the built frontend served by the backend.
40+
- Prefer mock auth for portal E2E tests.
41+
- Keep Playwright selectors semantic:
42+
- labels
43+
- button text
44+
- headings
45+
- links
46+
47+
Avoid brittle CSS selectors unless no accessible selector exists.
48+
49+
## Storage Guidance
50+
51+
- Azure Table Storage is the main persistence layer.
52+
- Local tests should continue using the in-memory fallback unless the task explicitly needs Azure storage behavior.
53+
- Preserve request versioning semantics when changing create/update flows.
54+
55+
## Code Formatting and Linting
56+
57+
Both backend and frontend share the **same Prettier config** at `tenant-onboarding-portal/.prettierrc`:
58+
59+
```json
60+
{
61+
"semi": true,
62+
"singleQuote": true,
63+
"trailingComma": "all",
64+
"printWidth": 100,
65+
"tabWidth": 2
66+
}
67+
```
68+
69+
- **Prettier** formats all TypeScript source files. Always run `format` after making code changes.
70+
- **ESLint** enforces code quality. Both use ESLint 9 flat config with `typescript-eslint` and `eslint-config-prettier` (disables formatting rules that conflict with Prettier).
71+
- The backend config is at `backend/eslint.config.mjs`; the frontend config is at `frontend/eslint.config.js`.
72+
- **Pre-commit hooks** run ESLint + Prettier check automatically on changed `backend/` and `frontend/` TypeScript files. A commit will be rejected if lint or format checks fail.
73+
74+
**After every code change**, run from the respective directory:
75+
76+
```bash
77+
npm run format # auto-format with Prettier
78+
npm run lint # ESLint check (or lint:fix to auto-fix)
79+
```
80+
81+
## JSDoc Documentation
82+
83+
JSDoc is **mandatory** for every function and method in the codebase. This applies to:
84+
85+
- Every exported function or class method in the backend and frontend
86+
- Every internal (non-exported) function or class method
87+
- React component functions
88+
89+
JSDoc is **not required** for:
90+
91+
- Inline arrow function callbacks (e.g. inside `useEffect`, `map`, event handlers)
92+
- Test files (`*.spec.ts`)
93+
94+
### Required JSDoc structure
95+
96+
```ts
97+
/**
98+
* One-sentence description of what the function does.
99+
*
100+
* @param paramName - Description of the parameter. No `{Type}` — TypeScript owns types.
101+
* @returns Description of the return value when non-void.
102+
* @throws Description of the error when the function explicitly documents a failure path.
103+
*/
104+
```
105+
106+
Rules:
107+
- A **description sentence is required** on every JSDoc block — never leave it empty.
108+
- Use `@param name - description` format (dash separator, no type annotation).
109+
- Add `@returns` when the function returns a meaningful non-void value.
110+
- Add `@throws` only when you explicitly document an error condition.
111+
- Do **not** add `{Type}` annotations in `@param` or `@returns` — TypeScript provides the types.
112+
113+
### ESLint enforcement
114+
115+
Both packages enforce JSDoc via `eslint-plugin-jsdoc`. The relevant rules are set to **error**:
116+
117+
- `jsdoc/require-jsdoc` on `FunctionDeclaration` and `MethodDefinition`
118+
- `jsdoc/require-description` — blocks without a description sentence fail lint
119+
- `jsdoc/require-param` and `jsdoc/require-returns` — missing tags for documented params/returns fail lint
120+
- `jsdoc/require-param-type` and `jsdoc/require-returns-type` are **off** (TypeScript owns types)
121+
122+
Running `npm run lint` will report any missing JSDoc blocks.
123+
124+
## NestJS Backend Best Practices
125+
126+
- Use NestJS modules, controllers, services, and guards — do not put logic directly in `main.ts`.
127+
- Dependency injection: always inject services through constructor parameters with proper NestJS providers.
128+
- Use `@Injectable()` for services, `@Controller()` for route handlers, `@Module()` for feature modules.
129+
- Decorate request DTOs with class-validator decorators and use `ValidationPipe` globally.
130+
- Keep controller methods thin — delegate business logic to service classes.
131+
- Use `@UseGuards()` for auth enforcement; never skip guards with inline token inspection in controllers.
132+
- `no-explicit-any` is a lint warning (not error) — prefer typed interfaces and DTOs instead.
133+
134+
## React Frontend Best Practices
135+
136+
- State management uses Zustand stores — keep store slices focused and co-located with feature code.
137+
- Routing uses TanStack Router — define routes in files expected by the router plugin.
138+
- Use `@bcgov/design-system-react-components` components before reaching for custom HTML or Bootstrap directly.
139+
- Prefer React Query or similar data-fetching patterns over raw `useEffect` for async state.
140+
- `no-explicit-any` is a lint warning — always type API responses and component props.
141+
- React Hooks plugin enforces rules of hooks — do not call hooks conditionally.
142+
143+
## Implementation Rules
144+
145+
1. Preserve the `/api/...` contract used by the React SPA unless the task explicitly requires coordinated frontend and backend changes.
146+
2. Keep auth behavior centralized in the backend token validator and frontend auth store.
147+
3. Prefer environment-driven test modes over special-case test-only code paths scattered through controllers and components.
148+
4. When adding E2E coverage, verify the full user journey end to end instead of only checking page load.
149+
5. When changing tenant request fields, update validation, API types, frontend form handling, and tfvars generation together.
150+
6. **Always run `npm run format` after every code change** — the pre-commit hook will reject unformatted code.
151+
152+
## Useful Commands
153+
154+
```bash
155+
# Backend
156+
cd tenant-onboarding-portal/backend
157+
npm run format # auto-format source with Prettier
158+
npm run lint # ESLint check
159+
npm run lint:fix # ESLint auto-fix
160+
npm run format:check # Prettier dry-run (used by pre-commit)
161+
npm run build
162+
npm test
163+
npm run e2e
164+
165+
# Frontend
166+
cd tenant-onboarding-portal/frontend
167+
npm run format # auto-format source with Prettier
168+
npm run lint # ESLint check
169+
npm run lint:fix # ESLint auto-fix
170+
npm run format:check # Prettier dry-run (used by pre-commit)
171+
npm run build
172+
npm test
173+
```

.github/workflows/.deployer-using-secure-tunnel.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ jobs:
7777
steps:
7878
- name: Checkout
7979
uses: actions/checkout@v6
80-
80+
- name: Setup Node.js
81+
uses: actions/setup-node@v6
82+
with:
83+
node-version: 24
8184
- name: Azure CLI Login (OIDC)
8285
uses: azure/login@v2
8386
with:
@@ -86,7 +89,7 @@ jobs:
8689
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
8790

8891
- name: Setup Terraform
89-
uses: hashicorp/setup-terraform@v3
92+
uses: hashicorp/setup-terraform@v4
9093
with:
9194
terraform_version: ${{ env.TF_VERSION }}
9295
terraform_wrapper: false

.github/workflows/.deployer.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ jobs:
5656
steps:
5757
- name: Checkout
5858
uses: actions/checkout@v6
59-
59+
- name: Setup Node.js
60+
uses: actions/setup-node@v6
61+
with:
62+
node-version: 24
6063
- name: Azure CLI Login (OIDC)
6164
uses: azure/login@v2
6265
with:
@@ -65,7 +68,7 @@ jobs:
6568
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
6669

6770
- name: Setup Terraform
68-
uses: hashicorp/setup-terraform@v3
71+
uses: hashicorp/setup-terraform@v4
6972
with:
7073
terraform_version: ${{ env.TF_VERSION }}
7174
- name: Make deploy script executable

0 commit comments

Comments
 (0)