fc039ac0fcf2092e95107bd6cf2e483c72ae68da
photofetch
Deployed at https://photofetch.apoena.dev
Pick a Napta project and get a grid of the people staffed on it — each with their Slack profile picture, first name, last name, and role. People are matched between Napta and Slack by email.
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_API_TOKEN |
Napta API token (lists projects + their people) |
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 |
Without both tokens the API serves demo fixtures and the UI shows a "demo data" banner.
Deploy
Pushes to main are picked up by Coolify at https://platform.apoena.dev and
deployed to https://photofetch.apoena.dev.
Description
Languages
TypeScript
62.7%
Vue
30.6%
Dockerfile
2.5%
CSS
1.7%
Shell
1.6%
Other
0.9%