Posts can carry a Photo (IndieWeb photo) backed by a SQLite media store #131
Labels
No labels
kind
bug
kind
enhancement
wayfinder
grilling
wayfinder
map
wayfinder
prototype
wayfinder
research
wayfinder
task
workflow
needs-info
workflow
needs-triage
workflow
ready-for-agent
workflow
ready-for-human
workflow
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rosa/vernier#131
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Posts can carry a Photo (IndieWeb
photo) backed by a SQLite media storeLet a Post carry a single optional Photo — its IndieWeb
photo— rendered atthe top of the Post under the byline. Any Post may carry one, Article or Note. The
image is uploaded, optimized, and stored as a BLOB in SQLite, and served from
this instance's own origin. Both the web editor and Micropub can attach one.
Design was settled in a grilling / domain-modeling session; this issue is the
umbrella that carries it into code.
Design docs
docs/adr/0017-media-is-stored-as-optimized-blobs-in-sqlite.md— store,optimization, security allowlist
docs/adr/0018-media-is-served-at-an-unlisted-grade-capability-url.md—serving + the Private-is-only-Unlisted-grade trade-off
docs/adr/0019-media-creation-is-one-domain-op-behind-multiple-adapters.md— shared create-Media op + multipart forms
CONTEXT.md— new terms Photo, Media; Private sharpenedSettled decisions
photoproperty, not a bespoke "featured image". Class isu-photo.{ url, alt: optional }; renderalt=""when absent.Media the author owns via a
photo_media_idFK (URL→id resolution is thesame-origin enforcement).
media-scoped token, no Operator gate; per-upload size cap.media-endpointinq=config.media:content; Atom native<link rel="enclosure">.Phases (bottom-up; each compiles and is independently testable)
Mediamodel +Photo/PhotoRef { media_id, alt }value objects;photo: Option<PhotoRef>onPost/PostCreate/PostEdit; thread throughPost::new. Glossary terms already inCONTEXT.md.mediatable (random v4 id,user_idON DELETE CASCADE,content_type,bytesBLOB,byte_size,width,height,created_at);photo_media_idFK +photo_altonposts; migration;Mediaport ops(create + fetch); row mappings; mocks; regenerate
.sqlx.→ strip EXIF → downscale-only → WebP re-encode, with pre-decode dimension/byte
guards. Pick the initial pixel-bound + encoder quality here (tunable, not
ADR-frozen).
GET /media/{id}capability route, immutableCache-Control,no per-request authz (ADR-0018).
AppService(ADR-0019).POST /media; promote the dormantmediaScope to a real variant (token parsing, consent screen
scope_label/scope_field); advertisemedia-endpointinq=config.photoproperty — parse in create/update DTOs (reject-on-multiple→ new
MicropubError::TooManyPhotos);photoasSingleUpdate<PhotoRef>inapply_to; emit inq=source; URL→media_idsame-origin + author-owned resolution.new/post+editforms becomemultipart/form-data; fileinput + "remove photo" checkbox + editable alt; remove > replace > keep;
ValidatedFormlearns multipart; per-route body-limit bump (not global).<img class="u-photo" alt="…">under the byline before.e-content;example_postparity; CSS fragment.media:content(declare themedianamespace on the channel,attach a generic
Extensionper item); Atom<link rel="enclosure">;FeedEntry/FeedData::from_profilecarry the Media metadata.Deferred
Tracked separately — see the linked issues in the comments.
Deferred decisions, tracked separately:
Initial optimization tuning (pixel-bound + encoder quality) is chosen in phase 3
of this issue, not deferred — ADR-0017 leaves it a tunable knob rather than an
ADR-frozen value.