| .. | ||
| alembic | ||
| core | ||
| db | ||
| domains | ||
| integrations/livekit | ||
| scripts | ||
| .dockerignore | ||
| .gitignore | ||
| .python-version | ||
| alembic.ini | ||
| docker-compose.yml | ||
| Dockerfile | ||
| livekit.yaml | ||
| livekit.yaml.template | ||
| main.py | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
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
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/loginGET /users/POST /admin/usersPOST /admin/users/{user_id}/logoutPOST /admin/users/{user_id}/reset-secretGET /admin/usersGET /admin/groupsPOST /groups/GET /groups/myGET /groups/admin/allGET /groups/{group_id}/membersPOST /groups/{group_id}/inviteDELETE /groups/{group_id}/members/{user_id}WS /ws/groups/{group_id}
Environment Variables
Create a .env file in the project root:
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:
livekit.yaml.templateis a template, not a direct runtime config.- The
livekitcontainer generates/etc/livekit.yamlfrom env values at startup. - Raw YAML does not automatically resolve
${...}placeholders unless templated first.
Run With Docker
docker compose up --build -d
Services:
- API:
http://localhost:8000 - Swagger Docs:
http://localhost:8000/docs - LiveKit:
http://localhost:7880 - Postgres:
localhost:5432 - Redis:
localhost:6379
API logs:
docker compose logs -f api
Create Admin (Inside Docker)
After services are up, create the initial admin user inside the API container:
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/userscreates only non-admin users.- Sending
is_adminin the payload is not allowed and returns422. - Admin creation is only allowed through the server-side script:
scripts/create_admin.py.
Invalid payload example:
{
"username": "new_user",
"phone_number": "09123456789",
"is_admin": true
}
Admin login:
- Endpoint:
POST /auth/login - Body:
{
"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):
docker compose exec api alembic upgrade head
Create a new migration (autogenerate):
docker compose exec api alembic revision --autogenerate -m "your_message"
Check current DB revision:
docker compose exec api alembic current
Show migration history:
docker compose exec api alembic history
Important: run alembic upgrade head before starting the API in a new environment.
Local Development (Without Docker)
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Run migrations:
alembic upgrade head
Start API:
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.