abgeordnetenwatch PWA + backend

feature-based React PWA with Hono backend:
- feed from abgeordnetenwatch.de API (polls by topic + politician)
- follow topics, search and follow politicians
- geo-based politician discovery via Nominatim
- push notifications for new polls via web-push
- service worker with offline caching
- deploy to Uberspace 8 (systemd, PostgreSQL, web backend proxy)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 08:14:22 +01:00
commit 4e3aa682ac
51 changed files with 4131 additions and 0 deletions

87
AGENTS.md Normal file
View File

@@ -0,0 +1,87 @@
# 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/`) |
| State | Zustand (UI), localStorage (Follows) |
| 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 (feed, topics, politicians, location, settings)
│ └── <feature>/ components/, hooks/, lib/, index.ts
├── shared/ Shared code
│ ├── components/ui/ shadcn components
│ ├── hooks/ use-device-id, use-follows, use-push, use-pwa-update
│ └── lib/ aw-api, constants, push-client, utils
├── routes/ TanStack Router file-based routes
├── 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/<user>/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