docs: add production deployment guide (Dokploy)
- new DEPLOYMENT.md: security model, env vars, first deploy, DB reset - README: clarify demo accounts are dev-only, link to DEPLOYMENT.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
91
DEPLOYMENT.md
Normal file
91
DEPLOYMENT.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# Deployment (Dokploy)
|
||||||
|
|
||||||
|
Guide for deploying Space Booking to production via Dokploy. The app ships as a
|
||||||
|
Docker Compose stack (`docker-compose.yml`): a `backend` (FastAPI/SQLite) and a
|
||||||
|
`frontend` (Vue, served behind Traefik).
|
||||||
|
|
||||||
|
## Security model (read first)
|
||||||
|
|
||||||
|
- **No demo accounts in production.** The demo seed (`backend/seed_db.py`) only
|
||||||
|
runs when `RUN_SEED=1` is set — never set it in production.
|
||||||
|
- **First user becomes admin.** The first account to register on a fresh
|
||||||
|
database is automatically made `superadmin` and is activated immediately (no
|
||||||
|
email verification needed). **Register your own account first, right after the
|
||||||
|
first deploy.**
|
||||||
|
- **SECRET_KEY is enforced.** With `DEBUG=false` (the production default) the
|
||||||
|
backend refuses to start unless `SECRET_KEY` is a strong, random value
|
||||||
|
(≥ 32 chars, not a known placeholder). Tokens are forgeable with a weak key.
|
||||||
|
- **CORS** is restricted to `FRONTEND_URL` in production; `localhost` is allowed
|
||||||
|
only in dev (`DEBUG=true`).
|
||||||
|
|
||||||
|
## Required environment variables (Dokploy → service → Environment)
|
||||||
|
|
||||||
|
```
|
||||||
|
SECRET_KEY=<openssl rand -hex 32>
|
||||||
|
FRONTEND_URL=https://space.roa.romfast.ro
|
||||||
|
DOMAIN=space.roa.romfast.ro
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not** set `DEBUG` (defaults to `false` = production) and do **not** set
|
||||||
|
`RUN_SEED`.
|
||||||
|
|
||||||
|
Optional (email/SMTP — needed so non-admin users can verify their accounts):
|
||||||
|
|
||||||
|
```
|
||||||
|
SMTP_ENABLED=true
|
||||||
|
SMTP_HOST=smtp.example.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USER=user@example.com
|
||||||
|
SMTP_PASSWORD=...
|
||||||
|
SMTP_FROM_ADDRESS=rezervari@romfast.ro
|
||||||
|
```
|
||||||
|
|
||||||
|
> Without SMTP, only the first user (the admin, auto-activated) can log in;
|
||||||
|
> other registrations stay inactive until email verification.
|
||||||
|
|
||||||
|
## First deploy
|
||||||
|
|
||||||
|
1. Push the latest code to the git remote that Dokploy tracks (`master`).
|
||||||
|
2. In Dokploy, set the environment variables above.
|
||||||
|
3. **Deploy / Redeploy.** Tables are created automatically on boot.
|
||||||
|
4. Open the site → **Register** with your own email → you become `superadmin`.
|
||||||
|
|
||||||
|
## Resetting the database (start clean)
|
||||||
|
|
||||||
|
The production DB lives in the Docker volume `backend_data`, mounted at
|
||||||
|
`/data/space_booking.db`.
|
||||||
|
|
||||||
|
> ⚠️ Deleting the DB file while the container is running has no immediate
|
||||||
|
> effect — the app holds the file open and keeps using it. You **must restart**
|
||||||
|
> the container afterwards so it creates a fresh, empty database.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Find the backend container
|
||||||
|
docker ps | grep backend
|
||||||
|
# e.g. constanta-space-booking-mnsx1b-backend-1
|
||||||
|
|
||||||
|
# 2. Delete the database file
|
||||||
|
docker exec -it <container> rm -f /data/space_booking.db
|
||||||
|
|
||||||
|
# 3. Restart so the app recreates an empty DB
|
||||||
|
docker restart <container>
|
||||||
|
|
||||||
|
# 4. Verify it is empty (should print: users: [])
|
||||||
|
docker exec -it <container> \
|
||||||
|
python3 -c "import sqlite3; c=sqlite3.connect('/data/space_booking.db'); print('users:', list(c.execute('select id,email,role,is_active from users')))"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then go to the site and register your admin account again.
|
||||||
|
|
||||||
|
## Inspecting users in production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it <container> \
|
||||||
|
python3 -c "import sqlite3; c=sqlite3.connect('/data/space_booking.db'); [print(r) for r in c.execute('select id,email,role,is_active from users')]"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local development
|
||||||
|
|
||||||
|
For local dev with demo data, set `DEBUG=true` and `RUN_SEED=1`. The seed reads
|
||||||
|
account passwords from `ADMIN_PASSWORD` / `MANAGER_PASSWORD` / `USER_PASSWORD`
|
||||||
|
(weak defaults if unset). See `backend/.env.example`.
|
||||||
41
README.md
41
README.md
@@ -64,9 +64,12 @@ npm run dev
|
|||||||
|
|
||||||
Frontend will be available at: http://localhost:5173
|
Frontend will be available at: http://localhost:5173
|
||||||
|
|
||||||
## Demo Accounts
|
## Demo Accounts (local dev only)
|
||||||
|
|
||||||
After seeding the database (runs automatically on container start):
|
Demo accounts are **not** created in production. They are seeded only for local
|
||||||
|
development, and only when `RUN_SEED=1` is set (see `backend/.env.example`).
|
||||||
|
In production, the first user to register becomes the `superadmin` — see
|
||||||
|
[DEPLOYMENT.md](DEPLOYMENT.md).
|
||||||
|
|
||||||
| Email | Password | Role |
|
| Email | Password | Role |
|
||||||
|-------|----------|------|
|
|-------|----------|------|
|
||||||
@@ -74,6 +77,9 @@ After seeding the database (runs automatically on container start):
|
|||||||
| manager@example.com | managerpassword | Manager |
|
| manager@example.com | managerpassword | Manager |
|
||||||
| user@example.com | userpassword | User |
|
| user@example.com | userpassword | User |
|
||||||
|
|
||||||
|
> Passwords are overridable via `ADMIN_PASSWORD` / `MANAGER_PASSWORD` /
|
||||||
|
> `USER_PASSWORD`. Defaults are weak and for local use only.
|
||||||
|
|
||||||
## Docker Compose (local)
|
## Docker Compose (local)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -90,29 +96,20 @@ Backend API: http://localhost:8000/docs
|
|||||||
|
|
||||||
## Deploy (Dokploy)
|
## Deploy (Dokploy)
|
||||||
|
|
||||||
```
|
See **[DEPLOYMENT.md](DEPLOYMENT.md)** for the full production guide (security
|
||||||
Dokploy UI → New Service → Docker Compose → Git: space-booking repo
|
model, environment variables, first-deploy steps, and how to reset the
|
||||||
```
|
database).
|
||||||
|
|
||||||
### Environment Variables (Dokploy → Environment tab)
|
Quick version:
|
||||||
|
|
||||||
| Variable | Required | Example |
|
1. `Dokploy UI → New Service → Docker Compose → Git: space-booking repo`
|
||||||
|----------|----------|---------|
|
2. Set environment variables (`SECRET_KEY`, `FRONTEND_URL`, `DOMAIN`).
|
||||||
| `SECRET_KEY` | **Yes** | `python -c "import secrets; print(secrets.token_hex(32))"` |
|
3. Deploy. Tables are auto-created on boot; **no demo data** is seeded.
|
||||||
| `FRONTEND_URL` | **Yes** | `https://space.roa.romfast.ro` |
|
4. Open the site → **Register your own account first** → you become
|
||||||
| `SMTP_ENABLED` | No | `true` |
|
`superadmin`.
|
||||||
| `SMTP_HOST` | No* | `smtp.example.com` |
|
|
||||||
| `SMTP_PORT` | No* | `587` |
|
|
||||||
| `SMTP_USER` | No* | `user@example.com` |
|
|
||||||
| `SMTP_PASSWORD` | No* | `secret` |
|
|
||||||
| `SMTP_FROM_ADDRESS` | No* | `rezervari@romfast.ro` |
|
|
||||||
|
|
||||||
*Required only if `SMTP_ENABLED=true`
|
> The backend refuses to start in production unless `SECRET_KEY` is a strong,
|
||||||
|
> random value. Do not set `RUN_SEED` in production.
|
||||||
### Auto-seed
|
|
||||||
|
|
||||||
`entrypoint.sh` runs `seed_db.py` automatically on every container start.
|
|
||||||
The script is idempotent — skips if data already exists.
|
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user