nginx includes auth_enabled.conf, (re)written at container start from BASIC_AUTH_USER/PASSWORD (htpasswd via apache2-utils). Both set => the site + /api require a shared login; unset => open (local dev not locked out). Set both on the Coolify web service to protect the deployment.
photofetch
Deployed at https://photofetch.apoena.dev
Pick one or more Napta projects and get a grid of the people staffed on each — every person shown with their Slack profile picture, first name, last name, and role. People are matched between Napta and Slack by email. Selected projects are shown as separate groups, and you can export everyone's photos as a zip with one folder per project (people without a Slack photo get a generated initials image).
See CONTEXT.md for the vocabulary and DESIGN.md
for the design decisions.
Architecture
- frontend (repo root) — Vite + Vue 3 + TypeScript + Tailwind v4 + DaisyUI SPA.
- backend/ — TypeScript/Node API (Hono) that proxies Napta + Slack so their
tokens never reach the browser. Runs
.tsdirectly on Node 24 (no build step); SQLite via the built-innode:sqlitemodule (avatar cache atdata/app.db). Serves demo fixtures until live credentials are configured.
In production, nginx serves the built SPA and proxies /api to the backend
service (see nginx.conf + docker-compose.yml).
Develop
pnpm install
pnpm dev # frontend on :5173 (proxies /api -> :8000)
cd backend && pnpm install && pnpm dev # API on :8000
# …or run the whole stack in containers (open http://localhost:8080):
docker compose up --build
Deploy gates (run before pushing):
pnpm lint # oxlint (pnpm lint:fix to autofix)
pnpm fmt:check # oxfmt (pnpm fmt to format)
pnpm build # vue-tsc + vite build, no warnings
cd backend && pnpm typecheck
Configuration (live data)
Set on the Coolify app (or in backend/.env locally — see backend/.env.example):
| Var | Purpose |
|---|---|
NAPTA_CLIENT_ID / NAPTA_CLIENT_SECRET |
Napta Auth0 M2M credentials (lists projects + staffing). Without both → demo fixtures. |
NAPTA_BASE_URL |
Napta API base (default https://app.napta.io/api/v1) |
SLACK_BOT_TOKEN |
Slack bot token, scopes users:read + users:read.email. Optional — without it, Members show initials. |
BASIC_AUTH_USER / BASIC_AUTH_PASSWORD |
Set both (on the web service) to require a shared login for the whole site. Unset → open. |
Without Napta credentials the API serves demo fixtures and the UI shows a
"demo data" banner. BASIC_AUTH_* go on the web service; the rest on api.
Deploy
Pushes to main are picked up by Coolify at https://platform.apoena.dev and
deployed to https://photofetch.apoena.dev.