Files
fete/specs/012-link-preview/spec.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

105 lines
7.3 KiB
Markdown

# Feature Specification: Link Preview (Open Graph Meta-Tags)
**Feature Branch**: `012-link-preview`
**Created**: 2026-03-09
**Status**: Draft
**Input**: User description: "When people share an event link, the users messenger should show information about the site in the messenger"
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Event Link Preview in Messenger (Priority: P1)
A user copies the link to a specific event page and pastes it into a messenger (WhatsApp, Telegram, Signal, iMessage, etc.). The messenger automatically fetches metadata from the link and displays a rich preview card showing the event title, a short description, and the fete branding. The recipient sees this information without having to open the link.
**Why this priority**: This is the core feature. Without proper meta-tags on the event page, shared links appear as bare URLs with no context, reducing click-through rates and making events harder to discover.
**Independent Test**: Can be fully tested by sharing an event link in any messenger and verifying the preview card shows the correct event title, description with date and location, and the fete app name.
**Acceptance Scenarios**:
1. **Given** an event exists with title, date, location, and description, **When** a user shares the event URL in a messenger, **Then** the messenger displays a preview card showing the event title, a summary of the event (including date and location), and the fete app name.
2. **Given** an event exists with all details, **When** a social media crawler fetches the event URL, **Then** the response includes Open Graph meta-tags (`og:title`, `og:description`, `og:url`, `og:type`, `og:site_name`) with correct event-specific values.
3. **Given** an event exists, **When** a crawler fetches the event URL, **Then** the `og:description` includes the event date, location, and a truncated version of the event description (max 200 characters).
---
### User Story 2 - Fallback Preview for Generic Pages (Priority: P2)
When a user shares a non-event page (e.g., the homepage or event list), the messenger still shows a meaningful preview with the app name and a generic description of what fete is.
**Why this priority**: Users may share the main app link rather than a specific event. A generic fallback ensures every shared link looks polished.
**Independent Test**: Can be tested by sharing the homepage URL in a messenger and verifying a sensible default preview appears.
**Acceptance Scenarios**:
1. **Given** a user shares the app homepage URL, **When** a messenger fetches the link, **Then** the preview shows the app name "fete" as the title and a generic description (e.g., "Privacy-focused event planning. Create and share events without accounts.").
2. **Given** a user shares the event list URL, **When** a messenger fetches the link, **Then** the preview shows default app-level metadata.
---
### User Story 3 - Twitter/X Card Support (Priority: P3)
In addition to Open Graph tags, the system provides Twitter Card meta-tags so that links shared on Twitter/X also display rich preview cards.
**Why this priority**: Twitter/X uses its own card format alongside Open Graph. Adding these tags broadens the platforms where previews work correctly.
**Independent Test**: Can be tested by validating the HTML source contains `twitter:card`, `twitter:title`, and `twitter:description` meta-tags.
**Acceptance Scenarios**:
1. **Given** an event page, **When** a Twitter/X crawler fetches the URL, **Then** the response includes `twitter:card` (set to "summary"), `twitter:title`, and `twitter:description` meta-tags with correct values.
---
### Edge Cases
- What happens when an event has no description? The preview shows the event title, date, and location. The description meta-tag falls back to date and location only.
- What happens when an event has no location? The description meta-tag includes the date and whatever other details are available.
- What happens when the event title contains special characters (quotes, ampersands, angle brackets)? Meta-tag values are properly HTML-escaped.
- How does the system handle very long event titles or descriptions? Titles are truncated at 70 characters, descriptions at 200 characters.
- What happens when crawlers don't execute JavaScript? Meta-tags are served in the initial HTML response from the server, not injected client-side.
## Requirements *(mandatory)*
### Functional Requirements
- **FR-001**: The system MUST include Open Graph meta-tags (`og:title`, `og:description`, `og:url`, `og:type`, `og:site_name`) on every event page.
- **FR-002**: The system MUST populate `og:title` with the event title, truncated to 70 characters if necessary.
- **FR-003**: The system MUST populate `og:description` with a summary that includes the event date, location (if available), and a truncated event description (max 200 characters total).
- **FR-004**: The system MUST set `og:type` to "website" for all pages.
- **FR-005**: The system MUST set `og:site_name` to "fete".
- **FR-006**: The system MUST include fallback Open Graph meta-tags on non-event pages (homepage, event list) with a generic app description.
- **FR-007**: The system MUST include Twitter Card meta-tags (`twitter:card`, `twitter:title`, `twitter:description`) on every page.
- **FR-008**: The system MUST properly HTML-escape all meta-tag values to prevent rendering issues with special characters.
- **FR-009**: The system MUST serve meta-tags in the initial HTML response (not rely on client-side JavaScript rendering) so that crawlers can read them.
- **FR-010**: The system MUST set `og:url` to the canonical URL of the current page.
- **FR-011**: The system MUST include an `og:image` meta-tag on every page, pointing to a generic fete brand image (logo/icon).
### Key Entities
- **Event Metadata**: The subset of event information used for link previews — title, date, location, description. These are read-only projections of existing event data.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: 100% of event page links display a rich preview card (with title and description) when shared in WhatsApp, Telegram, and Signal.
- **SC-002**: All meta-tag values are correctly populated with event-specific data — verified by automated tests against the HTML output.
- **SC-003**: Non-event pages display a meaningful generic preview when shared in messengers.
- **SC-004**: Meta-tags are present in the initial server response (not injected by client-side JavaScript), verifiable by fetching the page without JavaScript execution.
## Clarifications
### Session 2026-03-09
- Q: Should a generic fete brand image be included as `og:image` fallback? → A: Yes, include a generic fete brand image as `og:image` on all pages (logo/icon).
- Q: In which language should meta-tag texts (generic description, site name) be? → A: English for all meta-tag texts.
## Assumptions
- The backend can serve or pre-render HTML with event-specific meta-tags for event detail pages. Since this is a Vue SPA, server-side rendering or a dedicated server-side mechanism will be needed for crawlers that don't execute JavaScript.
- A generic fete brand image (logo/icon) is used as `og:image` on all pages. Event-specific cover images are out of scope and can be added later.
- The date format in `og:description` uses a human-readable English format.
- All meta-tag texts (generic descriptions, site name, fallback content) are in English.