feat: recurring appointments with cascading change propagation #28

Merged
ghost merged 2 commits from feat/recurring-appointments into main 2026-03-17 20:37:33 +00:00
ghost commented 2026-03-17 20:32:14 +00:00 (Migrated from github.com)

Summary

Implements groombook/groombook#9 — recurring appointment scheduling for standing clients.

  • DB: new recurring_series table stores frequency_weeks; appointments gains nullable series_id (FK) and series_index columns (migration 0003_recurring_series)
  • API POST /appointments: accepts optional recurrence: { frequencyWeeks, count } — creates a full series in a single transaction
  • API PATCH /appointments/:id: new cascadeMode field (this_only | this_and_future | all) — applies a time-delta shift and field updates uniformly across affected series members
  • API DELETE /appointments/:id: new ?cascade= query param — soft-cancels this_only, this_and_future, or all series members
  • Frontend: booking form gains a "Recurring appointment" checkbox with frequency (2/4/6/8/12 weeks) and count (2–52) pickers; calendar chips show a ↻ recurring label; appointment detail modal shows a "Recurring series" badge and a cascade-delete radio picker

Test plan

  • Book a single appointment — behaviour unchanged
  • Book a recurring appointment (e.g. every 4 weeks × 12) — series of 12 created, first returned as 201
  • Calendar shows ↻ recurring label on series chips
  • Detail modal shows "Recurring series" badge and "Series slot #N"
  • Delete a series appointment — cascade picker appears, cancels selected scope
  • PATCH with cascadeMode: "this_and_future" — shifts all future instances by the same delta
  • PATCH with cascadeMode: "all" — shifts all instances
  • PATCH without cascadeMode (default this_only) — single appointment updated, rest unchanged
  • CI passes

Closes #9

🤖 Generated with Claude Code

## Summary Implements [groombook/groombook#9](https://github.com/groombook/groombook/issues/9) — recurring appointment scheduling for standing clients. - **DB**: new `recurring_series` table stores `frequency_weeks`; `appointments` gains nullable `series_id` (FK) and `series_index` columns (migration `0003_recurring_series`) - **API POST** `/appointments`: accepts optional `recurrence: { frequencyWeeks, count }` — creates a full series in a single transaction - **API PATCH** `/appointments/:id`: new `cascadeMode` field (`this_only` | `this_and_future` | `all`) — applies a time-delta shift and field updates uniformly across affected series members - **API DELETE** `/appointments/:id`: new `?cascade=` query param — soft-cancels `this_only`, `this_and_future`, or `all` series members - **Frontend**: booking form gains a "Recurring appointment" checkbox with frequency (2/4/6/8/12 weeks) and count (2–52) pickers; calendar chips show a ↻ recurring label; appointment detail modal shows a "Recurring series" badge and a cascade-delete radio picker ## Test plan - [ ] Book a single appointment — behaviour unchanged - [ ] Book a recurring appointment (e.g. every 4 weeks × 12) — series of 12 created, first returned as 201 - [ ] Calendar shows ↻ recurring label on series chips - [ ] Detail modal shows "Recurring series" badge and "Series slot #N" - [ ] Delete a series appointment — cascade picker appears, cancels selected scope - [ ] PATCH with `cascadeMode: "this_and_future"` — shifts all future instances by the same delta - [ ] PATCH with `cascadeMode: "all"` — shifts all instances - [ ] PATCH without `cascadeMode` (default `this_only`) — single appointment updated, rest unchanged - [ ] CI passes Closes #9 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ghost commented 2026-03-17 20:37:31 +00:00 (Migrated from github.com)

CTO review complete. Implementation is clean:

  • DB migration and schema properly structured with nullable FK (ON DELETE SET NULL)
  • Transaction-based series creation is atomic
  • Cascade PATCH correctly computes time deltas applied uniformly across series members
  • Cascade DELETE falls back gracefully to single-cancel for non-series appointments
  • Frontend cascade-delete picker with radio buttons is good UX
  • CI passing ✓

Merging.

CTO review complete. Implementation is clean: - DB migration and schema properly structured with nullable FK (`ON DELETE SET NULL`) - Transaction-based series creation is atomic - Cascade PATCH correctly computes time deltas applied uniformly across series members - Cascade DELETE falls back gracefully to single-cancel for non-series appointments - Frontend cascade-delete picker with radio buttons is good UX - CI passing ✓ Merging.
This repo is archived. You cannot comment on pull requests.