628c398e

By: Michael Lynch <git@mtlynch.io>

Add owner media uploads (milestone 6)

Owners can now upload photos and videos through the web UI, the first
write path in the app. Everything was previously read-only, populated
only by the offline import-from-tinybeans command.

Behavior:
- An always-visible "Upload" button appears in the navbar for owners
  (outside the collapsible region so it stays visible on mobile).
- Photos (JPEG) and animated GIFs are processed synchronously: the
  full-size image is re-encoded to strip Exif/metadata, and display and
  thumbnail variants are generated, before the item is published.
- Videos are transcoded to WebM (VP9 + Opus) in a background worker. The
  uploader sees a "Video processing in progress" notice and the item is
  hidden from other users until transcoding completes.
- Uploads are owner-only; subscribers get 403 and never see the button.

Media model and storage:
- Video is now always WebM. The TinyBeans import pipeline transcodes
  imported .mp4 videos to .webm too, so the system has a single video
  format. ImportMedia takes an injected video converter alongside the
  GIF converter.
- media_items gains a status column (ready/processing). ReadMediaItems
  filters by viewer so processing items are visible only to their
  uploader.

Other changes:
- newPageData resolves the current user to expose IsOwner to templates.
- The app binary is wrapped with ffmpeg in flake.nix, and the prod
  Dockerfile installs ffmpeg, since the app now execs ffmpeg/ffprobe.

Known limitation: because raw originals are not retained, a server
restart mid-transcode leaves a video stuck in the processing state;
durable job scheduling is future work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
configuredevShellbackendbackend-devcheck-bashcheck-frontendcheck-go-formattingcheck-go-test-packagescheck-trailing-newlinecheck-trailing-whitespacediagramdocker-imagee2e-testsgo-testsimport-from-tinybeanslint-sqllittle-momentslittle-moments-devx86_64-linux