[READ-ONLY] Mirror of https://github.com/agbocsardi/waffle-app.
Go 72%
JavaScript 17%
HTML 10%
Shell <1%
<1%
Dockerfile <1%

README.md

Wednesday Waffle #

A lightweight webapp for hosting weekly short video check-ins between friends.

Prerequisites #

# macOS
brew install go ffmpeg

Running #

go run ./cmd/server

Server starts on http://localhost:8080.

Environment variables:

  • WAFFLE_ADDR — bind address (default :8080)
  • WAFFLE_DB — SQLite path (default ./waffle.db)
  • WAFFLE_VIDEOS_DIR — uploaded video storage (default ./videos)
  • WAFFLE_PUBLIC_URL — public URL for invite links
  • WAFFLE_SECURE_COOKIES — set true when served over HTTPS
  • WAFFLE_SESSION_MAX_AGE — session cookie lifetime in seconds (default 30 days)
  • WAFFLE_TRANSCODE_WORKERS — max concurrent FFmpeg jobs (default 2)
  • WAFFLE_TRANSCODE_QUEUE — max queued transcode jobs (default 10)
  • WAFFLE_UPLOAD_RATE_LIMIT — max uploads per user per window (default 10)
  • WAFFLE_UPLOAD_RATE_WINDOW — rate-limit window in seconds (default 3600)
  • WAFFLE_UPLOAD_QUOTA_BYTES — per-user total storage quota in bytes (default 1073741824, 1 GB)
  • WAFFLE_BACKUP_DIR — directory for timestamped backups (empty disables backups)
  • WAFFLE_BACKUP_RETENTION — number of backups to keep (default 7)

Backups #

Run a one-off backup:

go run ./cmd/backup

The command copies the SQLite database (via VACUUM INTO) and the videos directory into a timestamped folder under WAFFLE_BACKUP_DIR. Older backups are pruned to WAFFLE_BACKUP_RETENTION copies.

For production, schedule this command daily with cron or a systemd timer.

Testing #

go test ./...

API Reference #

Join a conversation #

Creates a session for the user if the invite code is valid.

POST /api/conversations/join
Content-Type: application/json

{ "invite_code": "happy-blue-waffle", "username": "alice" }

Response sets a waffle_session cookie used for all subsequent requests.


Create a conversation #

Requires authentication. The creator is automatically added as a member.

POST /api/conversations
Content-Type: application/json

{ "name": "College Friends" }

Response:

{ "id": "...", "invite_code": "happy-blue-waffle", "name": "College Friends" }

List your conversations #

GET /api/conversations

Log out #

POST /api/logout

Clears the waffle_session cookie and invalidates the session on the server.


Upload a video #

POST /api/upload
Content-Type: multipart/form-data

fields:
  - file            (video file, supported: .mp4 .mov .avi .mkv)
  - conversation_id (string)

Upload is accepted immediately (HTTP 202). Transcoding to 720p MP4 happens in the background with up to 3 retries. Original file is deleted only after successful transcoding.


List conversation members #

GET /api/conversations/<id>/members

Response:

["alice", "bob"]

Delete a video #

DELETE /api/videos/<id>

Only the uploader can delete their own video.


List videos in a conversation #

GET /api/videos?conversation_id=<id>

Response:

[
  {
    "id": "...",
    "uploader": "alice",
    "status": "ready",
    "uploaded_at": "2026-02-20T12:00:00Z"
  }
]

Video statuses: pending, ready, error.