Files
chore/.github/specs/plan-routinesFeature.prompt.md
Ryan Kegel 6bf10fda2f
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m23s
feat: implement routines feature for child and parent modes
- Added backend models for routines, routine items, and schedules.
- Created API endpoints for managing routines and their items.
- Implemented frontend components for routine creation, detail view, and assignment.
- Integrated routines into child view with a scrolling list and approval workflow.
- Added push notifications for routine confirmations and pending approvals.
- Refactored existing components to accommodate new routines functionality.
- Updated tests to cover new routines feature and ensure proper functionality.
2026-04-28 23:30:52 -04:00

14 KiB

Plan: Routines Feature

Summary

A "Routines" system lets parents define a named checklist of simple items (e.g., "Morning Routine": Make Bed, Get Dressed, Eat Breakfast) worth X points. Children see routines in a scrollable list between Chores and Rewards in child mode. Tapping a routine opens a detail view showing the item list; a "Done" button submits it for parent approval. Points are awarded on parent approval. Supports scheduling (days/interval), deadlines, time extension, and per-child point overrides — all parallel to the existing chore system.


Key Design Decisions

  • Routine items are their own minimal entity (name + optional image, no points). Points belong to the routine.
  • No per-item completion tracking — detail screen is informational only. "Done" button submits the whole routine.
  • Assignment: per-child, same pattern as tasks (child.routines: list[str]).
  • Parent approval: approve/reject the whole routine (no item-level detail).
  • Scheduling: new RoutineSchedule model parallel to ChoreSchedule (same structure, routine_id instead of task_id).
  • Point overrides: reuse ChildOverride with entity_type='routine'.
  • Pending confirmations: extend PendingConfirmation entity_type to include 'routine'.
  • Routine editor: single-page with details section (name, points, image) + items sub-panel below.

Phase 1: Backend Models & DB

  1. Create backend/models/routine.py — fields: name, points, image_id, user_id (inherits BaseModel). Mirror Task model.
  2. Create backend/models/routine_item.py — fields: routine_id, name, image_id, order (int). No points.
  3. Create backend/models/routine_schedule.py — copy of ChoreSchedule replacing task_id→routine_id. Same DayConfig, modes, deadline fields.
  4. Create backend/models/routine_extension.py — fields: child_id, routine_id, date (ISO). Mirror TaskExtension.
  5. Extend backend/models/pending_confirmation.py — add 'routine' to entity_type Literal.
  6. Extend backend/models/child.py — add routines: list[str] field (default=[]).
  7. Create DB layers (mirror existing patterns):
    • backend/db/routines.py — get/add/update/delete/list by user
    • backend/db/routine_items.py — get_items_for_routine/add/update/delete/delete_for_routine
    • backend/db/routine_schedules.py — get/upsert/delete/delete_for_child/delete_for_routine
    • backend/db/routine_extensions.py — get/add/delete_for_child_routine
  8. Extend backend/db/child_overrides.py entity_type to allow 'routine'.

Phase 2: Backend SSE Events

  1. Create event type files (mirror existing pattern):
    • backend/events/types/routine_modified.py — payload: routine_id, operation (ADD|EDIT|DELETE)
    • backend/events/types/child_routines_set.py — payload: child_id, routine_ids
    • backend/events/types/routine_schedule_modified.py — payload: child_id, routine_id, operation (SET|DELETED)
    • backend/events/types/routine_time_extended.py — payload: child_id, routine_id
    • backend/events/types/child_routine_confirmation.py — payload: child_id, routine_id, operation (PENDING|APPROVED|REJECTED|RESET)
  2. Update backend/events/types/event_types.py — add: ROUTINE_MODIFIED, CHILD_ROUTINES_SET, ROUTINE_SCHEDULE_MODIFIED, ROUTINE_TIME_EXTENDED, CHILD_ROUTINE_CONFIRMATION

