diff --git a/frontend/Dockerfile b/frontend/Dockerfile index d6bd9d9..61d6e4b 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -13,6 +13,9 @@ RUN npm install -g bun WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . +# Set environment for build to ensure server binds to all interfaces +ENV HOSTNAME="0.0.0.0" +ENV PORT="3000" RUN bun run build # Stage 3: Runtime @@ -36,5 +39,7 @@ EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" -# Start standalone server +# Start standalone server - bind to all interfaces (0.0.0.0) for external access +ENV HOSTNAME="0.0.0.0" +ENV PORT="3000" CMD ["node", "server.js"] diff --git a/openspec/changes/archive/2026-03-20-replace-uuids-with-names/.openspec.yaml b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/.openspec.yaml new file mode 100644 index 0000000..3c861dd --- /dev/null +++ b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-18 diff --git a/openspec/changes/archive/2026-03-20-replace-uuids-with-names/design.md b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/design.md new file mode 100644 index 0000000..ebcaa72 --- /dev/null +++ b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/design.md @@ -0,0 +1,99 @@ +## 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:** +```typescript +// 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)? diff --git a/openspec/changes/archive/2026-03-20-replace-uuids-with-names/proposal.md b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/proposal.md new file mode 100644 index 0000000..6fe50bf --- /dev/null +++ b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/proposal.md @@ -0,0 +1,34 @@ +## Why + +Currently, the frontend displays raw UUIDs for user references (assignee, creator, members) which creates a poor user experience. Users should see meaningful names like "Alice Smith" instead of "a1b2c3d4-e5f6-7890-abcd-ef1234567890". The backend already stores display names in the Member entity, but the API DTOs don't expose them. + +## What Changes + +- **Backend DTOs**: Add name fields to task and shift DTOs + - `TaskListItemDto`: Add `string? AssigneeName` + - `TaskDetailDto`: Add `string? AssigneeName` and `string CreatedByName` + - `ShiftSignupDto`: Add `string MemberName` +- **Backend Services**: Update TaskService and ShiftService to query and populate member names + - Join with Members table to fetch display names + - Include names in DTO construction +- **Frontend Types**: Update TypeScript interfaces to include new name fields + - `TaskListItemDto`, `TaskDetailDto`, `ShiftSignupDto` interfaces +- **Frontend UI**: Replace UUID displays with names + - Task list: show assignee name instead of ID + - Task detail: show assignee and creator names + - Shift detail: show member names in signup list + +## Capabilities + +### New Capabilities +- `member-name-enrichment`: API DTOs include human-readable member names alongside IDs + +### Modified Capabilities +- None (this is purely an enhancement to existing capabilities) + +## Impact + +- **Backend**: TaskService.cs, ShiftService.cs, and DTOs in WorkClub.Application +- **Frontend**: Tasks pages, Shifts pages, and React hooks (useTasks.ts, useShifts.ts) +- **Database**: Additional JOIN queries on Members table (no schema changes) +- **API Response**: New optional fields in existing endpoints (backward compatible) diff --git a/openspec/changes/archive/2026-03-20-replace-uuids-with-names/specs/member-name-enrichment/spec.md b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/specs/member-name-enrichment/spec.md new file mode 100644 index 0000000..3dd4b38 --- /dev/null +++ b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/specs/member-name-enrichment/spec.md @@ -0,0 +1,43 @@ +## ADDED Requirements + +### Requirement: Task list items include assignee name +The API SHALL return the assignee's display name in TaskListItemDto. + +#### Scenario: Task with assignee +- **WHEN** a task is assigned to a member +- **THEN** the TaskListItemDto SHALL include the assignee's DisplayName as `assigneeName` + +#### Scenario: Task without assignee +- **WHEN** a task has no assignee +- **THEN** the TaskListItemDto SHALL have `assigneeName` set to null + +### Requirement: Task details include creator and assignee names +The API SHALL return the display names of both the creator and assignee in TaskDetailDto. + +#### Scenario: Viewing task details +- **WHEN** a user requests task details +- **THEN** the TaskDetailDto SHALL include `createdByName` (the creator's DisplayName) +- **AND** the TaskDetailDto SHALL include `assigneeName` (the assignee's DisplayName, or null if unassigned) + +### Requirement: Shift signup includes member name +The API SHALL return the member's display name in ShiftSignupDto. + +#### Scenario: Viewing shift signups +- **WHEN** a user views shift details with signups +- **THEN** each ShiftSignupDto SHALL include `memberName` (the member's DisplayName) + +### Requirement: Frontend displays names instead of UUIDs +The frontend SHALL render member names instead of UUIDs wherever user references appear. + +#### Scenario: Task list view +- **WHEN** viewing the task list +- **THEN** the Assignee column SHALL display the assignee's name (or "Unassigned") + +#### Scenario: Task detail view +- **WHEN** viewing a task detail page +- **THEN** the Assignee field SHALL display the assignee's name (or "Unassigned") +- **AND** the Created By field SHALL display the creator's name + +#### Scenario: Shift detail view +- **WHEN** viewing a shift detail page with signups +- **THEN** the member list SHALL display each member's name instead of their ID diff --git a/openspec/changes/archive/2026-03-20-replace-uuids-with-names/tasks.md b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/tasks.md new file mode 100644 index 0000000..b1ad585 --- /dev/null +++ b/openspec/changes/archive/2026-03-20-replace-uuids-with-names/tasks.md @@ -0,0 +1,41 @@ +## 1. Backend DTO Updates + +- [x] 1.1 Update TaskListItemDto.cs to add `string? AssigneeName` field +- [x] 1.2 Update TaskDetailDto.cs to add `string? AssigneeName` and `string? CreatedByName` fields +- [x] 1.3 Update ShiftSignupDto.cs to add `string? MemberName` field + +## 2. Backend Service Updates - Tasks + +- [x] 2.1 Update TaskService.GetTasksAsync() to join with Members and populate assigneeName +- [x] 2.2 Update TaskService.GetTaskByIdAsync() to join with Members for assignee and creator names +- [x] 2.3 Update TaskService.CreateTaskAsync() to fetch and include creator name in response +- [x] 2.4 Update TaskService.UpdateTaskAsync() to join with Members for assignee and creator names + +## 3. Backend Service Updates - Shifts + +- [x] 3.1 Update ShiftService.GetShiftByIdAsync() to include member display name in ShiftSignupDto +- [x] 3.2 Update ShiftService.UpdateShiftAsync() to include member display name in ShiftSignupDto + +## 4. Frontend Type Updates + +- [x] 4.1 Update TaskListItemDto interface in useTasks.ts to add `assigneeName?: string` +- [x] 4.2 Update TaskDetailDto interface in useTasks.ts to add `assigneeName?: string` and `createdByName?: string` +- [x] 4.3 Update ShiftSignupDto interface in useShifts.ts to add `memberName?: string` + +## 5. Frontend UI Updates - Tasks + +- [x] 5.1 Update tasks/page.tsx to display assigneeName instead of assigneeId +- [x] 5.2 Update tasks/[id]/page.tsx to display assigneeName instead of assigneeId +- [x] 5.3 Update tasks/[id]/page.tsx to display createdByName instead of createdById + +## 6. Frontend UI Updates - Shifts + +- [x] 6.1 Update shifts/[id]/page.tsx to display memberName instead of memberId in signup list + +## 7. Testing & Verification + +- [x] 7.1 Run backend build to verify C# compilation succeeds +- [x] 7.2 Run frontend build to verify TypeScript compilation succeeds +- [x] 7.3 Verify task list shows member names correctly +- [x] 7.4 Verify task detail shows assignee and creator names +- [x] 7.5 Verify shift detail shows member names in signup list