Merge pull request 'docs: add from-scratch deploy script and env templates' (#12) from chore/deploy-script-from-scratch into dev
All checks were successful
CI / skip-ci-check (pull_request) Successful in 7s
CI / lint-and-type-check (pull_request) Successful in 51s
CI / python-lint (pull_request) Successful in 31s
CI / test-backend (pull_request) Successful in 2m30s
CI / build (pull_request) Successful in 3m18s
CI / secret-scanning (pull_request) Successful in 15s
CI / dependency-scan (pull_request) Successful in 13s
CI / sast-scan (pull_request) Successful in 1m24s
CI / workflow-summary (pull_request) Successful in 6s

Reviewed-on: #12
This commit is contained in:
tanyar09 2026-01-28 14:40:07 -05:00
commit fe9dbc77e5
5 changed files with 445 additions and 0 deletions

20
.env_example Normal file
View File

@ -0,0 +1,20 @@
# PunimTag root environment (copy to ".env" and edit values)
# PostgreSQL (main application DB)
DATABASE_URL=postgresql+psycopg2://punimtag:CHANGE_ME@127.0.0.1:5432/punimtag
# PostgreSQL (auth DB)
DATABASE_URL_AUTH=postgresql+psycopg2://punimtag_auth:CHANGE_ME@127.0.0.1:5432/punimtag_auth
# JWT / bootstrap admin (change these!)
SECRET_KEY=CHANGE_ME_TO_A_LONG_RANDOM_STRING
ADMIN_USERNAME=admin
ADMIN_PASSWORD=CHANGE_ME
# Photo storage
PHOTO_STORAGE_DIR=/punimtag/data/uploads
# Redis (RQ jobs)
REDIS_URL=redis://127.0.0.1:6379/0

View File

@ -0,0 +1,6 @@
# Admin frontend env (copy to ".env" )
# Backend API base URL (must be reachable from the browser)
VITE_API_URL=

276
docs/DEPLOY_FROM_SCRATCH.md Normal file
View File

@ -0,0 +1,276 @@
# Deploying PunimTag (From Scratch, Simple)
This guide is for a **fresh install** where the databases do **not** need to be migrated.
You will start with **empty PostgreSQL databases** and deploy the app from a copy of the repo
(e.g., downloaded from **SharePoint**).
PunimTag is a monorepo with:
- **Backend**: FastAPI (`backend/`) on port **8000**
- **Admin**: React/Vite (`admin-frontend/`) on port **3000**
- **Viewer**: Next.js (`viewer-frontend/`) on port **3001**
- **Jobs**: Redis + RQ worker (`backend/worker.py`)
---
## Prerequisites (One-time)
On the server you deploy to, install:
- **Python 3.12+**
- **Node.js 18+** and npm
- **PostgreSQL 12+**
- **Redis 6+**
- **PM2** (`npm i -g pm2`)
Also make sure the server has:
- A path for uploaded photos (example: `/punimtag/data/uploads`)
- Network access to Postgres + Redis (local or remote)
### Quick install (Ubuntu/Debian)
```bash
sudo apt update
sudo apt install -y \
python3 python3-venv python3-pip \
nodejs npm \
postgresql-client \
redis-server
sudo systemctl enable --now redis-server
redis-cli ping
# PM2 (process manager)
sudo npm i -g pm2
```
Notes:
- If you manage Postgres on a separate host, you only need `postgresql-client` on this server.
- If you install Postgres locally, install `postgresql` (server) too, not just the client.
---
## Fast path (recommended): run the deploy script
On Ubuntu/Debian you can do most of the setup with one script:
```bash
cd /opt/punimtag
chmod +x scripts/deploy_from_scratch.sh
./scripts/deploy_from_scratch.sh
```
The script will:
- Install system packages (including Redis)
- Copy `*_example` env files to real `.env` files (if missing)
- Install Python + Node dependencies
- Generate Prisma clients for the viewer
- Create auth DB tables and admin user (idempotent)
- Start services with PM2
If you prefer manual steps, continue below.
## Step 1 — Put the code on the server
If you received the code via SharePoint:
1. Download the repo ZIP from SharePoint.
2. Copy it to the server (SCP/SFTP).
3. Extract it into a stable path (example used below):
```bash
sudo mkdir -p /opt/punimtag
sudo chown -R $USER:$USER /opt/punimtag
# then extract/copy the repository contents into /opt/punimtag
```
---
## Step 2 — Create environment files (rename `_example` → real)
### 2.1 Root env: `/opt/punimtag/.env`
1. Copy and rename:
```bash
cd /opt/punimtag
cp .env_example .env
```
2. Edit `.env` and set the real values. The template includes **at least**:
```bash
# PostgreSQL (main database)
DATABASE_URL=postgresql+psycopg2://USER:PASSWORD@HOST:5432/punimtag
# PostgreSQL (auth database)
DATABASE_URL_AUTH=postgresql+psycopg2://USER:PASSWORD@HOST:5432/punimtag_auth
# JWT / admin bootstrap (change these!)
SECRET_KEY=change-me
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-me
# Photo uploads storage
PHOTO_STORAGE_DIR=/opt/punimtag/data/uploads
# Redis (background jobs)
REDIS_URL=redis://127.0.0.1:6379/0
```
Notes:
- The backend **auto-creates tables** on first run if they are missing.
- The backend will also attempt to create the databases **if** the configured Postgres user has
privileges (otherwise create the DBs manually).
### 2.2 Admin env: `/opt/punimtag/admin-frontend/.env`
1. Copy and rename:
```bash
cd /opt/punimtag/admin-frontend
cp .env_example .env
```
2. Edit `.env`:
```bash
VITE_API_URL=http://YOUR_SERVER_IP_OR_DOMAIN:8000
```
### 2.3 Viewer env: `/opt/punimtag/viewer-frontend/.env`
1. Copy and rename:
```bash
cd /opt/punimtag/viewer-frontend
cp .env_example .env
```
2. Edit `.env`:
```bash
# Main DB (same as backend, but Prisma URL format)
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/punimtag
# Auth DB (same as backend, but Prisma URL format)
DATABASE_URL_AUTH=postgresql://USER:PASSWORD@HOST:5432/punimtag_auth
# Optional write-capable DB user (falls back to DATABASE_URL if not set)
# DATABASE_URL_WRITE=postgresql://USER:PASSWORD@HOST:5432/punimtag
# NextAuth
NEXTAUTH_URL=http://YOUR_SERVER_IP_OR_DOMAIN:3001
NEXTAUTH_SECRET=change-me
AUTH_URL=http://YOUR_SERVER_IP_OR_DOMAIN:3001
```
---
## Step 3 — Install dependencies
From the repo root:
```bash
cd /opt/punimtag
# Backend venv
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
# Frontends
cd admin-frontend
npm ci
cd ../viewer-frontend
npm ci
```
---
## Step 4 — Initialize the viewer Prisma clients
The viewer uses Prisma clients for both DBs.
```bash
cd /opt/punimtag/viewer-frontend
npm run prisma:generate:all
```
---
## Step 5 — Create the auth DB tables + admin user
The auth DB schema is set up by the viewer scripts.
```bash
cd /opt/punimtag/viewer-frontend
# Creates required auth tables / columns (idempotent)
npx tsx scripts/setup-auth.ts
# Ensures an admin user exists (idempotent)
npx tsx scripts/fix-admin-user.ts
```
---
## Step 6 — Start the services (PM2)
This repo includes a PM2 config at `ecosystem.config.js`.
Verify the paths/ports match your server, then:
```bash
cd /opt/punimtag
pm2 start ecosystem.config.js
pm2 save
```
Optional (auto-start on reboot):
```bash
pm2 startup
```
---
## Step 7 — First-run DB initialization (automatic)
On first startup, the backend will connect to Postgres and create missing tables automatically.
To confirm:
```bash
curl -sS http://127.0.0.1:8000/api/v1/health
```
Viewer health check (verifies DB permissions):
```bash
curl -sS http://127.0.0.1:3001/api/health
```
---
## Step 8 — Open the apps
- **Admin**: `http://YOUR_SERVER:3000`
- **Viewer**: `http://YOUR_SERVER:3001`
- **API docs**: `http://YOUR_SERVER:8000/docs`
---
## Common fixes
### Viewer `/api/health` says permission denied
Run the provided grant script on the DB server (as a privileged Postgres user):
- `viewer-frontend/grant_readonly_permissions.sql`
### Logs
```bash
pm2 status
pm2 logs punimtag-api --lines 200
pm2 logs punimtag-viewer --lines 200
pm2 logs punimtag-admin --lines 200
pm2 logs punimtag-worker --lines 200
```

128
scripts/deploy_from_scratch.sh Executable file
View File

@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
echo "== PunimTag deploy (from scratch) =="
echo "Project root: ${PROJECT_ROOT}"
echo ""
if [[ "$(id -u)" -eq 0 ]]; then
echo "❌ Do not run as root. Run as a normal user with sudo."
exit 1
fi
command_exists() {
command -v "$1" >/dev/null 2>&1
}
ensure_file_from_example() {
local example_path="$1"
local target_path="$2"
if [[ -f "${target_path}" ]]; then
echo "✅ Found ${target_path}"
return 0
fi
if [[ ! -f "${example_path}" ]]; then
echo "❌ Missing ${example_path}"
exit 1
fi
cp "${example_path}" "${target_path}"
echo "✅ Created ${target_path} from ${example_path}"
}
echo "== 1) Install system dependencies (Ubuntu/Debian) =="
if command_exists apt-get; then
sudo apt-get update
sudo apt-get install -y \
python3 python3-venv python3-pip \
postgresql-client \
redis-server \
nodejs npm
else
echo "❌ This script currently supports Ubuntu/Debian (apt-get)."
echo " Install dependencies manually, then re-run this script."
exit 1
fi
echo ""
echo "== 2) Ensure Redis is running =="
sudo systemctl enable --now redis-server || true
if command_exists redis-cli; then
if ! redis-cli ping >/dev/null 2>&1; then
echo "❌ Redis is not reachable on localhost:6379"
echo " Fix Redis (service, firewall, config) and retry."
exit 1
fi
echo "✅ Redis OK (redis-cli ping)"
else
echo "❌ redis-cli not found after install"
exit 1
fi
echo ""
echo "== 3) Ensure env files exist (copied from *_example) =="
ensure_file_from_example "${PROJECT_ROOT}/.env_example" "${PROJECT_ROOT}/.env"
ensure_file_from_example "${PROJECT_ROOT}/admin-frontend/.env_example" \
"${PROJECT_ROOT}/admin-frontend/.env"
ensure_file_from_example "${PROJECT_ROOT}/viewer-frontend/.env_example" \
"${PROJECT_ROOT}/viewer-frontend/.env"
echo ""
echo "⚠️ IMPORTANT: Edit these files NOW before continuing:"
echo " - ${PROJECT_ROOT}/.env"
echo " - ${PROJECT_ROOT}/admin-frontend/.env"
echo " - ${PROJECT_ROOT}/viewer-frontend/.env"
echo ""
echo "Press Enter once they are updated..."
read -r
echo ""
echo "== 4) Backend Python venv + deps =="
cd "${PROJECT_ROOT}"
python3 -m venv venv
./venv/bin/pip install --upgrade pip
./venv/bin/pip install -r requirements.txt
echo "✅ Backend dependencies installed"
echo ""
echo "== 5) Admin frontend deps =="
cd "${PROJECT_ROOT}/admin-frontend"
npm ci
echo "✅ Admin dependencies installed"
echo ""
echo "== 6) Viewer frontend deps + Prisma clients =="
cd "${PROJECT_ROOT}/viewer-frontend"
npm ci
npm run prisma:generate:all
echo "✅ Viewer dependencies installed and Prisma clients generated"
echo ""
echo "== 7) Auth DB setup scripts (viewer) =="
cd "${PROJECT_ROOT}/viewer-frontend"
npx tsx scripts/setup-auth.ts
npx tsx scripts/fix-admin-user.ts
echo "✅ Auth DB setup done"
echo ""
echo "== 8) Start services (PM2) =="
if ! command_exists pm2; then
echo "Installing PM2..."
sudo npm i -g pm2
fi
cd "${PROJECT_ROOT}"
pm2 start ecosystem.config.js
pm2 save
echo ""
echo "✅ Done."
echo "Admin: http://<server>:3000"
echo "Viewer: http://<server>:3001"
echo "API: http://<server>:8000/docs"

View File

@ -0,0 +1,15 @@
# Viewer frontend env (copy to ".env" and edit values)
# Prisma DB URLs (note: no "+psycopg2" here)
DATABASE_URL=postgresql://punimtag:CHANGE_ME@127.0.0.1:5432/punimtag
DATABASE_URL_AUTH=postgresql://punimtag_auth:CHANGE_ME@127.0.0.1:5432/punimtag_auth
# NextAuth
NEXTAUTH_URL=http://127.0.0.1:3001
NEXTAUTH_SECRET=CHANGE_ME_TO_A_LONG_RANDOM_STRING
AUTH_URL=http://127.0.0.1:3001
RESEND_API_KEY=CHANGE_ME_secret-key
RESEND_FROM_EMAIL="onboarding@resend.dev"
UPLOAD_DIR="/mnt/db-server-uploads/pending-photos"