Erste Vereins-App, die fremde Drittseiten crawlt und aggregiert (Event-Übersicht Konstanz/Kreuzlingen, DE+CH zusammen). Phase-0- Build dependency-arm (manaspur-Pattern): keine @mana/* via Verdaccio, Föderations-Boilerplate inline. - Hono+Bun-API mit health/manifest/search/takedown/dsgvo - Drizzle-Schema (8 Tabellen) gemäß AGGREGATOR_POLICY §6: countries, regions, venues, event_sources, events, crawl_jobs (mit robots_check_passed-Compliance-Beweis), takedown_requests, blocked_domains - Crawl-Policy-Skelett (assertCrawlAllowed) mit Block-List-Check + Pro-Host-Rate-Limit; robots.txt-Lookup pending α-1 - mana-research- und mana-geocoding-Client-Stubs - Search-Endpoint public (kein Auth — Browse-only MVP) - Postgres lokal :5441, db:push grün, /healthz + /readyz + /.well-known/mana-app.json smoke-getestet Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.7 KiB
CLAUDE.md — Seepuls
Guidance für Claude Code in diesem Repo.
Wenn du gerade neu bist: lies zuerst
STATUS.md— dort steht der aktuelle Phasen-Stand. Dieses CLAUDE.md ist nur die Konventions- und Architektur-Referenz.
Was dieses Repo ist
Seepuls — Event-Aggregator für die Grenzregion Konstanz/Kreuzlingen
(Bodensee, DE+CH zusammen). Föderierte App des mana e.V.-Ökosystems.
Erste Vereins-App, die fremde Drittseiten crawlt, aggregiert und
re-publiziert — gilt die AGGREGATOR_POLICY.md
in mana/docs/.
HTTPS ┌──────────────────┐
mana e.V. ◄─────────────── │ seepuls/ │ Postgres `seepuls`
Plattform │ (this repo) │ seepuls.mana.how
• mana-research (crawl) │ Astro-Web + │
• mana-geocoding (DE/CH-Geo) │ Hono-API │
• mana-media (Bilder) └──────────────────┘
• mana-auth (Phase β) ▲
│ HTTPS
│
┌─────────┴────────┐
│ Drittseiten │
│ (Kulturhaus etc.)│
│ via Firecrawl │
└──────────────────┘
Status
Phase α-0 — Repo-Skelett (2026-05-15). Manifest + API-Boilerplate
stehen, DB-Schema und Crawler-Pipeline noch nicht implementiert.
Roadmap siehe STATUS.md.
Architektonische Invarianten
Beschlossen. Nicht ohne explizite Diskussion antasten.
- Aggregator-Policy ist nicht-verhandelbar. robots.txt, ≥1s
Crawl-Delay, User-Agent mit Kontakt-Mail, sichtbare Attribution,
Take-Down-Endpoint binnen 72h vorläufige Deaktivierung. Siehe
AGGREGATOR_POLICY.md. - Cross-Border by design. Default-Ansicht zeigt DE+CH gemeinsam.
countries-Tabelle mit ISO-Codes (DE/CH),regions-Tabelle als curated Klammer (bodensee,hegau,thurgau-west). - mana-research als Crawl-Provider. Eigene Crawler vermeiden; Firecrawl/Jina respektieren robots.txt by default. Cost-Tracking geht über mana-credits.
- Hot-Link für Bilder (Default). Bilder von Drittseiten werden
nicht lokal gehostet —
<img src="originalquelle">. Lokales Caching nur als begründete Ausnahme. - MVP ohne User-Auth. Browse + Take-Down sind public; Claim-Flow und Lieblings-Venue-Abo kommen mit mana-auth ab Phase β-3.
- Web ist Astro mit Hono-API, nicht SvelteKit. Begründung in Plan: Discovery-/SEO-Last, hohe statische Seitenzahl, Mobile-First.
- Eigene Postgres-DB
seepulsim geteilten Mana-Cluster (lokal :5441), Schema-Isolation viapgSchema('seepuls').
Stack
| Layer | Wahl |
|---|---|
| Web | Astro (Node-Adapter, SSR + Islands für Filter+Karte) |
| API | Hono + Bun |
| Datenbank | PostgreSQL + Drizzle ORM |
| Auth | @mana/shared-hono/auth (JWKS aus mana-auth, ab β-3) |
| Föderation | @mana/shared-app-tpl für Manifest/Share/Tools/DSGVO |
| Crawl | mana-research (Firecrawl/Jina/Readability) |
| Geo | mana-geocoding (Photon Europe, DE+CH) |
| Storage | mana-media (nur App-eigene Bilder, nicht gecrawlte) |
| Job-Scheduling | node-cron in-process (kein Plattform-Scheduler) |
Ports: API 3095, Web 3096, Postgres 5441 (siehe
../mana/docs/PORTS.md).
Repo-Struktur
seepuls/
├── apps/
│ ├── api/ Hono+Bun-Backend (Phase α-0+)
│ │ └── src/
│ │ ├── index.ts App-Boot + shared-app-tpl-Mounts
│ │ ├── handlers.ts Share-/Tool-Handler (leer im MVP)
│ │ ├── store.ts Datenzugriff (Drizzle, später)
│ │ └── db/schema/ Drizzle-Schema (folgt α-0)
│ └── web/ Astro-Frontend (Phase α-4, später)
├── packages/ leer für jetzt
├── docs/ repo-eigene Doks
├── app-manifest.json Föderations-Manifest (validiert beim Boot)
├── docker-compose.yml lokales Postgres :5441
├── STATUS.md aktueller Phasen-Stand
└── .github/workflows/ ci.yml
Datenmodell (Plan, gemäß AGGREGATOR_POLICY §6)
countries DE, CH (hartcodiert)
regions bodensee, hegau, thurgau-west, … (curated)
venues Org/Lokal-Eintrag, gecrawlt oder geclaimt
event_sources N pro venue; Listing-URL + Crawl-Intervall
events Einzel-Event, deduplikiert via external_id_hash
crawl_jobs Audit-Trail: was wurde wann gecrawlt, mit
robots_check_passed-Flag (Compliance-relevant)
takedown_requests DSGVO-/Urheber-Anfragen mit Frist-Tracking
blocked_domains Source-Block-Liste (Eskalations-Stufe 2)
Föderations-Vertrag
Pflicht-Endpoints (alle aus @mana/shared-app-tpl):
| Method | Path | Quelle |
|---|---|---|
GET |
/healthz, /readyz, /healthz/details |
healthRoutes() |
GET |
/.well-known/mana-app.json |
wellKnownManifestHandler() |
POST |
/api/v1/share/receive |
shareReceiveRouter() (Handler leer im MVP) |
POST |
/api/v1/tools/:name |
toolsRouter() (Handler leer im MVP) |
GET |
/api/v1/search?q= |
app-eigen, public (keine Auth) |
GET |
/api/v1/dsgvo/export |
dsgvoExportHandler() (takedown-Mails) |
Manifest-Drift-Check beim Boot — Service startet nicht, wenn das Manifest nicht zum aktuellen Schema-Stand passt.
Konventionen
- pnpm 9.15.x, Node 20+, Turborepo 2.x, Bun für API-Runtime
- Tabs für Indent, single quotes, 100-col Prettier
- Drizzle 0.38 / drizzle-kit 0.30 (Plattform-Einklang)
- JWT-Validation lokal über JWKS-Cache (5 min), kein Live-Call
- Service-to-Service via
X-Service-Key(MANA_SERVICE_KEY) - Tests: Vitest
Crawler-Disziplin (Pflicht)
Jeder Crawl muss durch src/crawl/policy.ts (folgt α-1) gehen, die
folgendes prüft und protokolliert:
robots.txt-Lookup pro Host (gecached 24h)- User-Agent:
SEEPULS_CRAWL_USER_AGENTaus env, mit+https://seepuls.mana.how; kontakt@mana.how - ≥ 1.1s zwischen Requests pro Host (
SEEPULS_CRAWL_INTERVAL_MS) - ETag/If-Modified-Since vom letzten Crawl mitgeben
- Backoff bei 429/503 (exponential, min 6h)
- Audit-Log in
crawl_jobsmitrobots_check_passed: bool— Compliance-Beweis
Bei Verstößen: mana-compliance-Subagent kann ein Veto auf einen Live-
Crawl-Cut werfen. Pre-Live-Check ist Pflicht.
Lokal entwickeln
pnpm install # @mana/* aus pkg.mana.how
pnpm docker:up || docker compose up -d # lokales Postgres :5441
pnpm --filter ./apps/api dev # API auf :3095
# (apps/web folgt in α-4)
Voraussetzungen:
- mana-Plattform-Stack lokal laufend (mindestens
mana-auth:3001,mana-research:3068,mana-geocoding:3075) - Verdaccio-Token in
~/.npmrc(npm login --registry=https://pkg.mana.how)
Wichtige Cross-Repo-Doks
../mana/docs/AGGREGATOR_POLICY.md— Crawl-Regeln, nicht-verhandelbar../mana/docs/FEDERATION.md— Architektur-Grundlage../mana/docs/PORTS.md— Port-Allokation../mana/services/mana-research/CLAUDE.md— Crawl-Provider../mana/services/mana-geocoding/CLAUDE.md— DE+CH-Geo