# Agent Instructions These instructions are authoritative for work in this repository. ## Project Overview Abgeordnetenwatch PWA + Backend — a progressive web app that lets users follow Bundestag/Landtag topics and politicians, displaying a personalized feed of votes with push notifications for new votes. The PWA queries the Abgeordnetenwatch API directly for browsing; the backend polls for new votes and sends Web Push notifications to subscribed devices. ## Stack — PWA (root) | Layer | Tool | |---|---| | Runtime | Bun | | Build | Vite + TanStack Router Plugin + vite-plugin-pwa (injectManifest) | | UI | React 19 + shadcn/ui + Tailwind CSS v4 | | Routing | TanStack Router (file-based, `src/routes/app/` for mobile) | | State | Zustand (ephemeral UI), PGlite (persistent data via IndexedDB) | | Validation | Zod | | Code Quality | Biome + simple-git-hooks + lint-staged | | Testing | Vitest + Testing Library | ## Stack — Backend (`server/`) | Layer | Tool | |---|---| | Runtime | Node 22 (production via tsx), Bun (development) | | Framework | Hono + @hono/node-server | | Database | PostgreSQL + Drizzle ORM | | Job Queue | pg-boss (cron: poll-checker every 15 min) | | Push | web-push (VAPID) | | Validation | Zod | | Testing | Vitest | ## Architecture ``` src/ PWA source ├── features/ Feature modules │ ├── home/ Home tab (placeholder) │ ├── bundestag/ Bundestag tab: DIP + AW feed, configure (topics + reps) │ ├── landtag/ Landtag tab: representatives by geo-detection, configure │ ├── feed/ Shared feed components (FeedList, FeedItemCard, useFeed) │ ├── location/ Geo-detection, Bundestag mandate caching, party metadata │ ├── topics/ useTopics hook (shared by configure pages) │ └── settings/ Settings page (notifications, location, updates) ├── shared/ Shared code │ ├── components/ representative-list, topic-toggle-list │ │ └── ui/ shadcn components │ ├── db/ PGlite client, migrations, data-access modules, DbProvider │ ├── hooks/ use-device-id, use-follows, use-push, use-pwa-update │ └── lib/ aw-api, dip-api, constants, push-client, utils ├── routes/ TanStack Router file-based routes │ ├── app/ Tabs: Home / Bundestag / Landtag / Einstellungen │ │ ├── bundestag/ index (feed) + configure sub-route │ │ └── landtag/ index (reps) + configure sub-route │ └── index.tsx Redirect → /app/home ├── sw.ts Custom service worker (precache + push handlers) ├── app.tsx RouterProvider ├── app.css Tailwind v4 + shadcn theme └── main.tsx Entry point server/ Backend source ├── src/ │ ├── features/push/ Push subscription routes + service │ ├── shared/ │ │ ├── db/ Drizzle client + schema (push_subscriptions, device_follows, seen_polls, politician_mandates) │ │ ├── jobs/ pg-boss client + poll-checker cron │ │ └── lib/ env validation, AW API client (server-side), web-push helper │ ├── app.ts Hono app assembly │ └── index.ts Entry point ├── drizzle.config.ts ├── package.json └── .env.example DATABASE_URL, PORT, VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT ``` ## Deployment - PWA: static files deploy to Uberspace at `/var/www/virtual//html/agw/` - Backend: deployed as a supervisord service on Uberspace at `~/services/agw-backend/` - Backend API is reverse-proxied at `/agw/api/` via `uberspace web backend` - `./deploy.sh` builds and deploys both PWA and backend - Apache `.htaccess` handles SPA routing ## Commands — PWA (root) - `bun dev` — start dev server - `bun run build` — production build - `bun run test` — run tests - `bun run lint` — biome check - `bun run lint:fix` — biome auto-fix ## Commands — Backend (`server/`) - `bun dev` — start with file watching - `bun start` — start with Node + tsx (production) - `bun run db:generate` — generate Drizzle migrations - `bun run db:migrate` — run Drizzle migrations - `bun run test` — run tests - `bun run lint` — biome check