You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

6.2 KiB

ROADMAP

Goal: Build a self-hosted security camera footage viewer — Go backend, modern dark UI, Docker Compose deployment, responsive for desktop and mobile.


Constraints

  • Target hardware: Intel Atom (low CPU budget). Minimise transcoding at all costs.
  • Video files are raw H.265 bitstreams (.265). Browsers cannot play them natively.
  • Remuxing (copy stream into MP4 container) is acceptable — no re-encode.
  • No Node.js build step. Tailwind CSS loaded from CDN.

Footage directory layout (read-only mount)

<FOOTAGE_ROOT>/
  YYYYMMDD/
    images/   A<YYYYMMDD><HHMMSS><seq>.jpg
    record/   A<YYYYMMDD>_<HHMMSS>_<HHMMSS>.265
  • FOOTAGE_ROOT is configured as an env var / volume in docker-compose.yml.
  • The app must not write into the footage tree (thumbnails cached in memory).

Priority 1 — Project scaffold

Objective: Establish a working Go module, Dockerfile, and docker-compose skeleton so every subsequent task has a solid base to build on.

  • Go module github.com/domagojzecevic/cammonitor (or local path).
  • cmd/server/main.go entry point, chi router wired up, static health endpoint.
  • Multi-stage Dockerfile (builder → gcr.io/distroless/static or debian:slim for ffmpeg).
  • docker-compose.yml with:
    • app service (Go binary)
    • FOOTAGE_ROOT volume bind-mount configurable via .env
    • DB_PATH for SQLite file
    • Port mapping (default 8080)
  • README.md with quick-start instructions.

Priority 2 — Auth (multi-user, SQLite)

Objective: Secure the app behind a login wall with session cookies and an admin user-management page.

  • SQLite schema: users table (id, username, bcrypt_password_hash, is_admin, created_at).
  • SQLite schema: sessions table (token, user_id, expires_at).
  • First-run bootstrap: if no users exist, create an admin user from env vars (ADMIN_USER, ADMIN_PASS).
  • Login page (/login): username + password form, sets session cookie on success.
  • Logout endpoint (/logout).
  • Auth middleware protecting all non-login routes.
  • Admin user-management page (/admin/users): list, add, delete users (admin only).
  • Session expiry configurable via env var (SESSION_TTL, default 24 h).

Priority 3 — Footage scanner

Objective: Efficiently list available days, images, and videos from the footage tree.

  • On startup and periodically (configurable interval, default 5 min), scan FOOTAGE_ROOT.
  • Build an in-memory index: map[date]DayEntry where DayEntry holds sorted slices of image paths and video paths.
  • Expose a simple internal API used by HTTP handlers to query the index.
  • Parse filenames to extract timestamps for display and sorting.
  • Handle missing images/ or record/ sub-directories gracefully.

Priority 4 — Image browser

Objective: Browse JPEG images for a selected day with thumbnail strip and arrow navigation.

  • Route /day/{date}/images — lists all images for the day.
  • Thumbnail endpoint /thumb/image/{relpath}: resize JPEG to 160×90 px in Go (golang.org/x/image or stdlib image + nfnt/resize or manual scaling), cache result in memory (bounded LRU, max 500 entries).
  • Full-image endpoint /raw/image/{relpath}: serve JPEG directly from disk (no processing).
  • UI:
    • Fixed top strip showing all image thumbnails for the day (horizontally scrollable).
    • Main area shows the currently selected image at full width.
    • Left / right arrow buttons (keyboard and on-screen) to step through images.
    • Active thumbnail highlighted in the strip.
    • Deep-linkable URL per image (?idx=N).

Priority 5 — Video browser

Objective: Browse and play H.265 videos for a selected day with thumbnail strip, arrow navigation, and on-demand remux streaming.

  • Route /day/{date}/videos — lists all videos for the day.
  • Thumbnail endpoint /thumb/video/{relpath}: extract first frame via ffmpeg -i <pipe or file> -vframes 1 -f image2 pipe:1, scale to 160×90, cache in memory (bounded LRU, max 200 entries).
  • Stream endpoint /stream/video/{relpath}: ffmpeg -i {input} -c:v copy -movflags frag_keyframe+empty_moov -f mp4 pipe:1 piped directly to the HTTP response (Content-Type: video/mp4). No disk writes. One ffmpeg process per active stream (kill on client disconnect).
  • UI:
    • Fixed top strip showing all video thumbnails for the day (horizontally scrollable, shows clip duration parsed from filename).
    • Main area: HTML5 <video> player (controls, autoplay on navigation).
    • Left / right arrow buttons (keyboard and on-screen) to step through videos.
    • Active thumbnail highlighted in the strip.
    • Deep-linkable URL per video (?idx=N).

Priority 6 — Responsive layout & day navigation

Objective: Unified dark-theme shell that adapts to desktop and mobile viewports.

  • Tailwind CSS dark palette (slate-900 background, slate-700 cards, accent indigo-500).
  • Desktop (≥ 768 px): collapsible left sidebar listing available days grouped by month; clicking a day navigates to its images or videos tab.
  • Mobile (< 768 px): sidebar hidden; top navigation bar with a hamburger/date picker drawer; bottom tab bar for Images / Videos switch.
  • Shared header: app name, logged-in username, logout button.
  • Smooth transitions between images/videos on the same day without full-page reloads (HTMX swap or minimal vanilla JS fetch).
  • Keyboard shortcuts: / navigate items, I/V switch tabs.

Acceptance Criteria (overall)

  • docker compose up starts a working app with no extra steps beyond setting env vars.
  • Login required before any footage is visible.
  • Images load directly from disk with no processing delay.
  • Videos play in the browser within ~2 s of clicking (remux start latency).
  • Thumbnail strip visible and scrollable on both desktop and mobile.
  • Arrow navigation works on desktop (keyboard) and mobile (touch buttons).
  • All pages pass basic responsiveness check at 375 px and 1280 px viewport widths.
  • go vet ./... and go test ./... pass cleanly.

Out of scope (this cycle)

  • Live / real-time camera feed.
  • Motion detection or alerting.
  • Video download / export.
  • Per-camera filtering (footage layout assumed to be one camera per day folder for now).
  • HTTPS termination (expected to sit behind a reverse proxy or Tailscale).