4.4 KiB
4.4 KiB
NFR Requirements — Unit 3: frontend-cms-page
Maintainability
| ID | Requirement | Rationale |
|---|---|---|
| NFR-FE-01 | All new components use react-hook-form + zodResolver + Zod schemas, consistent with InviteUserDialog and LoginPage patterns in this project. |
Single validation strategy across the entire frontend. |
| NFR-FE-02 | All user-visible strings are externalised in src/i18n/locales/{lang}/translation.json under the cms.* namespace. No hardcoded UI text in components. |
Enables future language additions without code changes. |
| NFR-FE-03 | Components follow the existing Shadcn/UI composition pattern: Dialog, Table, Select, Badge, DropdownMenu from @/components/ui/*. No third-party UI additions. |
Keeps the component surface consistent and avoids dependency sprawl. |
Testability
| ID | Requirement | Rationale |
|---|---|---|
| NFR-FE-04 | Test scope: hooks + page integration + individual component tests (Q2: C). Required test files: useCmsInstances.test.ts, useAddCmsInstance.test.ts, useUpdateCmsInstanceStatus.test.ts, CmsPage.test.tsx, AddCmsInstanceDialog.test.tsx, SetStatusDialog.test.tsx. |
Matches precedent set by InviteUserDialog.test.tsx. Isolated component tests cover error states and conditional logic (DisableMessage) without needing a full page mount. |
| NFR-FE-05 | MSW handlers cover all three API operations (GET list, POST create, PUT status) with at least one happy-path and one error variant per endpoint. | Handlers must be registered in both src/mocks/browser.ts (dev) and src/mocks/server.ts (tests). |
| NFR-FE-06 | All interactive elements receive data-testid attributes following the existing naming convention (cms-*, e.g. cms-add-button, cms-instance-row, cms-set-status-submit). |
Required for RTL getByTestId selectors in tests. |
Security
| ID | Requirement | Rationale |
|---|---|---|
| NFR-FE-07 | The apiKey field in AddCmsInstanceDialog is rendered as type="password" using the existing PasswordField component (which includes a show/hide toggle). |
Prevents shoulder-surfing of infrastructure credentials during the add flow (Q3: A). Reuses existing PasswordField.tsx component. |
| NFR-FE-08 | The apiKey value is sent once to the backend on form submit. It is not stored in React state beyond the form lifecycle and is not logged to the console. |
Credentials must not leak into browser DevTools' React state inspector or console logs. |
| NFR-FE-09 | CmsPage relies on RoleGuard allowedRoles={['Owner']} at the route level. No additional role check is implemented inside the page or its components. |
Single point of access control; avoids partial/inconsistent guards. See BR-FE-20. |
Reliability
| ID | Requirement | Rationale |
|---|---|---|
| NFR-FE-10 | Loading state for useCmsInstances is rendered as <p className="text-sm text-muted-foreground">{t('common.loading')}</p>, consistent with UsersPage. No skeleton component is introduced. |
Uniform loading UX without additional dependencies. |
| NFR-FE-11 | Error state for useCmsInstances is rendered as <p className="text-sm text-destructive">{t('errors.generic')}</p>, consistent with UsersPage. |
No custom error component needed. |
| NFR-FE-12 | TanStack Query stale time for useCmsInstances is 30 000 ms. Cache is invalidated on every successful mutation (add or status update). |
Balances freshness with network efficiency; avoids redundant refetches while dialogs are open. |
Validation
| ID | Requirement | Rationale |
|---|---|---|
| NFR-FE-13 | URL field in AddCmsInstanceDialog uses z.string().url() (strict Zod URL validation). The user must supply a fully-qualified URL including protocol (e.g. http://192.168.1.5:8080). |
Q1: A. Backend validates anyway; client-side strict validation prevents protocol-less entries from ever reaching the API. |
| NFR-FE-14 | react-hook-form mode is set to onTouched for all new dialogs, consistent with LoginPage. Validation messages appear after a field is touched, not on initial render. |
Avoids red errors appearing before the user has interacted with the form. |
| NFR-FE-15 | Field-level validation errors are rendered using the existing <FieldError> component (src/components/ui/FieldError.tsx). |
Consistent error presentation across all forms. |