eksplicit mapping af envs
This commit is contained in:
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
|
||||
```
|
||||
Reference in New Issue
Block a user