4.7 KiB
4.7 KiB
Implementation Plan: Admin Area General Settings UTC Datetime Round-Trip
1. Architectural Reconnaissance
- Codebase style & conventions: TypeScript monorepo with an Angular 17 standalone SPA and NestJS backend. The General Settings screen uses a strictly typed, non-nullable reactive form in
frontend/src/app/features/admin/general.component.ts, while reusable formatting and validation logic is extracted to pure functions infrontend/src/app/features/admin/general.pure.ts. The component loads backend ISO timestamps throughtoDatetimeLocal, submits form values throughtoIsoUtc, and uses async/await around the promise-basedAdminServiceAPI facade. - Data Layer: NestJS persists general settings as string key/value rows through
SettingsService.AdminGeneralService.updateSettingswriteseventStartUtcandeventEndUtcverbatim afterGeneralSettingsSchemavalidates timezone-aware ISO-8601 strings and strict start/end ordering. No database schema or migration is required; the defect is isolated to frontend conversion of UTC-labelleddatetime-localvalues. - Test Framework & Structure: Root Jest 29 multi-project configuration with
ts-jest; frontend tests run in jsdom from the dedicatedtests/frontend/folder.npm testruns backend and frontend projects together, whilenpm run test:frontendruns the focused frontend project. Existing pure-helper coverage is intests/frontend/admin-general-pure.spec.ts, which is the appropriate lightweight regression location and requires no browser UI. - Required Tools & Dependencies: No new system tools, global CLI utilities, package dependencies, persistent
/dataassets, orsetup.shchanges are required. The implementation uses built-in JavaScriptDateUTC construction/serialization and the existing Jest toolchain.
2. Impacted Files
- To Modify:
frontend/src/app/features/admin/general.pure.ts— maketoIsoUtcinterpret the numeric components of the UTC-labelleddatetime-localstring as UTC rather than as the browser's local timezone.tests/frontend/admin-general-pure.spec.ts— add a focused timezone regression proving the displayed UTC wall-clock components serialize unchanged and preserve existing empty/invalid behavior.
- To Create: None.
3. Proposed Changes
- Database / Schema Migration: No changes. The existing setting keys and backend zod schema already accept and persist canonical UTC ISO strings correctly.
- Backend Logic & APIs: No changes.
PUT /api/v1/admin/general/settingsalready validates timezone-aware ISO-8601 input, enforceseventEndUtc > eventStartUtc, and stores the payload without timezone conversion;GET /api/v1/event/statustherefore reflects whatever canonical instant the frontend sends. - Frontend UI Integration:
- Update
toIsoUtcingeneral.pure.tsto parse thedatetime-localyear, month, day, hour, minute, and optional second/fraction components as UTC components, then create the timestamp withDate.UTC(...)and returntoISOString(). - Preserve the helper's current contract for empty values (
'') and invalid values (return the original string), so the existing reactive-form validation and negative save paths remain unchanged. - Keep
toDatetimeLocalunchanged because it already renders backend timestamps from UTC getters. Together,toDatetimeLocal(iso)andtoIsoUtc(local)will become true timezone-independent inverses for the minute-precision native inputs used byAdminGeneralComponent. - Keep
AdminGeneralComponent.onSubmitand the service/API contract unchanged; both event fields already pass throughtoIsoUtc, so correcting the shared helper fixes start and end submissions without UI or backend rewiring.
- Update
4. Test Strategy
- Target Unit Test File:
tests/frontend/admin-general-pure.spec.ts. - Mocking Strategy: No external boundaries need mocking because the defect is entirely in a pure function. Add a minimal deterministic regression around
toIsoUtc('2027-03-15T08:30') === '2027-03-15T08:30:00.000Z'and the corresponding end value2027-03-17T16:45, explicitly exercising the America/Los_Angeles/PDT scenario without launching a UI. Prefer running the focused Jest process withTZ=America/Los_Angeles(or isolate a small child Jest invocation configured with that environment) so the test fails against the current local-time implementation and passes only when conversion is browser-timezone independent. Retain or extend the existing empty-input assertion and add only the key invalid-input assertion if needed to lock the helper's fallback contract. Verify with the root single-command suite (npm test) plus the existing root build/type-check path (npm run build); no visual confirmation or persistent test data is involved.