Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

08 — Form Specifications (Settings Module)

Every field of every Settings form/editor, field-by-field. Validation mirrors the class-validator decorators exactly from src/modules/settings/dto/update-setting.dto.ts; where the DTO has no decorator (key/value), the server accepts anything and a missing required field surfaces as a Mongoose validation error → 500 (OQ-3). Client validates inline first; the server remains the authority for group enum.


1. Upsert Form — PUT /settings (update-setting.dto.ts)

#FieldLabelType / EditorRequiredValidation (server)Client UX
1keyKeytext, monoyes (TS !)no decorators (update-setting.dto.ts:6-7) — missing/undefined → Mongoose required error → 500 (OQ-3)trim; non-empty; pattern hint ^[a-z0-9._-]+$ (convention, not enforced); error: "Enter a key"
2valueValuetyped editor by runtime type (string / number / boolean / JSON)yes (TS !)no decorators (update-setting.dto.ts:9-10) — any JSON accepted; stored raw (setting.schema.ts:21-22)type-specific (see §2); never coerced
3groupGroupAppDropdown (enum)no@IsEnum(SettingGroup) optional (update-setting.dto.ts:12-15) → 400 VALIDATION_ERROR with detailsdefault GENERAL (setting.schema.ts:24-25); dropdown restricts to 6 values
4labelLabeltextno@IsString() optional (update-setting.dto.ts:17-20)hidden — never persisted (settings.service.ts:25 drops it)
5descriptionDescriptiontextno@IsString() optional (update-setting.dto.ts:22-25)hidden — never persisted

Server 400 details mapping: invalid groupdetails: [{message: "group must be one of the following values: academic, attendance, grading, notification, theme, general"}] (http-exception.filter.ts:103-108).

Submit behavior: save → PUT /settings → 200 returns the saved doc (setting.repository.ts:35-39, new: true); form reconciles to server truth. Retry-safe (idempotent upsert) — a network retry never duplicates.

2. Value-type-specific editing (core form behavior)

TypeEditorFormatting / formattersLocal validationServer
stringsingle-line AppTextFieldnone; mono for key-like valuesnon-empty (unless the key was created with an empty string — allowed)stored as-is
numbernumeric AppTextFieldFilteringTextInputFormatter.allow(RegExp(r'[0-9.\-]'))double.tryParse != nullstored as JSON number (value: unknown$set {value} raw, setting.repository.ts:37)
booleanAppSwitch (SwitchListTile)stored as JSON true/false; instant save on toggle
object / array / nullAppJsonEditor (mono, multi-line)pretty-print on save (JsonEncoder.withIndent(' '))jsonDecode must succeedstored as raw JSON object
unknownJSON editor fallbacksamesame

Rule: no type coercion on save — a numeric-looking string stays a string; the client never guesses. Type chips in the list re-derive from the last server response.

3. New Setting Form (FAB sheet)

Fields: key (1), group (3), value as JSON editor (type unknown at creation). On success → row appears in its group; group move after creation = edit the group dropdown and save again (upsert persists group when present, setting.repository.ts:37).

4. Batch Save — PUT /settings/bulk

AspectContract
RequestJSON array of UpdateSettingDto (settings.controller.ts:43-47)
Serversequential upsert loop, all results returned (settings.service.ts:28-34) — not transactional (OQ-4)
Clientonly dirty keys serialized; each item = the full {key, value, group} (never partial {value} — an omitted group on an existing row is fine, but sending the known group is the stable form)
Failure"Saved N of M" + per-row retry; re-send the full dirty set (idempotent)
Duplicate keys in one batchlast item wins (loop order) — client dedupes by key before sending

5. Delete — no form

DELETE /settings/:key (settings.controller.ts:49-53) — confirm dialog only; no body. 404 → treat as removed. Soft-delete consequence: re-creating the key fails with E11000 → 500 (OQ-5); dialog copy warns.

Form-level rules (all)

  • Double-submit: Save disabled while pending (00-shared/08 §6).
  • Optimistic: explicit-save editors are server-confirm; boolean toggle is the only optimistic write (rollback on error — 00-shared/06 §3.5).
  • Undo: none for delete (soft-delete not reversible through the API — OQ-5); value edits undo = re-edit (last-write-wins).
  • Abandonment: dirty explicit editors prompt "Discard changes?"; batch mode Cancel restores last-server values.
  • Keyboard: Enter saves single-line editors, Ctrl/Cmd+Enter saves JSON editor, Tab field order key → group → value; Esc cancels.
  • Error copy: business 4xx message allowed; codes drive the rest (00-shared/07 §11).

Client-side error priority

  1. 400 VALIDATION → field (group enum; JSON parse is client-side pre-submit).
  2. 401 UNAUTHENTICATED → silent refresh; fail → session expiry.
  3. 404 RESOURCE_NOT_FOUND (detail/delete) → treat as removed.
  4. 500 INTERNAL_SERVER_ERROR → generic + requestId; form kept (retry safe).
  5. 429 RATE_LIMITED → countdown (global api tier, 00-shared/07 §4).