190 lines
4.0 KiB
Markdown
190 lines
4.0 KiB
Markdown
# NEDA Backend
|
|
|
|
NEDA is a FastAPI backend for real-time group voice communication.
|
|
It includes authentication, user/group management, WebSocket signaling, Redis for real-time state, and PostgreSQL for persistent data.
|
|
|
|
## Tech Stack
|
|
|
|
- FastAPI + Uvicorn
|
|
- SQLAlchemy (Async) + asyncpg
|
|
- PostgreSQL
|
|
- Redis
|
|
- Alembic
|
|
- LiveKit
|
|
|
|
## Project Structure
|
|
|
|
```text
|
|
core/ config, security, deps
|
|
alembic/ database migrations
|
|
db/ database/redis setup
|
|
domains/ domain modules (auth, users, admin, groups, realtime, notifications)
|
|
integrations/ external integrations (LiveKit)
|
|
scripts/ utility scripts (create_admin)
|
|
main.py FastAPI app entrypoint
|
|
```
|
|
|
|
## Active Routes
|
|
|
|
- `POST /auth/login`
|
|
- `GET /users/`
|
|
- `POST /admin/users`
|
|
- `POST /admin/users/{user_id}/logout`
|
|
- `POST /admin/users/{user_id}/reset-secret`
|
|
- `GET /admin/users`
|
|
- `GET /admin/groups`
|
|
- `POST /groups/`
|
|
- `GET /groups/my`
|
|
- `GET /groups/admin/all`
|
|
- `GET /groups/{group_id}/members`
|
|
- `POST /groups/{group_id}/invite`
|
|
- `DELETE /groups/{group_id}/members/{user_id}`
|
|
- `WS /ws/groups/{group_id}`
|
|
|
|
## Environment Variables
|
|
|
|
Create a `.env` file in the project root:
|
|
|
|
```env
|
|
APP_NAME=NEDA
|
|
DEBUG=False
|
|
|
|
SECRET_KEY=change-me
|
|
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
|
ALGORITHM=HS256
|
|
SECRET_PASS_LENGTH=32
|
|
|
|
POSTGRES_DB=neda
|
|
POSTGRES_USER=neda_user
|
|
POSTGRES_PASSWORD=neda_pass
|
|
DATABASE_URL=postgresql+asyncpg://neda_user:neda_pass@postgres:5432/neda
|
|
|
|
REDIS_URL=redis://redis:6379/0
|
|
|
|
LIVEKIT_API_KEY=neda_key
|
|
LIVEKIT_API_SECRET=neda_secret
|
|
LIVEKIT_HOST=http://livekit:7880
|
|
LIVEKIT_PORT=7880
|
|
LIVEKIT_TCP_PORT=7881
|
|
LIVEKIT_UDP_PORT=7882
|
|
```
|
|
|
|
LiveKit note:
|
|
- This project runs LiveKit v1.9.12 in Docker.
|
|
- `--api-key/--api-secret` are not used; the server receives credentials via `LIVEKIT_KEYS`.
|
|
- `livekit.yaml` is kept as a reference file and is not mounted/used at runtime in `docker-compose.yml`.
|
|
- Docker-internal API host must be `http://livekit:7880`.
|
|
- For local API execution (outside Docker), use a separate env value such as `LIVEKIT_HOST=http://localhost:7780`.
|
|
|
|
## Run With Docker
|
|
|
|
```bash
|
|
docker compose up --build -d
|
|
```
|
|
|
|
Services:
|
|
- API: `http://localhost:8000`
|
|
- Swagger Docs: `http://localhost:8000/docs`
|
|
- LiveKit: `http://localhost:7780`
|
|
- Postgres: `localhost:5432`
|
|
- Redis: `localhost:6379`
|
|
|
|
API logs:
|
|
|
|
```bash
|
|
docker compose logs -f api
|
|
```
|
|
|
|
## Create Admin (Inside Docker)
|
|
|
|
After services are up, create the initial admin user inside the API container:
|
|
|
|
```bash
|
|
docker compose exec api python -m scripts.create_admin
|
|
```
|
|
|
|
The script asks for `username` and optional `phone_number`, creates the user with `is_admin=True`, and prints the initial `secret`.
|
|
|
|
## Admin API Hardening
|
|
|
|
- `POST /admin/users` creates only non-admin users.
|
|
- Sending `is_admin` in the payload is not allowed and returns `422`.
|
|
- Admin creation is only allowed through the server-side script: `scripts/create_admin.py`.
|
|
|
|
Invalid payload example:
|
|
|
|
```json
|
|
{
|
|
"username": "new_user",
|
|
"phone_number": "09123456789",
|
|
"is_admin": true
|
|
}
|
|
```
|
|
|
|
Admin login:
|
|
- Endpoint: `POST /auth/login`
|
|
- Body:
|
|
|
|
```json
|
|
{
|
|
"username": "admin_username",
|
|
"secret": "printed_secret"
|
|
}
|
|
```
|
|
|
|
## Database Migrations (Alembic)
|
|
|
|
This project uses Alembic, and `env.py` reads `DATABASE_URL` from `.env`.
|
|
|
|
Apply migrations (inside Docker):
|
|
|
|
```bash
|
|
docker compose exec api alembic upgrade head
|
|
```
|
|
|
|
Create a new migration (autogenerate):
|
|
|
|
```bash
|
|
docker compose exec api alembic revision --autogenerate -m "your_message"
|
|
```
|
|
|
|
Check current DB revision:
|
|
|
|
```bash
|
|
docker compose exec api alembic current
|
|
```
|
|
|
|
Show migration history:
|
|
|
|
```bash
|
|
docker compose exec api alembic history
|
|
```
|
|
|
|
Important: run `alembic upgrade head` before starting the API in a new environment.
|
|
|
|
## Local Development (Without Docker)
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
source .venv/bin/activate
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
Run migrations:
|
|
|
|
```bash
|
|
alembic upgrade head
|
|
```
|
|
|
|
Start API:
|
|
|
|
```bash
|
|
uvicorn main:app --reload
|
|
```
|
|
|
|
## Realtime Notes
|
|
|
|
- Presence is stored in Redis.
|
|
- Speaker lock is managed atomically in Redis.
|
|
- LiveKit tokens for listener/speaker roles are issued during the WebSocket flow.
|