Files

3.4 KiB

Context

Currently, the frontend displays raw UUIDs for user references:

  • Task list shows assigneeId (e.g., "a1b2c3d4-e5f6...") or "Unassigned"
  • Task detail shows assigneeId and createdById
  • Shift detail shows memberId for each signup

The backend already stores DisplayName in the Member entity but the API DTOs don't expose it. The ShiftService already demonstrates the pattern of joining with Members (lines 82-87), which we can replicate for Tasks.

Goals / Non-Goals

Goals:

  • Add member name fields to backend DTOs
  • Update TaskService to query and include member names
  • Update ShiftService to include member name in ShiftSignupDto
  • Update frontend TypeScript interfaces
  • Replace UUID displays with names in task/shift UIs

Non-Goals:

  • No database schema changes
  • No changes to authentication or authorization
  • No changes to how tasks/shifts are created or updated
  • No caching layer for member names

Decisions

1. Add names to existing DTOs vs create new DTOs

Decision: Add optional fields to existing DTOs

Rationale:

  • Keeps API surface simple
  • Backward compatible - existing clients ignore new fields
  • No breaking changes to existing integrations

Alternative considered: Create new DTO versions (e.g., TaskDetailDtoV2)

  • Rejected: Unnecessary complexity for a simple additive change

2. Fetch member names via JOIN vs separate query

Decision: Use JOIN in TaskService methods

Rationale:

  • More efficient - single query per endpoint
  • Pattern already exists in ShiftService
  • Avoids N+1 query problem

Alternative considered: Query members separately and build lookup dictionary

  • Rejected: Adds complexity and extra database round-trips

3. Handle missing members (orphaned IDs)

Decision: Return null for name when member not found

Rationale:

  • Data integrity issue should surface visibly
  • Frontend can display fallback like "Unknown" or keep showing ID
  • Logging can track data inconsistencies

4. Frontend handling of null names

Decision: Frontend shows fallback text when name is null

Implementation:

// Task list
task.assigneeName || 'Unassigned'

// Task detail
task.assigneeName || 'Unassigned'
task.createdByName || 'Unknown'

// Shift signups
signup.memberName || 'Unknown Member'

Risks / Trade-offs

Risk Mitigation
JOIN adds query complexity Keep JOINs simple, only on indexed columns (Member.Id)
Larger API response payloads Minimal impact - names are small strings
Member names become stale Acceptable - names rarely change; eventual consistency
Database performance degradation Monitor query execution plans; add caching if needed
Partial data on member deletion Show "Unknown" fallback; log orphaned references

Migration Plan

  1. Backend DTO changes - Add new optional fields
  2. Backend service changes - Update queries to include names
  3. Frontend type updates - Add name fields to interfaces
  4. Frontend UI updates - Replace ID displays with names

Rollback:

  • DTO changes are backward compatible
  • Frontend can revert to showing IDs by changing display logic
  • No database changes required

Open Questions

  • Should we include externalUserId in the signup display? (Currently available in ShiftSignupDto)
  • Do we need to include member email for any display purposes?
  • Should we add name fields to shift list items (showing creator name)?