eksplicit mapping af envs
This commit is contained in:
72
Docs/ADMIN.md
Normal file
72
Docs/ADMIN.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Admin Dashboard — Social Proximity
|
||||
|
||||
## Purpose
|
||||
|
||||
The admin dashboard shows anonymised platform statistics — not to monitor users, but to understand if the nudge concept is working.
|
||||
|
||||
**What it shows:**
|
||||
- How many sessions were started today / this week
|
||||
- How many matches were made
|
||||
- Which interest categories are most popular (no user-level breakdown)
|
||||
- How many active sessions right now
|
||||
|
||||
**What it never shows:**
|
||||
- Who matched with whom
|
||||
- Where people were
|
||||
- Individual user data of any kind
|
||||
|
||||
## Technology: Next.js (TypeScript)
|
||||
|
||||
Simple choice: TypeScript, server-side rendering, easy to deploy. No complex state management needed — stats are read-only and refreshed periodically.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
admin/
|
||||
├── src/
|
||||
│ └── app/
|
||||
│ ├── layout.tsx
|
||||
│ ├── page.tsx ← Main dashboard
|
||||
│ └── api/
|
||||
│ └── stats/
|
||||
│ └── route.ts ← Proxy to backend /stats
|
||||
├── components/
|
||||
│ ├── StatCard.tsx ← Single metric card
|
||||
│ ├── InterestChart.tsx ← Bar chart of top interest categories
|
||||
│ └── ActivityChart.tsx ← Sessions/matches over time (7 days)
|
||||
├── package.json
|
||||
└── .env.local.example
|
||||
```
|
||||
|
||||
## Dashboard Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Social Proximity — Admin │
|
||||
├──────────┬──────────┬──────────┬────────────────────┤
|
||||
│ Sessions │ Matches │ Match % │ Active now │
|
||||
│ today │ today │ │ │
|
||||
├──────────┴──────────┴──────────┴────────────────────┤
|
||||
│ Sessions & Matches — last 7 days (line chart) │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Top interest categories (bar chart) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```env
|
||||
BACKEND_URL=http://localhost:8000
|
||||
```
|
||||
|
||||
## Running Locally
|
||||
|
||||
```bash
|
||||
cd admin
|
||||
npm install
|
||||
npm run dev # runs on localhost:3000
|
||||
```
|
||||
|
||||
## Access
|
||||
|
||||
In MVP the dashboard has no login. It should be deployed behind a reverse proxy with IP restriction or basic auth — not exposed publicly.
|
||||
129
Docs/APP.md
Normal file
129
Docs/APP.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Mobile App — Social Proximity
|
||||
|
||||
## Technology Choice: Flutter
|
||||
|
||||
We chose **Flutter** over React Native for this project because BLE scanning requires close hardware access. Flutter compiles to native ARM code and communicates with the platform via direct platform channels — no JavaScript bridge between the app logic and the BLE hardware.
|
||||
|
||||
| | Flutter (chosen) | React Native |
|
||||
|---|---|---|
|
||||
| Language | Dart | TypeScript |
|
||||
| BLE access | Platform channels — native | Via JS bridge |
|
||||
| Performance | Compiles to native | JS runtime overhead |
|
||||
| BLE library | `flutter_blue_plus` | `react-native-ble-plx` |
|
||||
| Platforms | Android + iOS from one codebase | Same |
|
||||
|
||||
**Dart** is straightforward to learn if you know TypeScript: strongly typed, OOP, async/await, null safety built in.
|
||||
|
||||
## BLE Library: `flutter_blue_plus`
|
||||
|
||||
`flutter_blue_plus` is the most actively maintained Flutter BLE library. It supports:
|
||||
- Scanning for nearby BLE peripherals
|
||||
- Advertising as a BLE peripheral (Android 5+, iOS limited)
|
||||
- Reading/writing GATT characteristics
|
||||
- Connection state management
|
||||
|
||||
**Required permissions:**
|
||||
|
||||
_Android (`AndroidManifest.xml`):_
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
```
|
||||
|
||||
_iOS (`Info.plist`):_
|
||||
```xml
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>Used to detect nearby people with shared interests.</string>
|
||||
```
|
||||
|
||||
## BLE Flow
|
||||
|
||||
```
|
||||
App starts
|
||||
└─► Check BLE permissions (request if missing)
|
||||
└─► Generate ephemeral BLE token (UUID v4, per-session)
|
||||
└─► Register token + interests with backend (POST /session)
|
||||
|
||||
User enables "Open to talk"
|
||||
└─► Start BLE advertising (token in manufacturer data)
|
||||
└─► Start BLE scanning for other tokens
|
||||
└─► Open WebSocket to backend (/ws/{token})
|
||||
|
||||
Nearby token detected
|
||||
└─► Send detected token to backend (POST /match)
|
||||
└─► If match: WebSocket nudge received
|
||||
└─► Display nudge card to user
|
||||
|
||||
User disables "Open to talk" or closes app
|
||||
└─► Stop advertising + scanning
|
||||
└─► Close WebSocket
|
||||
└─► Session expires on backend (Redis TTL)
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── lib/
|
||||
│ ├── main.dart
|
||||
│ ├── screens/
|
||||
│ │ ├── onboarding_screen.dart ← Interest selection on first launch
|
||||
│ │ ├── home_screen.dart ← "Open to talk" toggle + nudge display
|
||||
│ │ └── settings_screen.dart ← Manage interests, reset session
|
||||
│ ├── widgets/
|
||||
│ │ ├── nudge_card.dart ← The nudge notification UI
|
||||
│ │ ├── interest_chip.dart ← Selectable interest tag
|
||||
│ │ └── open_toggle.dart ← Big friendly on/off toggle
|
||||
│ ├── services/
|
||||
│ │ ├── ble_service.dart ← BLE scan/advertise logic
|
||||
│ │ ├── api_service.dart ← HTTP client (register, match)
|
||||
│ │ └── ws_service.dart ← WebSocket client (nudge receiver)
|
||||
│ └── models/
|
||||
│ ├── interest.dart
|
||||
│ ├── session.dart
|
||||
│ └── nudge.dart
|
||||
├── android/
|
||||
├── ios/
|
||||
└── pubspec.yaml
|
||||
```
|
||||
|
||||
## Screens
|
||||
|
||||
### Onboarding (first launch)
|
||||
- Choose interest categories (multi-select chips)
|
||||
- Brief explanation of how the app works
|
||||
- Consent acknowledgement
|
||||
|
||||
### Home
|
||||
- Large "Open to talk" toggle — the primary interaction
|
||||
- When active: scanning indicator
|
||||
- Nudge card appears when a match is found
|
||||
- Shows shared interests (no name, no face, no location)
|
||||
- "Say hello" is just a reminder — no in-app chat
|
||||
|
||||
### Settings
|
||||
- Manage interest categories
|
||||
- Reset ephemeral identity
|
||||
- Privacy information
|
||||
|
||||
## State Management
|
||||
|
||||
For MVP simplicity: use Flutter's built-in `Provider` or `Riverpod`.
|
||||
Avoid complex state management (no BLoC in MVP).
|
||||
|
||||
## Running Locally
|
||||
|
||||
```bash
|
||||
cd app
|
||||
flutter pub get
|
||||
flutter run # runs on connected device or emulator
|
||||
flutter run -d android
|
||||
flutter run -d ios
|
||||
```
|
||||
|
||||
**Prerequisites:**
|
||||
- Flutter SDK ≥ 3.x
|
||||
- Android Studio (for Android emulator) or Xcode (for iOS simulator)
|
||||
- Physical device recommended for BLE testing — emulators do not support BLE scanning
|
||||
97
Docs/ARCHITECTURE.md
Normal file
97
Docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Architecture — Social Proximity
|
||||
|
||||
## System Overview
|
||||
|
||||
Social Proximity er bygget som et minimal monorepo med tre separate komponenter:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
│ Mobile App (Flutter) │
|
||||
│ │
|
||||
│ BLE Scanner ──► Match Screen ──► "Say hello" nudge │
|
||||
└───────────────────────┬────────────────────────────────┘
|
||||
│ HTTPS + WebSocket
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
│ Backend (FastAPI) │
|
||||
│ │
|
||||
│ Match Engine ──► Session Store (Redis) ──► DB (PG) │
|
||||
└───────────┬────────────────────────────────────────────┘
|
||||
│ Internal API
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
│ Admin Dashboard (Next.js) │
|
||||
│ │
|
||||
│ Anonymised stats — pings, sessions, interest counts │
|
||||
└────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Mobile App
|
||||
- **Technology:** Flutter (Dart) — cross-platform Android + iOS
|
||||
- **BLE library:** `flutter_blue_plus`
|
||||
- **Responsibility:** BLE scanning and advertisement, interest profile, consent toggle, nudge display
|
||||
- **Does NOT:** store data persistently, track location, communicate with other users directly
|
||||
|
||||
### Backend
|
||||
- **Technology:** FastAPI (Python) + WebSockets
|
||||
- **Session store:** Redis — ephemeral sessions, no long-term identity storage
|
||||
- **Database:** PostgreSQL — anonymised aggregate stats only
|
||||
- **Responsibility:** receive BLE advertisement tokens, match users, push nudge via WebSocket, aggregate stats
|
||||
|
||||
### Admin Dashboard
|
||||
- **Technology:** Next.js (TypeScript)
|
||||
- **Responsibility:** display anonymised platform stats — no PII, no user-level data
|
||||
- **Access:** Internal only (no public-facing auth in MVP)
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Happy path — two users nudged to talk
|
||||
|
||||
```
|
||||
User A opens app, selects interests, enables "open to talk"
|
||||
└─► App generates ephemeral BLE token
|
||||
└─► App advertises token via BLE
|
||||
└─► App registers token + interests with backend (POST /session)
|
||||
|
||||
User B nearby detects User A's BLE token
|
||||
└─► App sends token to backend (POST /match)
|
||||
└─► Backend checks: does B's interest list overlap with A's?
|
||||
└─► If overlap + both consent: backend sends WebSocket nudge to both
|
||||
"Someone nearby also works with DevOps and enjoys hardstyle"
|
||||
└─► Users see nudge, put phones down, say hello
|
||||
└─► Session expires automatically (Redis TTL: 2 hours)
|
||||
```
|
||||
|
||||
### Privacy properties
|
||||
- BLE tokens are ephemeral — regenerated every session
|
||||
- Backend never stores exact location or movement history
|
||||
- Interest matching happens server-side — apps never see each other's raw profile
|
||||
- After session expiry, all session data is deleted from Redis
|
||||
|
||||
## Infrastructure
|
||||
|
||||
| Environment | Platform |
|
||||
|---|---|
|
||||
| Local dev | Docker Compose (backend + PostgreSQL + Redis) |
|
||||
| Production | Azure Container Apps or Kubernetes (i80.dk) |
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
SigHej/
|
||||
├── README.md
|
||||
├── Docs/ ← Technical documentation (this folder)
|
||||
├── backend/ ← FastAPI application
|
||||
├── app/ ← Flutter mobile app
|
||||
├── admin/ ← Next.js admin dashboard
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
See individual docs for each component:
|
||||
- [BACKEND.md](./BACKEND.md)
|
||||
- [APP.md](./APP.md)
|
||||
- [ADMIN.md](./ADMIN.md)
|
||||
- [TESTING.md](./TESTING.md)
|
||||
- [DECISIONS.md](./DECISIONS.md)
|
||||
185
Docs/BACKEND.md
Normal file
185
Docs/BACKEND.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Backend — Social Proximity
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Component | Choice | Reason |
|
||||
|---|---|---|
|
||||
| Framework | FastAPI (Python) | Async, typed, WebSocket support, fast to build |
|
||||
| Session store | Redis | Ephemeral data, TTL-based expiry, low latency |
|
||||
| Database | PostgreSQL | Aggregate stats only — structured, durable |
|
||||
| Real-time | WebSockets (FastAPI native) | Push nudge to app without polling |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
backend/
|
||||
├── app/
|
||||
│ ├── main.py ← FastAPI app init, router registration
|
||||
│ ├── api/
|
||||
│ │ ├── session.py ← POST /session — register BLE token + interests
|
||||
│ │ ├── match.py ← POST /match — attempt proximity match
|
||||
│ │ ├── ws.py ← WebSocket /ws/{token} — real-time nudge channel
|
||||
│ │ ├── stats.py ← GET /stats — anonymised aggregate stats (admin only)
|
||||
│ │ └── health.py ← GET /health
|
||||
│ ├── models/
|
||||
│ │ ├── session.py ← Pydantic: SessionCreate, SessionResponse
|
||||
│ │ ├── match.py ← Pydantic: MatchRequest, MatchResult
|
||||
│ │ └── stats.py ← Pydantic: StatsResponse
|
||||
│ ├── services/
|
||||
│ │ ├── session_service.py ← create/get/expire sessions in Redis
|
||||
│ │ ├── match_service.py ← interest overlap logic + nudge dispatch
|
||||
│ │ └── stats_service.py ← aggregate stats queries (PostgreSQL)
|
||||
│ └── core/
|
||||
│ ├── config.py ← Settings (env vars via pydantic-settings)
|
||||
│ ├── redis.py ← Redis connection pool
|
||||
│ └── database.py ← SQLAlchemy async engine + session
|
||||
├── tests/
|
||||
│ ├── test_session.py
|
||||
│ ├── test_match.py
|
||||
│ └── test_stats.py
|
||||
├── requirements.txt
|
||||
├── requirements-dev.txt
|
||||
├── Dockerfile
|
||||
└── .env.example
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### `POST /session`
|
||||
Register a new ephemeral session when user enables "open to talk".
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"ble_token": "abc123",
|
||||
"interests": ["devops", "hardstyle", "philosophy"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"session_id": "uuid",
|
||||
"expires_at": "2024-01-01T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
- BLE token stored in Redis with 2-hour TTL
|
||||
- Interest list hashed before storage — raw interests never persisted to DB
|
||||
|
||||
---
|
||||
|
||||
### `POST /match`
|
||||
Called when a user's app detects a nearby BLE token.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"own_token": "abc123",
|
||||
"detected_token": "xyz789"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"match": true,
|
||||
"shared_interests": ["devops", "hardstyle"],
|
||||
"nudge_sent": true
|
||||
}
|
||||
```
|
||||
|
||||
- If match found: WebSocket nudge pushed to both parties
|
||||
- Shared interests returned as category labels only — no raw profile data
|
||||
|
||||
---
|
||||
|
||||
### `WebSocket /ws/{ble_token}`
|
||||
Persistent connection from the app. Used to receive real-time nudges.
|
||||
|
||||
**Nudge message (server → client):**
|
||||
```json
|
||||
{
|
||||
"type": "nudge",
|
||||
"shared_interests": ["devops", "hardstyle"],
|
||||
"message": "Someone nearby shares your interest in devops and hardstyle."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `GET /health`
|
||||
Standard health check. Returns `200 OK` with service status.
|
||||
|
||||
---
|
||||
|
||||
### `GET /stats`
|
||||
Anonymised aggregate stats for admin dashboard. Internal access only.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"total_sessions_today": 142,
|
||||
"total_matches_today": 38,
|
||||
"top_interest_categories": ["tech", "music", "philosophy"],
|
||||
"active_sessions_now": 12
|
||||
}
|
||||
```
|
||||
|
||||
## Data Model (Redis)
|
||||
|
||||
Sessions are stored as Redis hashes:
|
||||
|
||||
```
|
||||
KEY: session:{ble_token}
|
||||
VALUE: {
|
||||
"session_id": "uuid",
|
||||
"interests_hash": "sha256(...)",
|
||||
"interest_categories": ["tech", "music"],
|
||||
"created_at": "iso8601"
|
||||
}
|
||||
TTL: 7200 seconds (2 hours)
|
||||
```
|
||||
|
||||
## Data Model (PostgreSQL)
|
||||
|
||||
Only aggregate counters — no user-level rows.
|
||||
|
||||
```sql
|
||||
CREATE TABLE daily_stats (
|
||||
date DATE PRIMARY KEY,
|
||||
total_sessions INTEGER DEFAULT 0,
|
||||
total_matches INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE interest_category_counts (
|
||||
date DATE,
|
||||
category TEXT,
|
||||
count INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (date, category)
|
||||
);
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```env
|
||||
REDIS_URL=redis://localhost:6379
|
||||
DATABASE_URL=postgresql+asyncpg://user:pass@localhost/sighej
|
||||
SESSION_TTL_SECONDS=7200
|
||||
ALLOWED_ORIGINS=http://localhost:3000
|
||||
```
|
||||
|
||||
## Running Locally
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
uvicorn app.main:app --reload --port 8000
|
||||
```
|
||||
|
||||
Or via Docker Compose from root:
|
||||
|
||||
```bash
|
||||
docker-compose up
|
||||
```
|
||||
78
Docs/DECISIONS.md
Normal file
78
Docs/DECISIONS.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Architecture Decision Records — Social Proximity
|
||||
|
||||
This file tracks key architectural decisions made during the project.
|
||||
Each decision includes context, what was decided, and the consequences.
|
||||
|
||||
---
|
||||
|
||||
## ADR-001: Flutter for the mobile app
|
||||
|
||||
**Date:** 2026-05-07
|
||||
**Status:** Accepted
|
||||
|
||||
**Context:**
|
||||
The app requires BLE scanning and advertising to detect nearby users. We needed a cross-platform framework (Android + iOS) that provides reliable, low-latency access to the BLE hardware stack.
|
||||
|
||||
**Decision:**
|
||||
Use Flutter (Dart) with `flutter_blue_plus`.
|
||||
|
||||
Flutter compiles to native ARM code and communicates with the platform via direct platform channels — no JavaScript bridge. This gives more stable and predictable BLE behaviour than React Native's bridge-based architecture. `flutter_blue_plus` is the most actively maintained Flutter BLE library with full support for scanning, advertising, and GATT on both Android and iOS.
|
||||
|
||||
**Consequences:**
|
||||
- Team needs to learn Dart (low barrier — similar to TypeScript)
|
||||
- BLE integration testing requires physical devices, not emulators
|
||||
- Build toolchain: Flutter SDK + Android Studio + Xcode
|
||||
|
||||
---
|
||||
|
||||
## ADR-002: FastAPI for the backend
|
||||
|
||||
**Date:** 2026-05-07
|
||||
**Status:** Accepted
|
||||
|
||||
**Context:**
|
||||
Backend needs to handle short-lived sessions, real-time WebSocket nudges, and serve anonymised stats. Should be fast to build and easy to maintain.
|
||||
|
||||
**Decision:**
|
||||
Use FastAPI (Python) with async support, WebSockets, and Pydantic for request/response validation.
|
||||
|
||||
**Consequences:**
|
||||
- Native async support fits the WebSocket and Redis use cases
|
||||
- Pydantic models double as documentation and runtime validation
|
||||
- Python aligns with DevOpsMCP tooling (complexity, type hints, PEP compliance)
|
||||
|
||||
---
|
||||
|
||||
## ADR-003: Redis for session storage (not PostgreSQL)
|
||||
|
||||
**Date:** 2026-05-07
|
||||
**Status:** Accepted
|
||||
|
||||
**Context:**
|
||||
User sessions are ephemeral by design — they expire after 2 hours and must never be reconstructed. We need fast reads/writes for the match engine.
|
||||
|
||||
**Decision:**
|
||||
Store all active sessions in Redis with a 2-hour TTL. Use PostgreSQL only for aggregate counters (stats).
|
||||
|
||||
**Consequences:**
|
||||
- Sessions are automatically deleted by Redis TTL — no manual cleanup needed
|
||||
- No user-level data ever reaches the database
|
||||
- Redis must be treated as infrastructure (not optional) — included in docker-compose
|
||||
|
||||
---
|
||||
|
||||
## ADR-004: No in-app messaging
|
||||
|
||||
**Date:** 2026-05-07
|
||||
**Status:** Accepted
|
||||
|
||||
**Context:**
|
||||
We want to nudge users into real, face-to-face conversation — not replace it with another chat interface.
|
||||
|
||||
**Decision:**
|
||||
The app will never include a messaging feature. The nudge is the product. After a match, the app's job is done.
|
||||
|
||||
**Consequences:**
|
||||
- Simpler backend (no message storage, no threads)
|
||||
- Clearer privacy posture
|
||||
- Risk: lower engagement metrics — accepted by design
|
||||
103
Docs/TESTING.md
Normal file
103
Docs/TESTING.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Testing & Code Quality — Social Proximity
|
||||
|
||||
## Scope
|
||||
|
||||
These rules apply to the **Python backend** (`backend/`). The Flutter app and Next.js admin have separate tooling.
|
||||
|
||||
Quality analysis runs via **DevOpsMCP** — a set of code analysis tools accessible through the MCP server at `https://devops-mcp.i80.dk`.
|
||||
|
||||
---
|
||||
|
||||
## When to Run What
|
||||
|
||||
| Tool | Trigger | Threshold |
|
||||
|---|---|---|
|
||||
| `check_pep_compliance` | Before every commit | Zero violations |
|
||||
| `check_personal_standards` | Before every commit | Zero `error`-level findings |
|
||||
| `analyze_complexity` | When writing functions > 20 lines | Max cyclomatic complexity: **8** |
|
||||
| `add_type_hints` | When adding new functions | Min type hint coverage: **80%** |
|
||||
| `analyze_missing_docstrings` | New classes and public functions | No missing docstrings on public API |
|
||||
| `analyze_yaml` + `analyze_github_actions` | When editing Gitea CI/CD workflow files | Zero security violations |
|
||||
|
||||
---
|
||||
|
||||
## Coding Standards (Python backend)
|
||||
|
||||
### Enforced by `check_personal_standards`
|
||||
|
||||
- **No `subprocess` with `shell=True`** — use SDK clients instead
|
||||
- **No bare `except:`** — always catch specific exceptions
|
||||
- **No `%` or `.format()` string formatting** — use f-strings
|
||||
- **No mutable default arguments** — use `None` and set inside function body
|
||||
- **No hardcoded secrets** — use environment variables via `pydantic-settings`
|
||||
|
||||
### Enforced by `analyze_complexity`
|
||||
|
||||
- Max cyclomatic complexity per function: **8**
|
||||
- Functions exceeding this must be refactored (extract helper functions)
|
||||
|
||||
### Enforced by `add_type_hints`
|
||||
|
||||
- All function parameters must have type annotations
|
||||
- All function return types must be annotated
|
||||
- Use `Optional[T]` or `T | None` — not bare `None` returns without annotation
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
```
|
||||
1. Write code
|
||||
2. Run check_personal_standards(file) → fix all 'error' findings
|
||||
3. Run analyze_complexity(file) → refactor if any function > 8
|
||||
4. Run add_type_hints(file, apply_changes=False) → review suggestions, apply manually
|
||||
5. Run check_pep_compliance(file) → fix formatting
|
||||
6. Commit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Strategy (backend)
|
||||
|
||||
Tests live in `backend/tests/` and use **pytest**.
|
||||
|
||||
| Layer | What to test | Example |
|
||||
|---|---|---|
|
||||
| Unit | Service logic in isolation | `test_match_service.py` — interest overlap calculation |
|
||||
| Integration | API endpoints with real Redis/DB | `test_session.py` — POST /session creates Redis key |
|
||||
| Contract | Request/response shapes match Pydantic models | Via pytest + httpx TestClient |
|
||||
|
||||
**Run tests:**
|
||||
```bash
|
||||
cd backend
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flutter App Testing
|
||||
|
||||
| Layer | Tool | Notes |
|
||||
|---|---|---|
|
||||
| Unit | `flutter test` | Test service logic, models |
|
||||
| Widget | `flutter test` + `WidgetTester` | Test UI components in isolation |
|
||||
| Integration | `flutter drive` | Requires physical device or emulator |
|
||||
|
||||
BLE scanning cannot be tested in emulators — use a physical device for BLE integration tests.
|
||||
|
||||
---
|
||||
|
||||
## DevOpsMCP Quick Reference
|
||||
|
||||
```python
|
||||
# Upload file and run analysis
|
||||
session = DevOpsMCP-start_project_session("sighej-backend", [
|
||||
{"file_path": "main.py", "content": "<content>"}
|
||||
])
|
||||
|
||||
DevOpsMCP-check_personal_standards(file_path="main.py")
|
||||
DevOpsMCP-analyze_complexity(file_path="main.py")
|
||||
DevOpsMCP-add_type_hints(file_path="main.py", apply_changes=False)
|
||||
DevOpsMCP-check_pep_compliance(file_path="main.py")
|
||||
DevOpsMCP-generate_tests(file_path="main.py")
|
||||
```
|
||||
21
Docs/colors.md
Normal file
21
Docs/colors.md
Normal file
@@ -0,0 +1,21 @@
|
||||
Sunny Beach Day
|
||||
Golden sand meets turquoise waves under a deep blue sky, kissed by coral and sunlit amber warmth.
|
||||
Colors
|
||||
~Charcoal Blue
|
||||
#264653
|
||||
Deep navy undertones blend with smoky steely hues for a sophisticated shade evoking midnight skies and modern elegance.
|
||||
~Verdigris
|
||||
#2a9d8f
|
||||
Shimmering between blue and green, evokes serene tropical tides and the calm of sunlit, crystalline waters.
|
||||
~Jasmine
|
||||
#e9c46a
|
||||
Mellow golden hue suggesting gentle charm, balancing gentle sweetness and cheerful sophistication in every space.
|
||||
~Sandy Brown
|
||||
#f4a261
|
||||
Light orangey-brown radiating summer, beach sand, and sunsets, lending softness and energy to compositions.
|
||||
~Burnt Peach
|
||||
#e76f51
|
||||
Fiery, robust shade bursts with energy, merging glowing embers and ripe fruit for a bold, unforgettable impression.
|
||||
Psychology
|
||||
Meaning
|
||||
every
|
||||
Reference in New Issue
Block a user