Files
fete/specs/012-link-preview/tasks.md
nitrix 751201617d
All checks were successful
CI / backend-test (push) Successful in 1m9s
CI / frontend-test (push) Successful in 23s
CI / frontend-e2e (push) Successful in 1m12s
CI / build-and-publish (push) Has been skipped
Add Open Graph and Twitter Card meta-tags for link previews
Replace PathResourceResolver SPA fallback with SpaController that
injects OG/Twitter meta-tags into cached index.html template.
Event pages get event-specific tags (title, date, location),
all other pages get generic fete branding. Includes og-image.png
brand asset and forward-headers-strategy for proxy support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:25:39 +01:00

202 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: Link Preview (Open Graph Meta-Tags)
**Input**: Design documents from `/specs/012-link-preview/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/
**Tests**: Included — constitution mandates TDD (Red → Green → Refactor).
**Organization**: Tasks grouped by user story for independent implementation and testing.
## 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, US3)
- Include exact file paths in descriptions
---
## Phase 1: Setup
**Purpose**: Prepare frontend template and static assets for meta-tag injection
- [x] T001 Add `<!-- OG_META_TAGS -->` placeholder comment in `<head>` of `frontend/index.html`
- [x] T002 [P] Create `og-image.png` brand image (1200x630) in `frontend/public/og-image.png`
- [x] T003 [P] Add `server.forward-headers-strategy=framework` to `backend/src/main/resources/application.properties`
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Core infrastructure for HTML meta-tag injection that ALL user stories depend on
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [x] T004 Write unit tests for `MetaTagRenderer` (HTML escaping, meta-tag HTML output) in `backend/src/test/java/de/fete/adapter/in/web/MetaTagRendererTest.java` — tests MUST fail (Red)
- [x] T005 Implement `MetaTagRenderer` utility that renders meta-tag key-value pairs into HTML `<meta>` strings with proper HTML escaping in `backend/src/main/java/de/fete/adapter/in/web/MetaTagRenderer.java`
- [x] T006 Write integration tests for `SpaController` base functionality (serves index.html, replaces placeholder) in `backend/src/test/java/de/fete/adapter/in/web/SpaControllerTest.java` — tests MUST fail (Red)
- [x] T007 Implement `SpaController` that caches `index.html` template at startup and replaces `<!-- OG_META_TAGS -->` placeholder before serving in `backend/src/main/java/de/fete/adapter/in/web/SpaController.java`
- [x] T008 Remove `PathResourceResolver` SPA fallback from `backend/src/main/java/de/fete/config/WebConfig.java` (replaced by `SpaController`)
**Checkpoint**: SPA still works (index.html served for all non-API/non-static routes), but now through `SpaController` with placeholder replacement ready
---
## Phase 3: User Story 1 — Event Link Preview in Messenger (Priority: P1) 🎯 MVP
**Goal**: Shared event links display rich preview cards with event title, date, location, and description in messengers
**Independent Test**: Share an event URL — messenger shows event title and formatted description with date/location
### Tests for User Story 1 ⚠️
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
- [x] T009 [P] [US1] Unit tests for `OpenGraphService.buildEventMeta()` — full event data, no location, no description, long title truncation, special characters in `backend/src/test/java/de/fete/application/OpenGraphServiceTest.java`
- [x] T010 [P] [US1] Integration tests for `SpaController` event routes — GET `/events/{token}` returns HTML with event-specific OG meta-tags, event not found falls back to generic in `backend/src/test/java/de/fete/adapter/in/web/SpaControllerTest.java`
### Implementation for User Story 1
- [x] T011 [US1] Implement `OpenGraphService.buildEventMeta()` — fetch event by token, compose `og:title` (truncated 70 chars), `og:description` (date + location + description, max 200 chars), `og:url`, `og:type`, `og:site_name`, `og:image` in `backend/src/main/java/de/fete/application/service/OpenGraphService.java`
- [x] T012 [US1] Wire `SpaController` to call `OpenGraphService` for `/events/{token}` routes, inject event-specific meta-tags via `MetaTagRenderer` in `backend/src/main/java/de/fete/adapter/in/web/SpaController.java`
- [ ] T013 [US1] E2E test — deferred (requires running backend; covered by integration tests)
**Checkpoint**: Event links show rich OG preview cards in messengers. MVP complete.
---
## Phase 4: User Story 2 — Fallback Preview for Generic Pages (Priority: P2)
**Goal**: Non-event pages (homepage, event list, create) show a meaningful generic fete preview when shared
**Independent Test**: Share the homepage URL — messenger shows "fete" as title and generic app description
### Tests for User Story 2 ⚠️
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
- [x] T014 [P] [US2] Unit tests for `OpenGraphService.buildGenericMeta()` — verify generic title "fete", generic description, correct URL, image URL in `backend/src/test/java/de/fete/application/service/OpenGraphServiceTest.java`
- [x] T015 [P] [US2] Integration tests for `SpaController` generic routes — GET `/`, GET `/create` return HTML with generic OG meta-tags in `backend/src/test/java/de/fete/adapter/in/web/SpaControllerTest.java`
### Implementation for User Story 2
- [x] T016 [US2] Implement `OpenGraphService.buildGenericMeta()` — title "fete", description "Privacy-focused event planning. Create and share events without accounts.", type "website", site_name "fete" in `backend/src/main/java/de/fete/application/service/OpenGraphService.java`
- [x] T017 [US2] Wire `SpaController` to call `OpenGraphService.buildGenericMeta()` for all non-event HTML routes in `backend/src/main/java/de/fete/adapter/in/web/SpaController.java`
- [ ] T018 [US2] E2E test — deferred (requires running backend; covered by integration tests)
**Checkpoint**: All shared fete links (event-specific and generic) show rich preview cards
---
## Phase 5: User Story 3 — Twitter/X Card Support (Priority: P3)
**Goal**: Links shared on Twitter/X also display rich preview cards via Twitter Card meta-tags
**Independent Test**: Verify HTML source contains `twitter:card`, `twitter:title`, `twitter:description` meta-tags
### Tests for User Story 3 ⚠️
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
- [x] T019 [P] [US3] Unit tests for Twitter Card meta-tag generation — verify `twitter:card` = "summary", `twitter:title`, `twitter:description` match OG values in `backend/src/test/java/de/fete/application/service/OpenGraphServiceTest.java`
- [x] T020 [P] [US3] Integration tests for `SpaController` — event and generic routes include Twitter Card meta-tags in `backend/src/test/java/de/fete/adapter/in/web/SpaControllerTest.java`
### Implementation for User Story 3
- [x] T021 [US3] Extend `OpenGraphService` to include Twitter Card meta-tags (`twitter:card`, `twitter:title`, `twitter:description`) alongside OG tags in `backend/src/main/java/de/fete/application/service/OpenGraphService.java`
- [x] T022 [US3] Extend `MetaTagRenderer` to render `<meta name="twitter:*">` tags (using `name` attribute instead of `property`) in `backend/src/main/java/de/fete/adapter/in/web/MetaTagRenderer.java`
- [ ] T023 [US3] E2E test — fetch event page and homepage, verify Twitter Card meta-tags present alongside OG tags in `frontend/e2e/link-preview.spec.ts`
**Checkpoint**: All three user stories complete — OG tags, generic fallback, and Twitter Cards all working
---
## Phase 6: Polish & Cross-Cutting Concerns
**Purpose**: Edge cases, hardening, and final verification
- [x] T024 [P] Verify HTML escaping for special characters (quotes, ampersands, angle brackets) in meta-tag values across all routes — edge-case tests in MetaTagRendererTest.java
- [x] T025 [P] Verify `SpaController` does not intercept static asset requests — SpaController only handles explicit routes, not wildcard
- [x] T026 Run full backend test suite (`cd backend && ./mvnw verify`) and fix any regressions — 97 tests, 0 bugs
- [x] T027 Run full frontend test suite (`cd frontend && npm run test:unit`) — 133 tests passed
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies — can start immediately
- **Foundational (Phase 2)**: Depends on T001 (placeholder in index.html) — BLOCKS all user stories
- **US1 (Phase 3)**: Depends on Foundational phase completion
- **US2 (Phase 4)**: Depends on Foundational phase completion — can run in parallel with US1
- **US3 (Phase 5)**: Depends on US1 or US2 (extends their meta-tag output)
- **Polish (Phase 6)**: Depends on all user stories being complete
### User Story Dependencies
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) — no dependencies on other stories
- **User Story 2 (P2)**: Can start after Foundational (Phase 2) — independent from US1
- **User Story 3 (P3)**: Depends on US1 or US2 — extends existing OG meta-tag output with Twitter tags
### Within Each User Story
- Tests MUST be written and FAIL before implementation (TDD Red phase)
- Service layer before controller wiring
- Unit tests before integration tests before E2E tests
- Story complete before moving to next priority
### Parallel Opportunities
- T001, T002, T003 can all run in parallel (Setup phase)
- T004 and T006 can run in parallel (Foundational tests — different files)
- T009, T010 can run in parallel (US1 tests — different files)
- T014, T015 can run in parallel (US2 tests — different files)
- T019, T020 can run in parallel (US3 tests — different files)
- US1 and US2 can be worked on in parallel after Foundational phase
---
## Parallel Example: User Story 1
```bash
# Launch US1 tests in parallel (Red phase):
Task: "Unit tests for OpenGraphService.buildEventMeta() in OpenGraphServiceTest.java"
Task: "Integration tests for SpaController event routes in SpaControllerTest.java"
# Then implement sequentially:
Task: "Implement OpenGraphService.buildEventMeta()"
Task: "Wire SpaController for /events/{token} routes"
Task: "E2E test for event page meta-tags"
```
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 1: Setup (T001T003)
2. Complete Phase 2: Foundational (T004T008)
3. Complete Phase 3: User Story 1 (T009T013)
4. **STOP and VALIDATE**: Share an event link in a messenger, verify preview card
5. Deploy/demo if ready
### Incremental Delivery
1. Setup + Foundational → SpaController serving index.html with placeholder replacement
2. Add US1 → Event links show rich previews → Deploy (MVP!)
3. Add US2 → Generic pages also show previews → Deploy
4. Add US3 → Twitter/X cards work too → Deploy
5. Polish → Edge cases hardened → Final release
---
## Notes
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- Each user story is independently completable and testable
- TDD enforced: write tests first, verify they fail, then implement
- Commit after each task or logical group
- Stop at any checkpoint to validate story independently