Files
chore/.github/specs/archive/feat-dynamic-points/IMPLEMENTATION_SUMMARY.md
Ryan Kegel 401c21ad82
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 25s
feat: add PendingRewardDialog, RewardConfirmDialog, and TaskConfirmDialog components
- Implemented PendingRewardDialog for handling pending reward requests.
- Created RewardConfirmDialog for confirming reward redemption.
- Developed TaskConfirmDialog for task confirmation with child name display.

test: add unit tests for ChildView and ParentView components

- Added comprehensive tests for ChildView including task triggering and SSE event handling.
- Implemented tests for ParentView focusing on override modal and SSE event management.

test: add ScrollingList component tests

- Created tests for ScrollingList to verify item fetching, loading states, and custom item classes.
- Included tests for two-step click interactions and edit button display logic.
- Moved toward hashed passwords.
2026-02-10 20:21:05 -05:00

4.9 KiB

Tracking Feature Implementation Summary

Implementation Complete

All acceptance criteria from feat-tracking.md have been implemented and tested.


📦 What Was Delivered

Backend

  1. Data Model (tracking_event.py)

    • TrackingEvent dataclass with full type safety
    • Factory method create_event() for server-side timestamp generation
    • Delta invariant validation (delta == points_after - points_before)
  2. Database Layer (tracking.py)

    • New TinyDB table: tracking_events.json
    • Helper functions: insert_tracking_event, get_tracking_events_by_child, get_tracking_events_by_user, anonymize_tracking_events_for_user
    • Offset-based pagination with sorting by occurred_at (desc)
  3. Audit Logging (tracking_logger.py)

    • Per-user rotating file handlers (logs/tracking_user_<user_id>.log)
    • 10MB max file size, 5 backups
    • Structured log format with all event metadata
  4. API Integration (child_api.py)

    • Tracking added to:
      • POST /child/<id>/trigger-task → action: activated
      • POST /child/<id>/request-reward → action: requested
      • POST /child/<id>/trigger-reward → action: redeemed
      • POST /child/<id>/cancel-request-reward → action: cancelled
  5. Admin API (tracking_api.py)

    • GET /admin/tracking with filters:
      • child_id (required if no user_id)
      • user_id (admin only)
      • entity_type (task|reward|penalty)
      • action (activated|requested|redeemed|cancelled)
      • limit (default 50, max 500)
      • offset (default 0)
    • Returns total count for future pagination UI
  6. SSE Events (event_types.py, tracking_event_created.py)

    • New event type: TRACKING_EVENT_CREATED
    • Payload: tracking_event_id, child_id, entity_type, action
    • Emitted on every tracking event creation

Frontend

  1. TypeScript Models (models.ts)

    • TrackingEvent interface (1:1 parity with Python)
    • Type aliases: EntityType, ActionType
    • TrackingEventCreatedPayload for SSE events
  2. API Helpers (api.ts)

    • getTrackingEventsForChild() function with all filter params
  3. SSE Registration

    • Event type registered in type union
    • Ready for future UI components

Tests

Backend Unit Tests (test_tracking.py):

  • Tracking event creation with factory method
  • Delta invariant validation
  • Insert and query tracking events
  • Filtering by entity_type and action
  • Offset-based pagination
  • User anonymization on deletion
  • Points change correctness (positive/negative/zero delta)
  • No points change for request/cancel actions

🔑 Key Design Decisions

  1. Append-only tracking table - No deletions, only anonymization on user deletion
  2. Server timestamps - occurred_at always uses server time (UTC) to avoid client clock drift
  3. Separate logging - Per-user audit logs independent of database
  4. Offset pagination - Simpler than cursors, sufficient for expected scale
  5. No UI (yet) - API/models/SSE only; UI deferred to future phase

🚀 Usage Examples

Backend: Create a tracking event

from models.tracking_event import TrackingEvent
from db.tracking import insert_tracking_event
from utils.tracking_logger import log_tracking_event

event = TrackingEvent.create_event(
    user_id='user123',
    child_id='child456',
    entity_type='task',
    entity_id='task789',
    action='activated',
    points_before=50,
    points_after=60,
    metadata={'task_name': 'Homework'}
)

insert_tracking_event(event)
log_tracking_event(event)

Frontend: Query tracking events

import { getTrackingEventsForChild } from "@/common/api";

const res = await getTrackingEventsForChild({
  childId: "child456",
  entityType: "task",
  limit: 20,
  offset: 0,
});

const data = await res.json();
// { tracking_events: [...], total: 42, count: 20, limit: 20, offset: 0 }

📋 Migration Notes

  1. New database file: backend/data/db/tracking_events.json will be created automatically on first tracking event.
  2. New log directory: backend/logs/tracking_user_<user_id>.log files will be created per user.
  3. No breaking changes to existing APIs or data models.

🔮 Future Enhancements (Not in This Phase)

  • Admin/parent UI for viewing tracking history
  • Badges and certificates based on tracking data
  • Analytics and reporting dashboards
  • Export tracking data (CSV, JSON)
  • Time-based filters (date range queries)