6.6 KiB
6.6 KiB
Implementation Plan: Admin Area General Settings and Categories 1.01
1. Architectural Reconnaissance
- Codebase style & conventions: TypeScript monorepo with a NestJS REST API and an Angular 17 standalone-component SPA. The General page is an OnPush standalone component using a non-nullable reactive form, signals for request state, and a typed
AdminService; server request validation uses Zod throughZodValidationPipe, while controllers delegate persistence to services. The affected flow isfrontend/src/app/features/admin/general.component.ts→AdminService.updateGeneralSettings()→AdminGeneralController.updateSettings()→GeneralSettingsSchema→AdminGeneralService.updateSettings()→SettingsService, with/api/v1/bootstrapsubsequently exposing the storedpageTitletoHomeComponentandShellHeaderComponent. - Data Layer: SQLite via TypeORM. General settings are key/value rows in the
settingtable;pageTitleis stored underSETTINGS_KEYS.PAGE_TITLE. No schema or migration change is required. Invalid requests must be rejected beforeAdminGeneralService.updateSettings()executes, ensuring the existing row remains unchanged. - Test Framework & Structure: Root Jest 29 multi-project configuration with
ts-jest: Node fortests/backend/**/*.spec.tsand jsdom fortests/frontend/**/*.spec.ts. Tests are kept in the dedicated/repo/teststree and all run from the repository root withnpm test; focused projects can run withnpm run test:frontendandnpm run test:backend. Add minimal pure frontend validation coverage and extend the existing backend schema/service test rather than introducing browser/UI infrastructure. - Required Tools & Dependencies: No new system tools, global CLIs, package dependencies, persistent
/datafixtures, orsetup.shchanges are required. Existing Angular Forms, Zod, Jest, and ts-jest cover the implementation and tests. Verification should usenpm testandnpm run build; the repository has no lint script or dedicated typecheck script, and the build scripts perform TypeScript/Angular compilation.
2. Impacted Files
- To Modify:
frontend/src/app/features/admin/general.pure.ts— add a small typed whitespace-aware page-title validator/helper that can be shared by the reactive form and tested without Angular UI setup.frontend/src/app/features/admin/general.component.ts— apply the page-title validator, render actionable field-level feedback, normalize the submitted title, and keep invalid forms from invoking the API.backend/src/modules/admin/dto/general.dto.ts— trimpageTitlebefore enforcing the existing 1–120 character contract so whitespace-only input is rejected and valid surrounding whitespace is not persisted.tests/frontend/admin-general-pure.spec.ts— cover empty/whitespace rejection and valid-title normalization/acceptance using the pure helper.tests/backend/admin-general-service.spec.ts— cover schema rejection of whitespace-only titles and schema output trimming for a valid title, proving invalid payloads cannot reach persistence.docs/guides/admin-general-settings.md— update the Page Title contract and expected save behavior to document trimming, inline validation feedback, and preservation of the stored value on invalid input.docs/api/admin.md— document the server contract as a trimmed, non-empty 1–120-character page title.
- To Create: None.
3. Proposed Changes
- Database / Schema Migration: No migration is needed. Continue using the existing
settingrow andSettingsService.set; rely on validation occurring before the service call so empty or whitespace-only requests perform no writes and the priorpageTitleremains available from both admin settings and/api/v1/bootstrap. - Backend Logic & APIs: Change
GeneralSettingsSchema.pageTitlefrom a rawz.string().min(1).max(120)to a trimmed string contract with the same bounds. BecauseZodValidationPipepassesparsed.dataonward, valid values such as' OpenVelo 'will reachAdminGeneralService.updateSettings()as'OpenVelo', while''and' 'will produce the existing400 VALIDATION_FAILEDenvelope before anyPromise.allpersistence or SSE emission. Keep endpoint paths, response types, error envelope, settings service, and bootstrap logic unchanged. - Frontend UI Integration: Add a standalone page-title validator/helper in
general.pure.tsthat treatsvalue.trim().length === 0as invalid while preserving Angular's max-length validation. Attach it to the non-nullablepageTitlecontrol inAdminGeneralComponent, show an inline field error beneathgeneral-pageTitlewhen the control is touched/dirty and either required/whitespace-invalid, and use an actionable message such as “Page title is required and cannot contain only whitespace.” Keep the existing disabled condition (form.invalid) andonSubmit()invalid guard/markAllAsTouched()so no PUT is issued for invalid values. For valid submissions, trimv.pageTitlebefore callingAdminService.updateGeneralSettings()so the immediate SPA request agrees with the server normalization. Clear stale save success/error state when a new submission begins as already done; only displaySaved.after a successful response and patch the normalized response back into the form. No shell-header fallback change is needed because invalid titles will no longer be persisted.
4. Test Strategy
- Target Unit Test File: Extend
tests/frontend/admin-general-pure.spec.tswith minimal tests for the page-title helper/validator: whitespace-only input is invalid, a normal title is valid, and valid surrounding whitespace normalizes to the intended persisted value. Extendtests/backend/admin-general-service.spec.tsunderGeneralSettingsSchema - validation ruleswith one rejection assertion for' 'and one successful parse assertion proving' OpenVelo 'becomes'OpenVelo'. These tests directly guard both client pre-validation and the authoritative server boundary without a visual/browser test. - Mocking Strategy: Frontend tests invoke only the pure helper with simple typed control-like values, so no TestBed, DOM interaction, or HTTP mock is needed. Backend schema tests use
safeParsedirectly, so no Nest application or database is needed; the existingAdminGeneralServicefake settings/hub test remains unchanged. This keeps tests fast and isolated while proving that invalid input never produces data suitable for persistence. Implement in TDD order: add the focused failing tests, verify the expected failures, make the minimal production changes, then runnpm testandnpm run buildfrom/repo.