Create Rich-Content-and-Media wiki page
@@ -0,0 +1,42 @@
|
||||
# Rich content & media
|
||||
|
||||
Images and video are first-class; embeds/charts/diagrams are a founding requirement (v1.1 §29-A restores what v1.0 omitted).
|
||||
|
||||
## Media pipeline (§29.1–29.4, v1.1)
|
||||
|
||||
- **Storage port** `ObjectStorage` (put/get/stat/delete); initial adapter stores on `/var/lib/eppp/media`; future adapters target S3/R2/MinIO without changing content records (content stores media IDs, never absolute paths).
|
||||
- **Upload validation (§29.1):** size checked before reading the body; content type from magic bytes (client header/extension advisory only); SHA-256 on ingest (duplicate checksum returns the existing record); generated content-addressed keys, never the original filename.
|
||||
- **Image processing (§29.2):** every accepted image re-encoded before serving (original bytes never served); metadata stripped, orientation baked in then dropped (GPS/camera serial never reach the public volume); derivative widths 480/800/1200/1600/2400 (never upscaled), AVIF + WebP per width + one universal JPEG fallback; rendered images carry `width`/`height` (zero CLS); lazy-load below the fold; immutable one-year cache headers.
|
||||
- **Video posture (§29.3):** no transcoding in v1; accept MP4 (H.264 + AAC) only, reject others with a message naming export settings; probe dimensions/duration, generate a poster frame.
|
||||
|
||||
## Embeds — three tiers (§29-A.1)
|
||||
|
||||
| Tier | Mechanism | Survives provider death | Public JS |
|
||||
|---|---|---|---|
|
||||
| 1 Native | chart/diagram blocks rendered server-side to SVG | yes | none |
|
||||
| 2 Snapshot | embed + locally cached static image | degrades to image | none |
|
||||
| 3 Live | sandboxed iframe from allowlisted host, click-to-load | no | one island |
|
||||
|
||||
The editor steers to tier 1 whenever data belongs to the author ("paste data" beside "paste embed URL").
|
||||
|
||||
## Provider allowlist (§29-A.2)
|
||||
|
||||
`eppp_embed_providers`: exact hostnames only (no wildcards), admin-editable, every change audited. Seed: Observable, Datawrapper, CodePen, `youtube-nocookie.com`, `player.vimeo.com`, `archive.org`, plus a configurable self-hosted Grafana host. Enforced twice: in the renderer and in a CSP `frame-src` generated from the same table.
|
||||
|
||||
## Fetch, cache & privacy (§29-A.3)
|
||||
|
||||
On save of content containing an embed: resolve provider by exact host (unknown host = author-visible error); fetch oEmbed through the hardened fetch; sanitise to an iframe with allowlisted `src` + dimensions; download and re-host the thumbnail (never hotlink); refresh on a 30-day cycle. Live iframes are click-to-load; every iframe carries `sandbox`, `referrerpolicy="no-referrer"`, `loading="lazy"`, a required `title`. **No reader request reaches a third party before explicit interaction.**
|
||||
|
||||
## Hardened outbound fetch (§29-A.4, core)
|
||||
|
||||
One shared core service (oEmbed, thumbnail download, future link checker): resolve DNS first and reject private/loopback/link-local/multicast/metadata ranges; re-check after every redirect (max 3), pinning the connection to the pre-resolved address (closes DNS-rebinding); 10 s timeout, 5 MB cap; worker egress additionally restricted at the network layer. No extension ever writes its own outbound fetch (FIT-015).
|
||||
|
||||
## Native charts & diagrams (§29-A.5)
|
||||
|
||||
`core.chart` (line, bar, area, scatter; CSV/JSON props) and `core.diagram` (Mermaid), rendered server-side to a single inline `<svg>`: every chart carries `<title>`, `<desc>` and a visually-hidden data table; all colour comes from theme tokens (a literal colour in chart output is a build failure, FIT-016); renderers are pure functions (no headless browser, no client bundle, no network); limits are configuration (2000 points / 12 series default, exceeded at save time).
|
||||
|
||||
Ownership: blocks/UX ship as first-party extensions (`org.eppp.embeds`, `org.eppp.charts`, or one `org.eppp.rich-content`); hardened fetch + CSP generation are core (FIT-015–017).
|
||||
|
||||
## Metadata & syndication (§34-A, v1.1)
|
||||
|
||||
Core (every content type needs it): per-page `<title>`, meta description, canonical URL, Open Graph tags, JSON-LD `BlogPosting` (headline, datePublished, dateModified, author) on articles; `sitemap.xml` regenerated on publish; `robots.txt` excluding `/admin` and `/api`; `ETag`/`Last-Modified` with conditional requests. RSS remains a v0.2 extension. Open Graph images (when added) are generated server-side (SVG rasterised at publish, cached as a media object), no headless browser.
|
||||
Reference in New Issue
Block a user