Spec, research, data model, API contract, implementation plan, and task breakdown for the public event detail page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
12 KiB
Tasks: View Event Landing Page
Input: Design documents from /specs/007-view-event/
Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/get-event.yaml
Tests: Included — constitution enforces Test-Driven Methodology (Principle II).
Organization: Tasks grouped by user story. US3 (cancelled event) is deferred until US-18.
Format: [ID] [P?] [Story] Description
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US4)
- Exact file paths included in descriptions
Phase 1: Setup (Cross-Cutting Schema Changes)
Purpose: OpenAPI contract update, database migration, and type generation — prerequisites for all backend and frontend work.
- T001 Update OpenAPI spec: add
GET /events/{token}endpoint,GetEventResponseschema, andtimezonefield toCreateEventRequest/CreateEventResponseinbackend/src/main/resources/openapi/api.yaml - T002 [P] Add Liquibase changeset:
timezone VARCHAR(64) NOT NULL DEFAULT 'UTC'column oneventstable inbackend/src/main/resources/db/changelog/ - T003 Regenerate frontend TypeScript types from updated OpenAPI spec in
frontend/src/api/schema.d.ts
Checkpoint: OpenAPI contract finalized, DB schema ready, frontend types available.
Phase 2: Foundational (Backend — Blocks All User Stories)
Purpose: Domain model update, new GET use case, controller endpoint, and backend tests. All user stories depend on this.
CRITICAL: No frontend user story work can begin until this phase is complete.
Backend Tests (TDD — write first, verify they fail)
- T004 [P] Backend unit tests for
GetEventUseCase: test getByEventToken returns event, returns empty for unknown token, computes expired flag — inbackend/src/test/java/de/fete/ - T005 [P] Backend controller tests for
GET /events/{token}: test 200 with full response, 200 with optional fields absent, 404 with ProblemDetail — inbackend/src/test/java/de/fete/ - T006 [P] Backend tests for timezone in Create Event flow: request validation (valid/invalid IANA zone), persistence round-trip — in
backend/src/test/java/de/fete/
Backend Implementation
- T007 Add
timezonefield (String) to domain model inbackend/src/main/java/de/fete/domain/model/Event.java - T008 [P] Add
timezonecolumn to JPA entity and update persistence mapping inbackend/src/main/java/de/fete/adapter/out/persistence/EventJpaEntity.javaandEventPersistenceAdapter.java - T009 [P] Update Create Event flow to accept and validate
timezone(must be valid IANA zone ID viaZoneId.getAvailableZoneIds()) inbackend/src/main/java/de/fete/application/service/EventService.javaandEventController.java - T010 Create
GetEventUseCaseinbound port withgetByEventToken(UUID): Optional<Event>inbackend/src/main/java/de/fete/domain/port/in/GetEventUseCase.java - T011 Implement
GetEventUseCaseinbackend/src/main/java/de/fete/application/service/EventService.java— delegates to existingfindByEventToken()repository method - T012 Implement
getEvent()inbackend/src/main/java/de/fete/adapter/in/web/EventController.java— maps domain Event to GetEventResponse, computesexpired(expiryDate vs server clock) andattendeeCount(hardcoded 0)
Checkpoint: Backend complete — GET /api/events/{token} returns 200 or 404. All backend tests pass.
Phase 3: User Story 1 — View Event Details as Guest (Priority: P1) MVP
Goal: A guest opens a shared event link and sees all event information: title, date/time with IANA timezone, description, location, attendee count. Loading shows skeleton shimmer.
Independent Test: Navigate to a valid event URL, verify all fields display correctly with locale-formatted date/time.
Tests for User Story 1
- T013 [P] [US1] Unit tests for EventDetailView loaded state: renders title, date/time (locale-formatted via
Intl.DateTimeFormat), timezone, description, location, attendee count — infrontend/src/__tests__/EventDetailView.spec.ts - T014 [P] [US1] Unit test for EventDetailView loading state: renders skeleton shimmer placeholders — in
frontend/src/__tests__/EventDetailView.spec.ts
Implementation for User Story 1
- T015 [P] [US1] Add skeleton shimmer CSS (CSS-only gradient animation, no dependencies) in
frontend/src/assets/main.css - T016 [US1] Create
EventDetailView.vuewith loading (skeleton shimmer) and loaded states — fetches event viaopenapi-fetchGET/events/{token}, formats date/time withIntl.DateTimeFormatusing browser locale — infrontend/src/views/EventDetailView.vue - T017 [US1] Update router to use
EventDetailViewfor/events/:tokenroute infrontend/src/router/index.ts - T018 [P] [US1] Update
EventCreateView.vueto sendtimezonefield (auto-detected viaIntl.DateTimeFormat().resolvedOptions().timeZone) infrontend/src/views/EventCreateView.vue - T019 [US1] E2E test for loaded event: navigate to valid event URL, verify all fields displayed, verify no external resource requests — in
frontend/e2e/event-view.spec.ts
Checkpoint: US1 complete — guest can view event details. Skeleton shimmer during loading. Date/time locale-formatted with timezone label.
Phase 4: User Story 2 — View Expired Event (Priority: P2)
Goal: A guest opens a link to an expired event. The page shows event details plus a clear "event has ended" indicator. No RSVP actions shown.
Independent Test: Create an event with past expiry date, navigate to its URL, verify "event has ended" state renders and no RSVP controls are present.
Dependencies: Requires Phase 3 (EventDetailView exists).
Tests for User Story 2
- T020 [P] [US2] Unit test for EventDetailView expired state: renders "event has ended" indicator, RSVP controls absent from DOM — in
frontend/src/__tests__/EventDetailView.spec.ts
Implementation for User Story 2
- T021 [US2] Add expired state rendering to
EventDetailView.vue: show event details + "event has ended" banner whenexpired === true, no RSVP actions in DOM — infrontend/src/views/EventDetailView.vue - T022 [US2] E2E test for expired event: MSW returns event with
expired: true, verify banner and absent RSVP controls — infrontend/e2e/event-view.spec.ts
Checkpoint: US2 complete — expired events clearly show "ended" state.
Phase 5: User Story 4 — Event Not Found (Priority: P2)
Goal: A guest navigates to an invalid event URL. The page shows a clear "event not found" message — no partial data, no error traces.
Independent Test: Navigate to a URL with an unknown event token, verify "event not found" message renders.
Dependencies: Requires Phase 3 (EventDetailView exists). No dependency on US2.
Tests for User Story 4
- T023 [P] [US4] Unit test for EventDetailView not-found state: renders "event not found" message, no event data in DOM — in
frontend/src/__tests__/EventDetailView.spec.ts
Implementation for User Story 4
- T024 [US4] Add not-found state rendering to
EventDetailView.vue: show "event not found" message when API returns 404 — infrontend/src/views/EventDetailView.vue - T025 [US4] E2E test for event not found: MSW returns 404 ProblemDetail, verify message and no event data — in
frontend/e2e/event-view.spec.ts
Checkpoint: US4 complete — invalid tokens show friendly not-found message.
Phase 6: Polish & Cross-Cutting Concerns
Purpose: Server error edge case, final validation, and cleanup.
- T026 Add server error state with manual retry button to
EventDetailView.vue: friendly error message + "Retry" button that re-fetches — infrontend/src/views/EventDetailView.vue - T027 [P] Unit test for server error + retry state in
frontend/src/__tests__/EventDetailView.spec.ts - T028 [P] E2E test for server error: MSW returns 500, verify error message and retry button functionality — in
frontend/e2e/event-view.spec.ts - T029 Run quickstart.md validation: verify all key changes listed in quickstart.md are implemented
Dependencies & Execution Order
Phase Dependencies
- Setup (Phase 1): No dependencies — start immediately
- Foundational (Phase 2): Depends on T001 (OpenAPI spec) and T002 (migration) from Setup
- US1 (Phase 3): Depends on Phase 2 completion (backend endpoint must exist)
- US2 (Phase 4): Depends on Phase 3 (EventDetailView exists) — can parallelize with US4
- US4 (Phase 5): Depends on Phase 3 (EventDetailView exists) — can parallelize with US2
- Polish (Phase 6): Depends on Phase 3 minimum; ideally after US2 + US4
User Story Dependencies
Phase 1 (Setup) ──► Phase 2 (Backend) ──► Phase 3 (US1/MVP)
│
┌────┴────┐
▼ ▼
Phase 4 Phase 5
(US2) (US4)
└────┬────┘
▼
Phase 6 (Polish)
- US1 (P1): Requires Phase 2 — no dependency on other stories
- US2 (P2): Requires US1 (same component) — no dependency on US4
- US4 (P2): Requires US1 (same component) — no dependency on US2
- US3 (P2): DEFERRED until US-18 (cancel event) is implemented
Within Each Phase
- Tests MUST be written and FAIL before implementation (TDD)
- Models/ports before services
- Services before controllers
- Backend before frontend (for the same endpoint)
Parallel Opportunities
Phase 1: T002 (migration) can run in parallel with T001 (OpenAPI update) Phase 2: T004, T005, T006 (tests) can run in parallel. T008, T009 can run in parallel after T007. Phase 3: T013, T014 (unit tests) and T015 (CSS) can run in parallel. T018 (create form timezone) is independent. Phase 4 + 5: US2 and US4 can be implemented in parallel (different UI states, same file but non-conflicting sections).
Parallel Example: Phase 2 (Backend)
# Write all backend tests in parallel (TDD):
Task T004: "Unit tests for GetEventUseCase"
Task T005: "Controller tests for GET /events/{token}"
Task T006: "Tests for timezone in Create Event flow"
# Then implement in parallel where possible:
Task T008: "Add timezone to JPA entity + persistence" # parallel
Task T009: "Update Create Event flow for timezone" # parallel
# T010-T012 are sequential (port → service → controller)
Implementation Strategy
MVP First (User Story 1 Only)
- Complete Phase 1: Setup (OpenAPI + migration + types)
- Complete Phase 2: Backend (domain + use case + controller + tests)
- Complete Phase 3: US1 (EventDetailView + router + tests)
- STOP and VALIDATE: Guest can view event details via shared link
- Deploy/demo if ready
Incremental Delivery
- Setup + Backend → Backend ready, API testable via curl
- Add US1 → Guest can view events (MVP!)
- Add US2 → Expired events show "ended" state
- Add US4 → Invalid tokens show "not found"
- Polish → Server error handling, final validation
Deferred Work
- US3 (Cancelled event): Blocked on US-18. No tasks generated. Will require adding
cancelled+cancellationMessageto GetEventResponse and a new UI state.
Notes
- [P] tasks = different files, no dependencies on incomplete tasks
- [Story] label maps task to specific user story for traceability
attendeeCountreturns 0 until RSVP feature (US-8+) is implemented (R-3)expiredis computed server-side using injected Clock bean (R-4)- Frontend route:
/events/:token— API path:/api/events/{token}(R-5) - Skeleton shimmer is CSS-only, no additional dependencies (R-6)
- Date/time formatted via
Intl.DateTimeFormatwith browser locale (spec clarification Q7)