Phase 3: Backend API

  1. Create backend/api/routine_api.py:
    • PUT /routine/add — create routine
    • GET /routine/<id> — fetch single
    • GET /routine/list — list by user
    • PUT /routine/<id>/edit — update
    • DELETE /routine/<id> — delete (cascade: remove from all children, delete items, schedules, overrides)
  2. Create backend/api/routine_item_api.py:
    • PUT /routine/<routine_id>/item/add — add item
    • PUT /routine/<routine_id>/item/<item_id>/edit — edit item name/image
    • DELETE /routine/<routine_id>/item/<item_id> — remove item
    • GET /routine/<routine_id>/items — list items
  3. Create backend/api/child_routine_api.py:
    • POST /child/<id>/assign-routine — add routine to child
    • POST /child/<id>/remove-routine — remove from child
    • PUT /child/<id>/set-routines — replace all assigned routines
    • GET /child/<id>/list-routines — list assigned routines with schedule, pending_status, extension_date, image_url, custom_value, and embedded items
    • GET /child/<id>/list-assignable-routines — routines not yet assigned
    • POST /child/<id>/confirm-routine — child submits routine as pending (creates PendingConfirmation entity_type='routine')
    • POST /child/<id>/cancel-routine-confirmation — cancel pending
  4. Create backend/api/routine_schedule_api.py:
    • GET /child/<child_id>/routine/<routine_id>/schedule — fetch
    • PUT /child/<child_id>/routine/<routine_id>/schedule — create/update
    • DELETE /child/<child_id>/routine/<routine_id>/schedule — delete
    • POST /child/<child_id>/routine/<routine_id>/extend — extend deadline
  5. Extend backend/api/pending_confirmation.py:
    • Add GET /pending-confirmations?type=routine support (or ensure existing endpoint includes routines)
    • Add POST /child/<id>/approve-routine/<confirmation_id> — approve (award points via override or routine.points)
    • Add POST /child/<id>/reject-routine/<confirmation_id> — reject
    • Add POST /child/<id>/reset-routine/<confirmation_id> — reset
  6. Update backend/api/child_api.py — cascade delete routines/schedules/extensions when child deleted.
  7. Update backend/main.py — register all new blueprints.

Phase 4: TypeScript Models & API Helpers

  1. Update frontend/src/common/models.ts:
    • Add Routine (id, name, points, image_id)
    • Add RoutineItem (id, routine_id, name, image_id, order)
    • Add ChildRoutine (extends Routine + custom_value, schedule, extension_date, pending_status, approved_at, items: RoutineItem[])
    • Add RoutineSchedule (mirror ChoreSchedule with routine_id)
    • Add new SSE payload types: RoutineModifiedEventPayload, ChildRoutinesSetEventPayload, RoutineScheduleModifiedPayload, RoutineTimeExtendedPayload, ChildRoutineConfirmationPayload
  2. Update frontend/src/common/backendEvents.ts — add new event type string constants.
  3. Update frontend/src/common/api.ts — add helpers: confirmRoutine(), cancelRoutineConfirmation(), setChildRoutineOverride().

Phase 5: Frontend — Child Mode

  1. Create frontend/src/components/routine/RoutineDetailView.vue:
    • Receives childId + routineId as route params
    • Fetches routine data (name, points, image, items list) via GET /child/<id>/list-routines (or dedicated detail endpoint)
    • Displays routine header (name, image, points)
    • Vertical card list of items (name + image, non-interactive)
    • "Done" button → RoutineConfirmDialog → calls confirmRoutine() → routine becomes 'pending'
    • If pending_status='pending': "Done" shows cancel dialog instead
    • If approved today: shows "COMPLETED" stamp (read-only)
    • If expired: shows "TOO LATE" (no action)
    • Back navigation to ChildView
    • Register SSE child_routine_confirmation to update status reactively
  2. Update frontend/src/components/child/ChildView.vue:
    • Add routines: ref<string[]> and childRoutineListRef
    • Add Routines ScrollingList between Chores list and Rewards list
      • fetchBaseUrl: /api/child/${child.id}/list-routines
      • itemKey: 'routines'
      • filter-fn: filter by schedule (isScheduledToday equivalent for routines)
      • sort-fn: completed → pending → scheduled → general
      • getItemClass: similar chore-inactive logic for expired/completed
    • On routine click → navigate to RoutineDetailView route instead of triggering inline
    • Register new SSE handlers: routine_modified, child_routines_set, routine_schedule_modified, routine_time_extended, child_routine_confirmation
    • Expiry timer logic for routine deadlines (parallel to existing chore timer logic)
  3. Add routes:
    • /child/:id/routine/:routineId → RoutineDetailView

Phase 6: Frontend — Parent Mode (Routine Library)

  1. Create frontend/src/components/routine/RoutineEditor.vue:
    • Top section: EntityEditForm-style fields — name (text), points (number), image picker
    • Bottom section: Items sub-panel
      • List of existing items (name + image thumbnail + delete button)
      • "Add item" row: inline input for name + optional image picker + confirm button
      • Each item has edit-in-place or edit button
    • Save button submits both routine details and item changes
    • On edit mode: pre-populate all fields and items
  2. Create frontend/src/views/parent/RoutinesView.vue:
    • ItemList of all routines with add/edit/delete
    • Add → RoutineEditor (create mode)
    • Edit → RoutineEditor (edit mode)
  3. Add parent routes under TaskSubNav (4th tab — "Routines"):
    • /parent/tasks/routines — library list (RoutinesView)
    • /parent/tasks/routines/add — create (RoutineEditor)
    • /parent/tasks/routines/:id/edit — edit (RoutineEditor)
  4. Add tab to frontend/src/components/task/TaskSubNav.vue — "Routines" tab pointing to /parent/tasks/routines

