An event companion and onboarding experience for the ATmosphere (alpha) atmo.quest
6

Configure Feed

Select the types of activity you want to include in your feed.

Go 53.6%
JavaScript 25.4%
templ 13.0%
CSS 7.7%
TypeScript 0.2%
Nix 0.1%
Dockerfile 0.1%
Other 0.1%
65 13 0

Clone this repository

https://tangled.org/vvill.dev/atmoquest https://tangled.org/did:plc:4qiqeh7zxqzqjiq3zydc66hb
git@knot.vvill.dev:vvill.dev/atmoquest git@knot.vvill.dev:did:plc:4qiqeh7zxqzqjiq3zydc66hb

For self-hosted knots, clone URLs may differ based on your setup.



README.md

atmo.quest#

An event-companion app on ATProto. Scan a QR, write a private note, leave a conference with a real follow-up list. Records live in your PDS, not ours.

Quick start#

cp .env.example .env
go tool task live

Then open the URL printed in the logs (defaults to http://127.0.0.1:9090). The task live recipe runs templ-watch, the web-asset bundler, and an air-driven live-reloading Go server. task is registered as a Go tool dependency, so no separate install is needed. If you'd rather have a bare task on your PATH: brew install go-task. For a one-shot run without live reload: go run -tags dev ./cmd/web.

On first boot the app creates data/atmoquest.db (SQLite) and data/admin_signing.key (ed25519, badge signing). No further setup needed.

Use 127.0.0.1, not localhost — atproto OAuth requires the redirect URI to match the configured PUBLIC_URL exactly. If port 9090 is taken on your machine, edit .env and update both PORT and PUBLIC_URL to match.

Useful routes#

Route Notes
/ Guest landing or authed dashboard, depending on session
/signin Start OAuth via your Bluesky handle
/profile, /profile/edit View / edit your atmo.quest profile
/c/{did} Connect page (target of QR scans)
/e/{token} Event check-in page
/admin Admin console — requires users.is_admin = 1
/healthz Liveness probe

To grant yourself admin after signing in once, either:

# Local dev: edit the SQLite file directly.
sqlite3 data/atmoquest.db "UPDATE users SET is_admin=1 WHERE did='did:plc:…';"

Or set BOOTSTRAP_ADMIN_DIDS (space-separated) and restart the app. The listed DIDs are promoted to admin on every boot — idempotent and safe to leave set. This is the supported path in deployed environments where sqlite3 isn't reachable (the prod image is scratch-based):

BOOTSTRAP_ADMIN_DIDS="did:plc:xxx did:plc:yyy"

Either way, the DID must have signed in at least once first (so the users row exists).

Layout#

cmd/web/          entrypoint
config/           env + config singleton
router/           top-level route wiring
features/<name>/  handlers.go, routes.go, pages/*.templ
internal/<name>/  storage & domain logic (event, checkin, profile, …)
web/resources/    static assets (css, js, fonts, datastar)

Env vars#

Var Default Required
PORT 8080 no
PUBLIC_URL http://127.0.0.1:$PORT no (dev) / yes (prod)
SESSION_SECRET dev default yes in prod
DATABASE_URL file:data/atmoquest.db?… no
ADMIN_SIGNING_KEY auto-generated in dev yes in prod
BOOTSTRAP_ADMIN_DIDS unset no
LOG_LEVEL INFO no

-tags dev selects the dev config (random session key, auto-generated admin key). -tags prod (or no tag, in CI) requires the real secrets above.

Tests#

go test -tags dev ./...

Production build#

go tool task build      # writes bin/main, embeds prod tag
./bin/main

Or Docker:

docker build -t atmoquest:latest .
docker run --rm -p 8080:8080 \
  -v atmoquest_data:/data \
  -e PUBLIC_URL=https://your.domain \
  -e SESSION_SECRET=$(openssl rand -hex 32) \
  -e ADMIN_SIGNING_KEY=$(openssl rand -base64 32) \
  -e BUCKET_NAME=your-bucket \
  -e AWS_ENDPOINT_URL_S3=https://your-s3-endpoint \
  -e AWS_ACCESS_KEY_ID=\
  -e AWS_SECRET_ACCESS_KEY=\
  -e AWS_REGION=auto \
  atmoquest:latest

The image bundles Litestream as its supervisor process: it watches /data/atmoquest.db's WAL and streams changes to S3-compatible object storage. Replica config lives in litestream.yml and reads bucket + credentials from the BUCKET_NAME / AWS_* env vars above. Litestream is required — without those vars set the container won't start. Mount a volume at /data so the database and the OAuth signing key (/data/oauth_key.pem) survive restarts.

Contributing#

PRs and feature requests welcome.