- Implemented ChoreAssignView for assigning chores to children. - Created ChoreConfirmDialog for confirming chore completion. - Developed KindnessAssignView for assigning kindness acts. - Added PenaltyAssignView for assigning penalties. - Introduced ChoreEditView and ChoreView for editing and viewing chores. - Created KindnessEditView and KindnessView for managing kindness acts. - Developed PenaltyEditView and PenaltyView for managing penalties. - Added TaskSubNav for navigation between chores, kindness acts, and penalties.
39 KiB
Feature: Chore Completion Confirmation + Task Refactor
Overview
Goal: Refactor the "task" concept into three distinct entity types — Chore, Kindness, and Penalty — and implement a chore completion confirmation flow where children can confirm chores and parents approve them.
User Stories:
- As a child, I can click on a chore and confirm that I completed it. I see a PENDING banner (yellow) until a parent confirms.
- As a child, I can click an already PENDING chore and cancel my confirmation.
- As a child, I see a COMPLETED banner (green) on a chore that a parent has approved. That chore is disabled for the rest of the day.
- As a parent, I see pending chore confirmations in the Notifications tab alongside pending reward requests.
- As a parent, I can click a PENDING chore to approve it (awarding points) or reject it (resetting to available).
- As a parent, I can click a non-pending/non-completed chore and award points directly (current behavior). The child view then shows the COMPLETED banner.
- As a parent, I can reset a completed chore from the kebab menu so the child can confirm it again (points are kept).
- As an admin, I can view full tracking history in the database/logs for all confirmation lifecycle events.
Rules: .github/copilot-instructions.md
Design Decisions (Resolved)
Task Refactor → Chore / Kindness / Penalty
Decision: Full refactor.
| Old Concept | New Concept | Behavior |
|---|---|---|
Task with is_good=true (schedulable) |
Chore | Scheduled, expirable, confirmable by child |
Task with is_good=true (ad-hoc, e.g. "Child was good today") |
Kindness | Parent-only award, not confirmable |
Task with is_good=false |
Penalty | Parent-only deduction |
- The
is_goodfield is removed. Entity type itself determines point direction. - The
Taskmodel is retained in the backend but gains atypefield:'chore' | 'kindness' | 'penalty'. task_api.pyis split intochore_api.py,kindness_api.py,penalty_api.py.- Existing
is_good=truetasks are auto-classified as chore;is_good=falseas penalty. - Kindness items must be manually created post-migration (acceptable).
Merged Pending Table
Decision: Single PendingConfirmation model replaces PendingReward.
- Both pending reward requests and pending chore confirmations live in one
pending_confirmationstable, differentiated byentity_type. - The
/pending-rewardsendpoint is replaced by/pending-confirmations. pending_rewards.jsonDB file is replaced bypending_confirmations.json.
"Completed Today" Tracking
Decision: PendingConfirmation record with status='approved' + approved_at timestamp.
- An approved
PendingConfirmationrecord persists (DB-backed, survives restart) and serves as the "completed today" marker. - The frontend checks if
approved_atis today to determine the COMPLETED state. - On reset, the record is deleted (status returns to available).
- Multi-completion history is preserved via
TrackingEvent— each confirm/approve/reset cycle generates tracking entries. QueryTrackingEventbychild_id + entity_id + date + action='approved'to count completions per day.
Navigation
Decision: Sub-nav under "Tasks" tab.
- Top-level nav stays 4 items: Children | Tasks | Rewards | Notifications
- The "Tasks" tab opens a view with 3 sub-tabs: Chores | Kindness | Penalties
- Each sub-tab has its own list view, edit view, and assign view.
- No mobile layout changes needed to the top bar.
Chore Confirmation Scoping
- Each
PendingConfirmationis scoped to a single child. If a chore is assigned to multiple children, each confirms independently. - Expired chores cannot be confirmed.
- A chore that is already PENDING or COMPLETED today cannot be confirmed again (unless reset by parent).
Data Model Changes
Backend Models
Task Model (Modified)
File: backend/models/task.py
@dataclass
class Task(BaseModel):
name: str
points: int
type: Literal['chore', 'kindness', 'penalty'] # replaces is_good
image_id: str | None = None
user_id: str | None = None
is_good: bool→ removedtype: Literal['chore', 'kindness', 'penalty']→ added- Migration:
is_good=True→type='chore',is_good=False→type='penalty'
PendingConfirmation Model (New — replaces PendingReward)
File: backend/models/pending_confirmation.py
@dataclass
class PendingConfirmation(BaseModel):
child_id: str
entity_id: str # task_id or reward_id
entity_type: str # 'chore' | 'reward'
user_id: str
status: str = "pending" # 'pending' | 'approved' | 'rejected'
approved_at: str | None = None # ISO 8601 UTC timestamp, set on approval
- Replaces
PendingReward(which hadchild_id,reward_id,user_id,status) entity_idgeneralizesreward_idto work for both chores and rewardsentity_typedifferentiates between chore confirmations and reward requestsapproved_atenables "completed today" checks
TrackingEvent Model (Extended Types)
File: backend/models/tracking_event.py
EntityType = Literal['task', 'reward', 'penalty', 'chore', 'kindness']
ActionType = Literal['activated', 'requested', 'redeemed', 'cancelled', 'confirmed', 'approved', 'rejected', 'reset']
New actions:
confirmed— child marks chore as doneapproved— parent approves chore completion (points awarded)rejected— parent rejects chore completion (no point change)reset— parent resets a completed chore (no point change)
ChildOverride Model (Extended Types)
File: backend/models/child_override.py
entity_type: Literal['task', 'reward'] # → Literal['chore', 'kindness', 'penalty', 'reward']
ChildTask DTO (Modified)
File: backend/api/child_tasks.py
class ChildTask:
def __init__(self, name, type, points, image_id, id):
self.id = id
self.name = name
self.type = type # replaces is_good
self.points = points
self.image_id = image_id
SSE Event Types (New)
File: backend/events/types/event_types.py
class EventType(Enum):
# ... existing ...
CHILD_CHORE_CONFIRMATION = "child_chore_confirmation"
New payload class — File: backend/events/types/child_chore_confirmation.py
class ChildChoreConfirmation(Payload):
# child_id: str
# task_id: str
# operation: 'CONFIRMED' | 'APPROVED' | 'REJECTED' | 'CANCELLED' | 'RESET'
Error Codes (New)
File: backend/api/error_codes.py
class ErrorCodes:
# ... existing ...
CHORE_EXPIRED = "CHORE_EXPIRED"
CHORE_ALREADY_PENDING = "CHORE_ALREADY_PENDING"
CHORE_ALREADY_COMPLETED = "CHORE_ALREADY_COMPLETED"
PENDING_NOT_FOUND = "PENDING_NOT_FOUND"
INSUFFICIENT_POINTS = "INSUFFICIENT_POINTS"
Frontend Models
File: frontend/vue-app/src/common/models.ts
// Task — modified
export interface Task {
id: string;
name: string;
points: number;
type: "chore" | "kindness" | "penalty"; // replaces is_good
image_id: string | null;
image_url?: string | null;
}
// ChildTask — modified
export interface ChildTask {
id: string;
name: string;
type: "chore" | "kindness" | "penalty"; // replaces is_good
points: number;
image_id: string | null;
image_url?: string | null;
custom_value?: number | null;
schedule?: ChoreSchedule | null;
extension_date?: string | null;
}
// PendingConfirmation — new (replaces PendingReward)
export interface PendingConfirmation {
id: string;
child_id: string;
child_name: string;
child_image_id: string | null;
child_image_url?: string | null;
entity_id: string;
entity_type: "chore" | "reward";
entity_name: string;
entity_image_id: string | null;
entity_image_url?: string | null;
status: "pending" | "approved" | "rejected";
approved_at: string | null;
}
// EntityType — extended
export type EntityType = "chore" | "kindness" | "penalty" | "reward";
// ActionType — extended
export type ActionType =
| "activated"
| "requested"
| "redeemed"
| "cancelled"
| "confirmed"
| "approved"
| "rejected"
| "reset";
// SSE event payload — new
export interface ChildChoreConfirmationPayload {
child_id: string;
task_id: string;
operation: "CONFIRMED" | "APPROVED" | "REJECTED" | "CANCELLED" | "RESET";
}
Backend Implementation
API Changes
New Files
| File | Description |
|---|---|
backend/api/chore_api.py |
CRUD for chores (type='chore'). Routes: /chore/add, /chore/<id>, /chore/<id>/edit, /chore/list, DELETE /chore/<id> |
backend/api/kindness_api.py |
CRUD for kindness acts (type='kindness'). Routes: /kindness/add, /kindness/<id>, /kindness/<id>/edit, /kindness/list, DELETE /kindness/<id> |
backend/api/penalty_api.py |
CRUD for penalties (type='penalty'). Routes: /penalty/add, /penalty/<id>, /penalty/<id>/edit, /penalty/list, DELETE /penalty/<id> |
backend/models/pending_confirmation.py |
PendingConfirmation dataclass |
backend/events/types/child_chore_confirmation.py |
SSE payload class |
backend/api/pending_confirmation.py |
Response DTO for hydrated pending confirmation |
Modified Files
| File | Changes |
|---|---|
backend/models/task.py |
is_good → type field |
backend/models/tracking_event.py |
Extend EntityType and ActionType literals |
backend/models/child_override.py |
Extend entity_type literal |
backend/api/child_tasks.py |
is_good → type field in DTO |
backend/api/child_api.py |
Add chore confirmation endpoints, replace /pending-rewards with /pending-confirmations, update trigger-task to set COMPLETED state, update all is_good references to type |
backend/api/task_api.py |
Deprecate/remove — logic moves to entity-specific API files |
backend/api/error_codes.py |
Add new error codes |
backend/events/types/event_types.py |
Add CHILD_CHORE_CONFIRMATION |
backend/db/db.py |
Add pending_confirmations_db, remove pending_reward_db |
backend/main.py |
Register new blueprints, remove task_api blueprint |
New Endpoints (on child_api.py)
| Method | Route | Actor | Description |
|---|---|---|---|
POST |
/child/<id>/confirm-chore |
Child | Body: { task_id }. Creates PendingConfirmation(entity_type='chore', status='pending'). Validates: chore assigned, not expired, not already pending/completed today. Tracking: action='confirmed', delta=0. SSE: CHILD_CHORE_CONFIRMATION (CONFIRMED). |
POST |
/child/<id>/cancel-confirm-chore |
Child | Body: { task_id }. Deletes the pending confirmation. Tracking: action='cancelled', delta=0. SSE: CHILD_CHORE_CONFIRMATION (CANCELLED). |
POST |
/child/<id>/approve-chore |
Parent | Body: { task_id }. Sets status='approved', approved_at=now(). Awards points (respects overrides). Tracking: action='approved', delta=+points. SSE: CHILD_CHORE_CONFIRMATION (APPROVED) + CHILD_TASK_TRIGGERED. |
POST |
/child/<id>/reject-chore |
Parent | Body: { task_id }. Deletes the pending confirmation. Tracking: action='rejected', delta=0. SSE: CHILD_CHORE_CONFIRMATION (REJECTED). |
POST |
/child/<id>/reset-chore |
Parent | Body: { task_id }. Deletes the approved confirmation record. Tracking: action='reset', delta=0. SSE: CHILD_CHORE_CONFIRMATION (RESET). |
GET |
/pending-confirmations |
Parent | Returns all pending PendingConfirmation records for the user, hydrated with child/entity names and images. Replaces /pending-rewards. |
Modified Endpoints
| Endpoint | Change | |
|---|---|---|
POST /child/<id>/trigger-task |
When a parent triggers a chore directly (no pending), create an approved PendingConfirmation so child view shows COMPLETED. Update entity_type references from 'task' to the actual type. |
|
POST /child/<id>/request-reward |
Create PendingConfirmation(entity_type='reward') instead of PendingReward. |
|
POST /child/<id>/cancel-request-reward |
Query PendingConfirmation by entity_type='reward' instead of PendingReward. |
|
POST /child/<id>/trigger-reward |
Query/remove PendingConfirmation by entity_type='reward' instead of PendingReward. |
|
GET /child/<id>/list-tasks |
Add pending_status and approved_at fields to each chore in the response (from PendingConfirmation lookup). |
|
PUT /child/<id>/set-tasks |
Accept type parameter instead of `type: 'good' |
'bad'`. |
Database Migration
A one-time migration script (backend/scripts/migrate_tasks_to_types.py):
- For each record in
tasks.json: ifis_good=True→ settype='chore', ifis_good=False→ settype='penalty'. Removeis_goodfield. - For each record in
pending_rewards.json: convert toPendingConfirmationformat withentity_type='reward',entity_id=reward_id. Write topending_confirmations.json. - For each record in
tracking_events.json: updateentity_type='task'→'chore'or'penalty'based on the referenced task's oldis_goodvalue. - For each record in
child_overrides.json: updateentity_type='task'→'chore'or'penalty'based on the referenced task's oldis_goodvalue.
Backend Tests
Test File: backend/tests/test_chore_api.py (New)
test_add_chore— PUT/chore/addwithname,points→ 201, type auto-set to'chore'test_add_chore_missing_fields— 400 withMISSING_FIELDStest_list_chores— GET/chore/listreturns onlytype='chore'taskstest_get_chore— GET/chore/<id>→ 200test_get_chore_not_found— 404test_edit_chore— PUT/chore/<id>/edit→ 200test_edit_system_chore_clones_to_user— editing auser_id=Nonechore creates a user copytest_delete_chore— DELETE/chore/<id>→ 200, removed from children's task liststest_delete_chore_not_found— 404test_delete_chore_removes_from_assigned_children— cascade cleanup
Test File: backend/tests/test_kindness_api.py (New)
test_add_kindness— PUT/kindness/add→ 201, type auto-set to'kindness'test_list_kindness— returns onlytype='kindness'taskstest_edit_kindness— PUT/kindness/<id>/edit→ 200test_delete_kindness— cascade removal
Test File: backend/tests/test_penalty_api.py (New)
test_add_penalty— PUT/penalty/add→ 201, type auto-set to'penalty'test_list_penalties— returns onlytype='penalty'taskstest_edit_penalty— PUT/penalty/<id>/edit→ 200test_delete_penalty— cascade removal
Test File: backend/tests/test_chore_confirmation.py (New)
Child Confirm Flow
test_child_confirm_chore_success— POST/child/<id>/confirm-chorewith{ task_id }→ 200,PendingConfirmationrecord created withstatus='pending',entity_type='chore'test_child_confirm_chore_not_assigned— 400ENTITY_NOT_ASSIGNEDwhen chore is not in child's task listtest_child_confirm_chore_not_found— 404TASK_NOT_FOUNDwhen task_id doesn't existtest_child_confirm_chore_child_not_found— 404CHILD_NOT_FOUNDtest_child_confirm_chore_already_pending— 400CHORE_ALREADY_PENDINGwhen a pending confirmation already existstest_child_confirm_chore_already_completed_today— 400CHORE_ALREADY_COMPLETEDwhen an approved confirmation exists for todaytest_child_confirm_chore_expired— 400CHORE_EXPIREDwhen chore is past its deadlinetest_child_confirm_chore_creates_tracking_event— TrackingEvent withaction='confirmed',delta=0,entity_type='chore'test_child_confirm_chore_wrong_type— 400 when task is kindness or penalty (not confirmable)
Child Cancel Flow
test_child_cancel_confirm_success— POST/child/<id>/cancel-confirm-chore→ 200, pending record deletedtest_child_cancel_confirm_not_pending— 400PENDING_NOT_FOUNDtest_child_cancel_confirm_creates_tracking_event— TrackingEvent withaction='cancelled',delta=0
Parent Approve Flow
test_parent_approve_chore_success— POST/child/<id>/approve-chore→ 200, points increased,status='approved',approved_atsettest_parent_approve_chore_with_override— usescustom_valuefrom override instead of base pointstest_parent_approve_chore_not_pending— 400PENDING_NOT_FOUNDtest_parent_approve_chore_creates_tracking_event— TrackingEvent withaction='approved',delta=+pointstest_parent_approve_chore_points_correct—points_before+ task points ==points_afteron child
Parent Reject Flow
test_parent_reject_chore_success— POST/child/<id>/reject-chore→ 200, pending record deleted, points unchangedtest_parent_reject_chore_not_pending— 400PENDING_NOT_FOUNDtest_parent_reject_chore_creates_tracking_event— TrackingEvent withaction='rejected',delta=0
Parent Reset Flow
test_parent_reset_chore_success— POST/child/<id>/reset-chore→ 200, approved record deleted, points unchangedtest_parent_reset_chore_not_completed— 400 when no approved record existstest_parent_reset_chore_creates_tracking_event— TrackingEvent withaction='reset',delta=0test_parent_reset_then_child_confirm_again— full cycle: confirm → approve → reset → confirm → approve (two approvals tracked)
Parent Direct Trigger
test_parent_trigger_chore_directly_creates_approved_confirmation— POST/child/<id>/trigger-taskwith a chore → creates approved PendingConfirmation so child view shows COMPLETED
Pending Confirmations List
test_list_pending_confirmations_returns_chores_and_rewards— GET/pending-confirmationsreturns both typestest_list_pending_confirmations_empty— returns empty list when none existtest_list_pending_confirmations_hydrates_names_and_images— response includeschild_name,entity_name, image IDstest_list_pending_confirmations_excludes_approved— only pending status returnedtest_list_pending_confirmations_filters_by_user— only returns confirmations for the authenticated user's children
Test File: backend/tests/test_task_api.py (Modified)
- Update all existing tests that use
is_goodto usetypeinstead test_add_task→ split intotest_add_chore,test_add_kindness,test_add_penalty(or remove if fully migrated to entity-specific APIs)test_list_tasks_sorted→ update sort expectations fortypefield
Test File: backend/tests/test_child_api.py (Modified)
- Update tests referencing
is_goodto usetype - Update
set-taskstests for newtypeparameter values ('chore','kindness','penalty') - Update
list-tasksresponse assertions to check forpending_statusandapproved_atfields on chores - Update
trigger-tasktests to verifyPendingConfirmationcreation for chores - Update
request-reward/cancel-request-reward/trigger-rewardtests to usePendingConfirmationmodel - Replace
pending-rewardsendpoint tests withpending-confirmations
Frontend Implementation
New Files
| File | Description |
|---|---|
src/components/task/ChoreView.vue |
Admin list of chores (type='chore'). Same pattern as current TaskView.vue with blue theme. |
src/components/task/KindnessView.vue |
Admin list of kindness acts (type='kindness'). Yellow theme. |
src/components/task/PenaltyView.vue |
Admin list of penalties (type='penalty'). Red theme. |
src/components/task/ChoreEditView.vue |
Create/edit chore form. Fields: name, points, image. No is_good toggle. |
src/components/task/KindnessEditView.vue |
Create/edit kindness form. Fields: name, points, image. |
src/components/task/PenaltyEditView.vue |
Create/edit penalty form. Fields: name, points, image. |
src/components/task/TaskSubNav.vue |
Sub-nav component with Chores / Kindness / Penalties tabs. Renders as a tab bar within the Tasks view area. |
src/components/child/ChoreAssignView.vue |
Assign chores to child (replaces TaskAssignView with type='good'). |
src/components/child/KindnessAssignView.vue |
Assign kindness acts to child. |
src/components/child/PenaltyAssignView.vue |
Assign penalties to child (replaces TaskAssignView with type='bad'). |
src/components/child/ChoreConfirmDialog.vue |
Modal dialog for child to confirm chore completion. "Did you finish [chore name]?" with Confirm / Cancel buttons. |
src/components/child/ChoreApproveDialog.vue |
Modal dialog for parent to approve/reject pending chore. Shows chore name, child name, points. Approve / Reject buttons. |
Modified Files
| File | Changes |
|---|---|
src/common/models.ts |
Replace Task.is_good with Task.type, add PendingConfirmation interface, extend EntityType/ActionType, add ChildChoreConfirmationPayload, replace PendingReward with PendingConfirmation. Add pending_status and approved_at to ChildTask. |
src/common/backendEvents.ts |
Add child_chore_confirmation event listener pattern. |
src/common/api.ts |
Add confirmChore(), cancelConfirmChore(), approveChore(), rejectChore(), resetChore(), fetchPendingConfirmations(). Remove fetchPendingRewards(). |
src/components/child/ChildView.vue |
Add chore tap handler → show ChoreConfirmDialog. Add PENDING (yellow) / COMPLETED (green) banner rendering. Handle cancel-confirm on PENDING tap. Filter kindness acts into new scrolling row. Listen for child_chore_confirmation SSE events. |
src/components/child/ParentView.vue |
Add PENDING/COMPLETED banners on chores. Handle approve/reject on PENDING chore tap. Add "Reset" to kebab menu for completed chores. Add "Assign Kindness" button. Update trigger-task to create approved confirmation. Replace is_good filters with type checks. Listen for child_chore_confirmation SSE events. |
src/components/notification/NotificationView.vue |
Fetch from /api/pending-confirmations instead of /api/pending-rewards. Render both pending chores and pending rewards with differentiation (icon/label). Listen for child_chore_confirmation events in addition to existing child_reward_request. |
src/layout/ParentLayout.vue |
"Tasks" nav icon remains, routes to a view housing TaskSubNav with sub-tabs. |
src/components/task/TaskEditView.vue |
Remove or repurpose. Logic moves to entity-specific edit views (no is_good toggle). |
src/components/task/TaskView.vue |
Remove or repurpose into the sub-nav container view. |
src/components/child/TaskAssignView.vue |
Remove. Replaced by ChoreAssignView, KindnessAssignView, PenaltyAssignView. |
| Router config | Add routes for new views. Update existing task routes to chore/kindness/penalty. |
Files to Remove
| File | Reason |
|---|---|
backend/models/pending_reward.py |
Replaced by pending_confirmation.py |
backend/api/pending_reward.py |
Replaced by pending_confirmation.py DTO |
backend/data/db/pending_rewards.json |
Replaced by pending_confirmations.json |
ChildView Chore Tap Flow
Child taps chore card
├─ Chore expired? → No action (grayed out, "TOO LATE" stamp)
├─ Chore COMPLETED today? → No action (grayed out, "COMPLETED" stamp)
├─ Chore PENDING? → Show ModalDialog "Cancel confirmation?"
│ └─ Confirm → POST /child/<id>/cancel-confirm-chore
└─ Chore available? → Show ChoreConfirmDialog "Did you finish [name]?"
└─ Confirm → POST /child/<id>/confirm-chore
ParentView Chore Tap Flow
Parent taps chore card
├─ Chore PENDING? → Show ChoreApproveDialog
│ ├─ Approve → POST /child/<id>/approve-chore (awards points)
│ └─ Reject → POST /child/<id>/reject-chore (resets to available)
├─ Chore COMPLETED today? → No tap action. Kebab menu has "Reset"
│ └─ Reset → POST /child/<id>/reset-chore
└─ Chore available? → Show TaskConfirmDialog (current behavior)
└─ Confirm → POST /child/<id>/trigger-task (sets COMPLETED)
Banner Styling
| State | Banner Text | Text Color | Background | CSS Variable Suggestion |
|---|---|---|---|---|
| Pending | PENDING |
Yellow (--color-warning) |
Dark semi-transparent | --banner-bg-pending |
| Completed | COMPLETED |
Green (--color-success) |
Dark semi-transparent | --banner-bg-completed |
| Expired | TOO LATE |
Red (existing) | Gray overlay (existing) | (existing styles) |
Frontend Tests
Test File: components/__tests__/ChoreConfirmDialog.test.ts (New)
renders chore name in dialogemits confirm event on confirm button clickemits cancel event on cancel button click
Test File: components/__tests__/ChoreApproveDialog.test.ts (New)
renders chore name and points in dialogemits approve event on approve button clickemits reject event on reject button click
Test File: components/__tests__/TaskSubNav.test.ts (New)
renders three sub-tabs: Chores, Kindness, Penaltieshighlights active tab based on routenavigates on tab click
Test File: components/__tests__/ChoreView.test.ts (New)
fetches and renders chore listnavigates to edit on item clickshows delete confirmation modalrefreshes on task_modified SSE event
Test File: components/__tests__/NotificationView.test.ts (Modified)
fetches from /api/pending-confirmationsrenders both pending chores and pending rewardsdifferentiates chore vs reward with label/iconrefreshes on child_chore_confirmation SSE eventrefreshes on child_reward_request SSE event
Test File: components/__tests__/ChildView.test.ts (Modified / New)
shows PENDING banner on chore with pending confirmationshows COMPLETED banner on chore completed todayopens ChoreConfirmDialog on available chore tapopens cancel dialog on PENDING chore tapdoes not allow tap on expired choredoes not allow tap on COMPLETED chorerenders kindness scrolling rowrefreshes on child_chore_confirmation SSE event
Test File: components/__tests__/ParentView.test.ts (Modified / New)
shows PENDING banner on chore with pending confirmationshows COMPLETED banner on approved choreopens ChoreApproveDialog on PENDING chore tapopens TaskConfirmDialog on available chore tapshows Reset in kebab menu for completed chorerenders kindness scrolling rowshows Assign Kindness button
Future Considerations
- Recurring chore auto-reset: Automatically clear completed status on schedule rollover (e.g., daily chores reset at midnight).
- Chore streaks: Track consecutive days a child completes a chore using
TrackingEventhistory. - Multi-completion analytics dashboard: Query
TrackingEventto show completion counts per chore per day/week. - Partial credit: Allow parents to award fewer points than the chore's value when approving.
- Chore delegation: Allow one child to reassign a chore to a sibling.
- Photo proof: Child attaches a photo when confirming a chore.
- Kindness auto-classification: Suggested classification when creating new items based on name patterns.
Acceptance Criteria (Definition of Done)
Backend
Taskmodel usestype: 'chore' | 'kindness' | 'penalty'—is_goodremovedPendingConfirmationmodel created,PendingRewardmodel removedpending_confirmations_dbcreated indb.py,pending_reward_dbremoved- Migration script converts existing tasks, pending rewards, tracking events, and overrides
chore_api.py,kindness_api.py,penalty_api.pycreated with CRUD endpointstask_api.pyremoved or deprecated- Child chore confirmation endpoints:
confirm-chore,cancel-confirm-chore,approve-chore,reject-chore,reset-chore GET /pending-confirmationsreturns hydrated pending chores and rewardstrigger-taskcreates approvedPendingConfirmationwhen parent triggers a chore directly- Reward request/cancel/trigger endpoints migrated to
PendingConfirmation list-tasksresponse includespending_statusandapproved_atfor choresTrackingEventcreated for every mutation: confirmed, cancelled, approved, rejected, reset- Tracking events logged to rotating file logger
- SSE event
CHILD_CHORE_CONFIRMATIONsent for every confirmation lifecycle event - All new error codes defined and returned with proper HTTP status codes
- All existing tests updated for
typefield (nois_goodreferences) - All new backend tests pass
Frontend
TaskandChildTaskinterfaces usetypeinstead ofis_goodPendingConfirmationinterface replacesPendingReward- Sub-nav under "Tasks" with Chores / Kindness / Penalties tabs
ChoreView,KindnessView,PenaltyViewlist views createdChoreEditView,KindnessEditView,PenaltyEditViewedit/create views createdChoreAssignView,KindnessAssignView,PenaltyAssignViewassign views createdTaskView,TaskEditView,TaskAssignViewremoved or repurposedChoreConfirmDialog— child confirmation modalChoreApproveDialog— parent approve/reject modalChildView— chore tap opens confirm dialog, cancel dialog for pending, banners render correctlyChildView— expired and completed chores are non-interactiveChildView— kindness scrolling row addedParentView— pending chore tap opens approve/reject dialogParentView— available chore tap uses existing trigger flow + creates completion recordParentView— kebab menu "Reset" option for completed choresParentView— "Assign Kindness" button addedNotificationView— fetches from/pending-confirmations, renders both types- SSE listeners for
child_chore_confirmationin all relevant components - Banner styles: yellow PENDING, green COMPLETED (using CSS variables)
- All
is_goodreferences removed from frontend code - All frontend tests pass
- Router updated with new routes