style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
@@ -3,7 +3,7 @@ phase: 06-ux-polish
|
||||
plan: 06
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["06-01", "06-02", "06-03", "06-05"]
|
||||
depends_on: ['06-01', '06-02', '06-03', '06-05']
|
||||
files_modified:
|
||||
- apps/pwa/src/components/EventForm.tsx
|
||||
- apps/pwa/src/components/SeriesEditPrompt.tsx
|
||||
@@ -12,31 +12,31 @@ autonomous: false
|
||||
requirements: []
|
||||
must_haves:
|
||||
truths:
|
||||
- "Scope fence (D-01/D-02): this phase delivers only the six promoted polish items (999.2/3/6/7/8/9); 999.4 reminders/VALARM, 999.5 provider setup, and 999.1 provider abstraction are NOT built here (deferred to milestone 1.1)"
|
||||
- 'Scope fence (D-01/D-02): this phase delivers only the six promoted polish items (999.2/3/6/7/8/9); 999.4 reminders/VALARM, 999.5 provider setup, and 999.1 provider abstraction are NOT built here (deferred to milestone 1.1)'
|
||||
- "Moving an event's start moves its end with it, preserving duration; the end never strands behind the start (D-03/D-04, success criterion 2)"
|
||||
- "A recurring event can be bounded in the form via 'Ends: Never / On date / After N times' (D-06, success criterion 2)"
|
||||
- "Editing a recurring occurrence prompts 'Edit recurring series' before saving the whole-series change (D-08/D-09, success criterion 3)"
|
||||
- "The all-day-edit off-by-one stays fixed — re-editing an all-day event does not grow it by a day (D-05 verify, success criterion 2)"
|
||||
- "All-day events are visually distinct from timed events at a glance (999.6/D-12, success criterion 1)"
|
||||
- 'The all-day-edit off-by-one stays fixed — re-editing an all-day event does not grow it by a day (D-05 verify, success criterion 2)'
|
||||
- 'All-day events are visually distinct from timed events at a glance (999.6/D-12, success criterion 1)'
|
||||
artifacts:
|
||||
- path: "apps/pwa/src/components/EventForm.tsx"
|
||||
provides: "start onChange handlers that call computeNewTimedEnd/computeNewAllDayEnd; recurrence-bound control; hasRrule-gated series-edit confirmation"
|
||||
contains: "computeNewTimedEnd"
|
||||
- path: "apps/pwa/src/components/SeriesEditPrompt.tsx"
|
||||
provides: "whole-series edit confirmation sheet/dialog (focus trap, Escape=cancel)"
|
||||
contains: "Update series"
|
||||
- path: "apps/pwa/src/styles/index.css"
|
||||
provides: "Schedule-X all-day chip override (full-width filled pill)"
|
||||
contains: "sx__all-day-event"
|
||||
- path: 'apps/pwa/src/components/EventForm.tsx'
|
||||
provides: 'start onChange handlers that call computeNewTimedEnd/computeNewAllDayEnd; recurrence-bound control; hasRrule-gated series-edit confirmation'
|
||||
contains: 'computeNewTimedEnd'
|
||||
- path: 'apps/pwa/src/components/SeriesEditPrompt.tsx'
|
||||
provides: 'whole-series edit confirmation sheet/dialog (focus trap, Escape=cancel)'
|
||||
contains: 'Update series'
|
||||
- path: 'apps/pwa/src/styles/index.css'
|
||||
provides: 'Schedule-X all-day chip override (full-width filled pill)'
|
||||
contains: 'sx__all-day-event'
|
||||
key_links:
|
||||
- from: "apps/pwa/src/components/EventForm.tsx"
|
||||
to: "apps/pwa/src/lib/eventDateTime.ts"
|
||||
via: "start onChange → computeNewTimedEnd / computeNewAllDayEnd"
|
||||
pattern: "computeNewTimedEnd|computeNewAllDayEnd"
|
||||
- from: "apps/pwa/src/components/EventForm.tsx"
|
||||
to: "apps/pwa/src/api/client.ts"
|
||||
via: "payload carries recurrenceUntil/recurrenceCount; occurrence.hasRrule gates the prompt"
|
||||
pattern: "recurrenceUntil|recurrenceCount|hasRrule"
|
||||
- from: 'apps/pwa/src/components/EventForm.tsx'
|
||||
to: 'apps/pwa/src/lib/eventDateTime.ts'
|
||||
via: 'start onChange → computeNewTimedEnd / computeNewAllDayEnd'
|
||||
pattern: 'computeNewTimedEnd|computeNewAllDayEnd'
|
||||
- from: 'apps/pwa/src/components/EventForm.tsx'
|
||||
to: 'apps/pwa/src/api/client.ts'
|
||||
via: 'payload carries recurrenceUntil/recurrenceCount; occurrence.hasRrule gates the prompt'
|
||||
pattern: 'recurrenceUntil|recurrenceCount|hasRrule'
|
||||
---
|
||||
|
||||
<objective>
|
||||
@@ -67,12 +67,13 @@ Output: EventForm end-tracking handlers + recurrence-bound control + series-edit
|
||||
|
||||
<artifacts_this_plan_produces>
|
||||
NEW symbols introduced here (exclude from drift/convergence checks):
|
||||
|
||||
- Start `onChange` handlers in `EventForm.tsx` that call `computeNewTimedEnd`/`computeNewAllDayEnd`
|
||||
- `recurrenceBound: 'never'|'until'|'count'`, `recurrenceUntil: string`, `recurrenceCount: number` state + the "Ends" control in `EventForm.tsx`
|
||||
- `SeriesEditPrompt` component (`apps/pwa/src/components/SeriesEditPrompt.tsx`)
|
||||
- `.sx__all-day-event` CSS override block in `apps/pwa/src/styles/index.css`
|
||||
NOTE: `computeNewTimedEnd`, `computeNewAllDayEnd`, `recurrenceUntil`/`recurrenceCount` payload fields, and `hasRrule` are NOT new here — they are consumed from Plans 01/05.
|
||||
</artifacts_this_plan_produces>
|
||||
NOTE: `computeNewTimedEnd`, `computeNewAllDayEnd`, `recurrenceUntil`/`recurrenceCount` payload fields, and `hasRrule` are NOT new here — they are consumed from Plans 01/05.
|
||||
</artifacts_this_plan_produces>
|
||||
|
||||
<tasks>
|
||||
|
||||
@@ -193,21 +194,23 @@ NOTE: `computeNewTimedEnd`, `computeNewAllDayEnd`, `recurrenceUntil`/`recurrence
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| Boundary | Description |
|
||||
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| client → API (PATCH /api/events/:uid/edit) | Whole-series edit PUTs the master VEVENT back to Fastmail; the new `recurrenceUntil`/`recurrenceCount` cross here (validated server-side in Plan 02). |
|
||||
| user input → form state | Recurrence bound date/count are user inputs shaped in the form before submit. |
|
||||
| user input → form state | Recurrence bound date/count are user inputs shaped in the form before submit. |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-06-06-input | Tampering | recurrence bound inputs (EventForm) | mitigate | Form-side validation (count ≥ 1, until ≥ start) plus the authoritative server-side Zod validation from Plan 02 (`recurrenceUntil` max-10, `recurrenceCount` int≥1) — the client check is UX, the server check is the enforcement boundary. Defense in depth; no raw passthrough. (ASVS V5.) |
|
||||
| T-06-06-series | Tampering | whole-series edit PUT (EventForm → existing /edit route) | mitigate | Reuses the existing edit route's ownership + objectUrl/etag lookup (unchanged from Phase 3) — the prompt only gates the UX; it adds no new privilege. The PUT replaces the master VEVENT for the caller's own event only; access scope is the existing per-user filter. |
|
||||
| T-06-06-xss | Tampering / XSS | all-day pill label, prompt copy | accept | All-day labels and prompt text render as plain-text JSX children (existing EventForm XSS posture, T-03-15) — no `dangerouslySetInnerHTML`; the CSS override sets presentation only. No new injection surface. |
|
||||
| T-06-06-SC | Tampering | npm installs | accept | No package installs (zero new deps). |
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
| -------------- | --------------- | -------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| T-06-06-input | Tampering | recurrence bound inputs (EventForm) | mitigate | Form-side validation (count ≥ 1, until ≥ start) plus the authoritative server-side Zod validation from Plan 02 (`recurrenceUntil` max-10, `recurrenceCount` int≥1) — the client check is UX, the server check is the enforcement boundary. Defense in depth; no raw passthrough. (ASVS V5.) |
|
||||
| T-06-06-series | Tampering | whole-series edit PUT (EventForm → existing /edit route) | mitigate | Reuses the existing edit route's ownership + objectUrl/etag lookup (unchanged from Phase 3) — the prompt only gates the UX; it adds no new privilege. The PUT replaces the master VEVENT for the caller's own event only; access scope is the existing per-user filter. |
|
||||
| T-06-06-xss | Tampering / XSS | all-day pill label, prompt copy | accept | All-day labels and prompt text render as plain-text JSX children (existing EventForm XSS posture, T-03-15) — no `dangerouslySetInnerHTML`; the CSS override sets presentation only. No new injection surface. |
|
||||
| T-06-06-SC | Tampering | npm installs | accept | No package installs (zero new deps). |
|
||||
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
@@ -218,12 +221,13 @@ NOTE: `computeNewTimedEnd`, `computeNewAllDayEnd`, `recurrenceUntil`/`recurrence
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
|
||||
- D-03/D-04 (criterion 2): end follows start with a floor.
|
||||
- D-06 (criterion 2): recurrence is boundable; D-07: FREQ persists.
|
||||
- D-08/D-09 (criterion 3): whole-series edit behind a confirmation prompt.
|
||||
- D-05 (criterion 2): all-day edit off-by-one stays fixed.
|
||||
- 999.6/D-12 (criterion 1): all-day events visually distinct.
|
||||
</success_criteria>
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/06-ux-polish/06-06-SUMMARY.md` when done (note playwright-cli observations for each behavior).
|
||||
|
||||
Reference in New Issue
Block a user