# SigHej — AI Session Prompt > Paste this file at the start of a new AI coding session to get full project context. --- ## Hvad er SigHej? SigHej er et **nudge-værktøj** til fysiske samtaler i den virkelige verden. Idéen er simpel: folk i samme rum kan have interesser til fælles uden at vide det. SigHej bruger BLE (Bluetooth Low Energy) til at opdage nærliggende brugere, tjekker om der er fælles interesser, og sender et diskret nudge til begge parter — *"nogen i nærheden deler din interesse for X — sig hej"*. Det er det. Ingen chat, ingen profiler, ingen social graph. Kun et lille skub til en rigtig samtale. **Kerneprincipper:** - Ingen beskedudveksling — nudget er produktet, ikke en chat-app - Privacyby design — ingen lokationsdata, ingen bruger-ID'er, ephemerelle tokens - Simpelt og fokuseret — ét skærmbillede, én knap, ét formål --- ## Monorepo-struktur ``` SigHej/ ├── README.md ├── prompt.md ← dette fil ├── Makefile ← build workflow ├── docker-compose.yml ← backend + PostgreSQL + Redis ├── Docs/ │ ├── ARCHITECTURE.md ← system overview og data flow │ ├── BACKEND.md ← FastAPI detaljer │ ├── APP.md ← Flutter app detaljer │ ├── ADMIN.md ← Next.js admin detaljer │ ├── TESTING.md ← test- og kodestandarder │ ├── DECISIONS.md ← ADR'er (architecture decision records) │ └── colors.md ← "Sunny Beach Day" farvepalet ├── backend/ ← FastAPI Python ├── app/ ← Flutter Dart (Android + iOS + web) └── admin/ ← Next.js TypeScript admin dashboard ``` --- ## Teknisk arkitektur ### Flutter App (`app/`) - **Sprog:** Dart, Flutter 3.x - **BLE:** `flutter_blue_plus` ^1.36.8 — *kun scanning* på Android/iOS; web/macOS kører i demo-mode - **State:** `provider` + `SessionStore` (ChangeNotifier) - **Persistens:** `shared_preferences` — navn, tagline, interesser, bleToken - **Screens:** - `ProfileScreen` — første-gangs onboarding + redigering af profil - `HomeScreen` — hoved-skærm med toggle-knap, pulseanimation og nudge-kort - **Theme:** `app/lib/theme.dart` — "Sunny Beach Day" farvepalet, light + dark mode - **Platform-betinget BLE:** `_bleAvailable` guard — alle BLE-kald er beskyttet; web/macOS simulerer match efter 3 sekunder (demo mode) - **Web:** kører i Chrome via `flutter run -d chrome --web-port 8080` **Farvepalet (Sunny Beach Day):** | Rolle | Navn | Hex | |---|---|---| | Primary | Verdigris | `#2A9D8F` | | Secondary | Sandy Brown | `#F4A261` | | Tertiary | Jasmine | `#E9C46A` | | Error/CTA | Burnt Peach | `#E76F51` | | Surface dark | Charcoal Blue | `#264653` | ### Backend (`backend/`) - **Sprog:** Python 3.12, FastAPI, async - **Session store:** Redis (TTL: 2 timer — auto-sletning, ingen cleanup nødvendig) - **Database:** PostgreSQL — kun anonymiserede aggregat-statistikker (ingen PII) - **Kommunikation:** REST (POST /session, POST /match) + WebSocket (nudge push) - **Config:** `pydantic-settings` — miljøvariabler, ingen hardcodede secrets - **Tests:** pytest, httpx TestClient ### Admin Dashboard (`admin/`) - **Sprog:** TypeScript, Next.js 14 - **Formål:** anonymiserede stats — pings, sessioner, interest counts - **Ingen PII, ingen bruger-niveau data** - **Build:** multi-stage Docker, `output: "standalone"`, kræver `package-lock.json` --- ## Data flow — happy path ``` Bruger A åbner app → vælger interesser → aktiverer "Åben for snak" └─► App genererer ephemeral BLE token (UUID) └─► App advertiser token via BLE (Android/iOS) └─► App registrerer token + interesser: POST /session Bruger B i nærheden scanner BLE → finder A's token └─► App sender token: POST /match └─► Backend: overlapper B's interesser med A's? └─► Ja → WebSocket nudge til begge: "Nogen i nærheden deler din interesse for X — sig hej" └─► Brugerne lægger telefonen fra sig og siger hej └─► Session udløber automatisk (Redis TTL: 2 timer) ``` --- ## Makefile workflow ```bash make up # start backend + PostgreSQL + Redis (Docker) make down # stop services make build # byg Docker images make logs # følg logs make be-dev # kør FastAPI i dev mode (hot reload) make be-test # kør pytest make be-lint # ruff lint make be-fmt # ruff format make adm-dev # kør Next.js admin i dev mode make adm-build # byg admin til produktion make app-get # flutter pub get make app-analyze # flutter analyze (skal være "No issues found!") make app-test # flutter test make check # fuld CI: lint + test på alle tre komponenter ``` --- ## Kodestandarder ### Python backend Analyse kører via **DevOpsMCP** (`https://devops-mcp.i80.dk`): ```python # Upload og analysér session = DevOpsMCP-start_project_session("sighej-backend", [ {"file_path": "main.py", "content": ""} ]) DevOpsMCP-check_personal_standards(file_path="main.py") # ingen error-findings DevOpsMCP-analyze_complexity(file_path="main.py") # max complexity: 8 DevOpsMCP-add_type_hints(file_path="main.py") # min 80% coverage DevOpsMCP-check_pep_compliance(file_path="main.py") # zero violations ``` **Regler:** - Ingen `subprocess` med `shell=True` — brug SDK-klienter - Ingen bare `except:` — fang specifikke exceptions - Kun f-strings — ingen `%` eller `.format()` - Ingen mutable default-argumenter - Ingen hardcodede secrets — kun env vars via `pydantic-settings` ### Flutter app - `flutter analyze` skal altid returnere `No issues found!` - Alle BLE-kald skal guards af `_bleAvailable` - Ingen direkte import af `dart:io` på web-paths ### Git commits Brug conventional commits: ``` feat(app): tilføj pulsanimation til toggle-knap fix(backend): ret Redis TTL ved session-fornyelse docs: opdater ARCHITECTURE.md med WebSocket flow ``` --- ## Arkitekturbeslutninger (ADR-resumé) | ADR | Beslutning | Begrundelse | |---|---|---| | ADR-001 | Flutter frem for React Native | Native ARM, stabil BLE via direkte platform channels | | ADR-002 | FastAPI frem for Express/Django | Async-first, Pydantic validation, hurtig at bygge | | ADR-003 | Redis til sessions, ikke PostgreSQL | Ephemerelle data, auto-TTL, ingen manuel cleanup | | ADR-004 | Ingen in-app messaging | Nudget ER produktet — chat modarbejder formålet | --- ## Privacy-design - **Ingen bruger-ID'er** — kun ephemerelle BLE tokens (UUID, ny pr. session) - **Ingen lokationsdata** — BLE proximity er ikke GPS - **Server-side matching** — apps ser aldrig hinandens rå profiler - **Auto-sletning** — Redis TTL 2 timer, ingen data efterlades - **Aggregat-stats kun** — PostgreSQL indeholder aldrig PII --- ## Kendte begrænsninger (MVP) - BLE advertising kræver fysisk Android/iOS-enhed — ikke tilgængeligt på macOS/web Flutter - Web/macOS kører i **demo mode**: simulerer et match efter 3 sekunder - Admin dashboard har ingen auth i MVP — bør tilføjes før produktion - Ingen push notifications (FCM/APNs) endnu — nudge vises kun mens app er åben - Android SDK + Xcode krævet for at bygge til mobile (se `flutter doctor`) --- ## Kom i gang (ny maskine) ```bash # Klon repo git clone && cd SigHej # Start backend infrastruktur make up # Flutter app i browser cd app && flutter pub get && flutter run -d chrome --web-port 8080 # Flutter app på Android (kræver USB debugging + Android SDK) flutter devices flutter run -d ``` Se `Docs/` for detaljeret dokumentation om hvert komponent.