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>
This commit is contained in:
98
specs/012-link-preview/contracts/html-meta-tags.md
Normal file
98
specs/012-link-preview/contracts/html-meta-tags.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Contract: HTML Meta-Tags
|
||||
|
||||
**Feature**: 012-link-preview | **Date**: 2026-03-09
|
||||
|
||||
## Overview
|
||||
|
||||
This feature does not add new REST API endpoints. The contract is the HTML meta-tag structure injected into the server-rendered `index.html`.
|
||||
|
||||
## Meta-Tag Contract: Event Pages
|
||||
|
||||
For requests to `/events/{eventToken}` where the event exists:
|
||||
|
||||
```html
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="{event title, max 70 chars}">
|
||||
<meta property="og:description" content="{formatted description, max 200 chars}">
|
||||
<meta property="og:url" content="{absolute canonical URL}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="fete">
|
||||
<meta property="og:image" content="{absolute URL}/og-image.png">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{event title, max 70 chars}">
|
||||
<meta name="twitter:description" content="{formatted description, max 200 chars}">
|
||||
```
|
||||
|
||||
### Description Format
|
||||
|
||||
Full event data:
|
||||
```
|
||||
📅 Saturday, March 15, 2026 at 7:00 PM · 📍 Berlin — First 200 chars of description...
|
||||
```
|
||||
|
||||
No location:
|
||||
```
|
||||
📅 Saturday, March 15, 2026 at 7:00 PM — First 200 chars of description...
|
||||
```
|
||||
|
||||
No description:
|
||||
```
|
||||
📅 Saturday, March 15, 2026 at 7:00 PM · 📍 Berlin
|
||||
```
|
||||
|
||||
No location, no description:
|
||||
```
|
||||
📅 Saturday, March 15, 2026 at 7:00 PM
|
||||
```
|
||||
|
||||
### Title Truncation
|
||||
|
||||
- Titles ≤ 70 characters: used as-is.
|
||||
- Titles > 70 characters: truncated to 67 characters + "..."
|
||||
|
||||
### HTML Escaping
|
||||
|
||||
All meta-tag `content` values MUST be HTML-escaped:
|
||||
- `"` → `"`
|
||||
- `&` → `&`
|
||||
- `<` → `<`
|
||||
- `>` → `>`
|
||||
|
||||
## Meta-Tag Contract: Non-Event Pages
|
||||
|
||||
For requests to `/`, `/create`, or any other non-event, non-API, non-static route:
|
||||
|
||||
```html
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="fete">
|
||||
<meta property="og:description" content="Privacy-focused event planning. Create and share events without accounts.">
|
||||
<meta property="og:url" content="{absolute canonical URL}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="fete">
|
||||
<meta property="og:image" content="{absolute URL}/og-image.png">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="fete">
|
||||
<meta name="twitter:description" content="Privacy-focused event planning. Create and share events without accounts.">
|
||||
```
|
||||
|
||||
## Meta-Tag Contract: Event Not Found
|
||||
|
||||
For requests to `/events/{eventToken}` where the event does NOT exist, fall back to generic meta-tags (same as non-event pages). The Vue SPA will handle the 404 UI client-side.
|
||||
|
||||
## Injection Mechanism
|
||||
|
||||
The `index.html` template contains a placeholder:
|
||||
|
||||
```html
|
||||
<head>
|
||||
...
|
||||
<!-- OG_META_TAGS -->
|
||||
...
|
||||
</head>
|
||||
```
|
||||
|
||||
The server replaces `<!-- OG_META_TAGS -->` with the generated meta-tag block before sending the response.
|
||||
Reference in New Issue
Block a user