# 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 `.ts` directly on Node 24 (no build step); SQLite via the built-in `node:sqlite` module (avatar cache at `data/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 ```bash 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: docker compose up --build ``` Deploy gates (run before pushing): ```bash 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.