Phase 7: Frontend — Parent Mode (Per-Child Routine Management)

  1. Extend ParentView (or child management component) to include a "Routines" section per child:
    • ItemList showing child's assigned routines
    • Assign button → RoutineAssignView (parallel to ChoreAssignView)
    • Kebab menu per routine item:
      • "Edit Routine" → navigate to /parent/tasks/routines/:id/edit
      • "Set Schedule" → open ScheduleModal with entityType='routine'
      • "Edit Points" → set ChildOverride with entity_type='routine'
      • "Extend Deadline" → call extend endpoint
    • Register SSE events to refresh list: routine_modified, child_routines_set, routine_schedule_modified, routine_time_extended, child_routine_confirmation, child_override_set
  2. Create frontend/src/components/routine/RoutineAssignView.vue — selectable ItemList of unassigned routines (parallel to ChoreAssignView).
  3. Extend pending confirmation approval UI — if entity_type='routine', fetch routine name and show in approval card. Approve → POST approve-routine endpoint. Reject → POST reject-routine.

Phase 8: Push Notifications for Routine Pending

  1. In backend/api/child_routine_api.py — after creating the PendingConfirmation for a routine, call send_push_to_user(user_id, payload) (mirror child_api.py chore confirmation pattern). Payload: type='routine_confirmed', title = "Routine Pending", body = "{child_name} completed {routine_name}", include approve/reject action tokens.

Phase 9: ScheduleModal entityType Refactor

  1. Refactor ScheduleModal.vue — replace hard-coded task_id with entityType: 'task' | 'routine' + entityId props. All API calls to .../schedule and .../extend switch on entityType to route to either /child/<childId>/task/<entityId>/... or /child/<childId>/routine/<entityId>/....
  2. Update all current ScheduleModal usages to explicitly pass entityType='task' so existing behavior is preserved.
  3. Routine kebab "Set Schedule" passes entityType='routine'.

Relevant Files

New backend:

  • backend/models/routine.py, routine_item.py, routine_schedule.py, routine_extension.py
  • backend/db/routines.py, routine_items.py, routine_schedules.py, routine_extensions.py
  • backend/api/routine_api.py, routine_item_api.py, child_routine_api.py, routine_schedule_api.py
  • backend/events/types/routine_modified.py, child_routines_set.py, routine_schedule_modified.py, routine_time_extended.py, child_routine_confirmation.py

Modified backend:

  • backend/models/child.py — add routines field
  • backend/models/pending_confirmation.py — extend entity_type Literal
  • backend/db/child_overrides.py — allow 'routine' entity_type
  • backend/api/child_api.py — cascade deletes
  • backend/api/pending_confirmation.py — routine approval endpoints
  • backend/events/types/event_types.py — new constants
  • backend/main.py — register blueprints

New frontend:

  • frontend/src/components/routine/RoutineEditor.vue
  • frontend/src/components/routine/RoutineDetailView.vue
  • frontend/src/components/routine/RoutineAssignView.vue
  • frontend/src/views/parent/RoutinesView.vue

Modified frontend:

  • frontend/src/common/models.ts — new interfaces + SSE payload types
  • frontend/src/common/backendEvents.ts — new event constants
  • frontend/src/common/api.ts — new helpers
  • frontend/src/components/child/ChildView.vue — add routines list + navigation
  • frontend/src/components/task/TaskSubNav.vue — add Routines tab
  • frontend/src/components/shared/ScheduleModal.vue — entityType refactor
  • ParentView component — add routines section
  • Router — new routes

Reference patterns:

  • backend/api/chore_api.py + chore_schedule_api.py — mirror for routine equivalents
  • backend/models/chore_schedule.py — copy for RoutineSchedule
  • backend/models/task_extension.py — copy for routine_extension.py
  • frontend/src/components/shared/ScrollingList.vue — reuse for routines in child view
  • frontend/src/components/shared/EntityEditForm.vue — reuse in RoutineEditor top section
  • backend/utils/push_sender.py + child_api.py chore confirm (~L1186) — push notification pattern

Verification

  1. Create a routine with 2+ items via Tasks → Routines tab, assign to a child, verify it appears in child view
  2. Child submits "Done" → push notification fires → pending confirmation appears in parent view → approve → points credited
  3. Reject flow → no points awarded
  4. Schedule a routine for specific days → verify it only appears on those days
  5. Set a deadline → verify "TOO LATE" stamp after deadline passes
  6. Extend deadline via kebab → verify stamp removed for that day
  7. Set per-child point override → verify override value shown and applied on approval
  8. Delete routine → cascades (removed from children, items/schedules/extensions/overrides deleted)
  9. SSE: parent sees routine confirmation in notifications without page refresh
  10. ScheduleModal: existing chore schedule still works after entityType refactor

Out of Scope

  • Reordering routine items (order field exists but no drag-and-drop UI planned)
  • Per-item completion tracking