From f224a160e353e2c7aa5079824b8757c6dbcbb80d Mon Sep 17 00:00:00 2001 From: tanyar09 Date: Wed, 28 Jan 2026 19:20:35 +0000 Subject: [PATCH] docs: add from-scratch deploy script and env templates --- .env_example | 20 +++ admin-frontend/.env_example | 6 + docs/DEPLOY_FROM_SCRATCH.md | 276 +++++++++++++++++++++++++++++++++ scripts/deploy_from_scratch.sh | 128 +++++++++++++++ viewer-frontend/.env_example | 15 ++ 5 files changed, 445 insertions(+) create mode 100644 .env_example create mode 100644 admin-frontend/.env_example create mode 100644 docs/DEPLOY_FROM_SCRATCH.md create mode 100755 scripts/deploy_from_scratch.sh create mode 100644 viewer-frontend/.env_example diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..e276393 --- /dev/null +++ b/.env_example @@ -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 + + diff --git a/admin-frontend/.env_example b/admin-frontend/.env_example new file mode 100644 index 0000000..58c6cb3 --- /dev/null +++ b/admin-frontend/.env_example @@ -0,0 +1,6 @@ +# Admin frontend env (copy to ".env" ) + +# Backend API base URL (must be reachable from the browser) +VITE_API_URL= + + diff --git a/docs/DEPLOY_FROM_SCRATCH.md b/docs/DEPLOY_FROM_SCRATCH.md new file mode 100644 index 0000000..32a0e2e --- /dev/null +++ b/docs/DEPLOY_FROM_SCRATCH.md @@ -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 +``` + + diff --git a/scripts/deploy_from_scratch.sh b/scripts/deploy_from_scratch.sh new file mode 100755 index 0000000..8f46b69 --- /dev/null +++ b/scripts/deploy_from_scratch.sh @@ -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://:3000" +echo "Viewer: http://:3001" +echo "API: http://:8000/docs" + + diff --git a/viewer-frontend/.env_example b/viewer-frontend/.env_example new file mode 100644 index 0000000..73e83a3 --- /dev/null +++ b/viewer-frontend/.env_example @@ -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" -- 2.49.1