Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
EXPO_PUBLIC_USE_LOCAL_API=1
EXPO_PUBLIC_LOCAL_API_URL=http://192.168.76.129:8080
EXPO_PUBLIC_API_URL=https://devbits.ddns.net
EXPO_PUBLIC_API_URL=https://devbits.app
EXPO_PUBLIC_LOCAL_API_PORT=8080
POSTGRES_DB=devbits_dev
POSTGRES_USER=devbits_dev
POSTGRES_PASSWORD=devbits_dev_password
POSTGRES_PASSWORD=devbits_dev_password
22 changes: 13 additions & 9 deletions Bash-Scripts/run-dev.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/bin/env bash

# Script: run-dev.sh
# Does: Boots local dev DB + local backend (isolated compose project), then launches frontend in local mode.
# Use: ./run-dev.sh [--clear]
# Does: Boots local dev DB + local backend (isolated compose project) only.
# Use: ./run-dev.sh
# DB: devbits_dev (user/pass: devbits_dev/devbits_dev_password) in compose project devbits-dev-local.
# Ports: backend default :8080, DB default :5433 (DEVBITS_BACKEND_PORT / DEVBITS_DB_PORT override).
# Modes: Frontend=ON(local API) | Backend=ON(local Docker) | Live stack untouched | Test DB untouched.
# Modes: Frontend=OFF | Backend=ON(local Docker) | Live stack untouched | Test DB untouched.

set -euo pipefail

Expand All @@ -14,9 +14,9 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BACKEND_DIR="$ROOT/backend"
COMPOSE_PROJECT="devbits-dev-local"

CLEAR_FRONTEND=""
if [[ "${1:-}" == "--clear" ]]; then
CLEAR_FRONTEND="--clear"
if [[ "${EUID}" -eq 0 ]]; then
echo "Warning: Running as root is not recommended for Expo local mode."
echo "Use ./run-dev.sh (without sudo) so LAN IP detection and device connectivity work reliably."
fi

if ! command -v docker >/dev/null 2>&1; then
Expand Down Expand Up @@ -109,6 +109,10 @@ for i in $(seq 1 60); do
sleep 1
done

echo "Launching frontend in local backend mode..."
cd "$ROOT"
EXPO_PUBLIC_LOCAL_API_PORT="$DEVBITS_BACKEND_PORT" "$SCRIPT_DIR/run-front.sh" --local $CLEAR_FRONTEND
echo
echo "Local backend stack is ready."
echo "Backend health: http://localhost:${DEVBITS_BACKEND_PORT}/health"
echo "To launch frontend against local backend, run:"
echo " EXPO_PUBLIC_LOCAL_API_PORT=${DEVBITS_BACKEND_PORT} $SCRIPT_DIR/run-front.sh --local"
echo "To launch frontend against live backend, run:"
echo " $SCRIPT_DIR/run-front.sh --live"
59 changes: 49 additions & 10 deletions Bash-Scripts/run-front.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash

# Script: run-front.sh
# Does: Starts Expo frontend and lets you choose backend target (Production or Local).
# Use: ./run-front.sh [--local|--production] [--clear] [--dev-client]
# Does: Starts Expo frontend and lets you choose backend target (Local or Live).
# Use: ./run-front.sh [--local|--live|--production] [--clear] [--dev-client]
# DB: None (frontend only).
# Ports: Metro uses LAN IP; local API defaults to :8080 (EXPO_PUBLIC_LOCAL_API_PORT overrides).
# Modes: Frontend=ON | Backend=Production URL or Local URL | Live stack untouched | Dev/Test DB untouched.
Expand Down Expand Up @@ -31,26 +31,53 @@ for arg in "$@"; do
--production)
MODE="production"
;;
--live)
MODE="production"
;;
*)
echo "Unknown argument: $arg"
echo "Usage: ./run-front.sh [--local|--production] [--clear] [--dev-client]"
echo "Usage: ./run-front.sh [--local|--live|--production] [--clear] [--dev-client]"
exit 1
;;
esac
done

detect_lan_ip() {
hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.' | head -n1
local from_route=""
local iface=""

if command -v ip >/dev/null 2>&1; then
from_route="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i=="src") {print $(i+1); exit}}')"
if [[ "$from_route" =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\. ]]; then
echo "$from_route"
return 0
fi

iface="$(ip route 2>/dev/null | awk '/^default/ {print $5; exit}')"
if [[ -n "$iface" ]]; then
ip -4 addr show dev "$iface" scope global 2>/dev/null |
awk '/inet / {print $2}' |
cut -d/ -f1 |
grep -E '^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.' |
head -n1
return 0
fi
fi

hostname -I 2>/dev/null |
tr ' ' '\n' |
grep -E '^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.' |
head -n1
}

LAN_IP="$(detect_lan_ip || true)"
if [[ -z "$LAN_IP" ]]; then
LAN_IP="127.0.0.1"
echo "Warning: Could not detect private LAN IPv4. Falling back to 127.0.0.1."
echo "Warning: Could not detect private LAN IPv4."
fi

if [[ -z "$MODE" ]]; then
echo "Select backend: 1) Production (devbits.ddns.net) 2) Local (LAN IP:8080)"
echo "Select backend: 1) Live (devbits.app) 2) Local (LAN IP:8080)"
read -r -p "Choose [1/2]: " selection
case "$selection" in
1) MODE="production" ;;
Expand All @@ -69,18 +96,30 @@ else
unset REACT_NATIVE_PACKAGER_HOSTNAME || true
unset EXPO_PACKAGER_HOSTNAME || true
fi
export EXPO_PUBLIC_API_URL="https://devbits.ddns.net"
export EXPO_PUBLIC_API_FALLBACK_URL="https://devbits.ddns.net"
export EXPO_PUBLIC_API_URL="https://devbits.app"
export EXPO_PUBLIC_API_FALLBACK_URL="https://devbits.app"

if [[ "$MODE" == "local" ]]; then
LOCAL_API_PORT="${EXPO_PUBLIC_LOCAL_API_PORT:-8080}"

if [[ "$LAN_IP" == "127.0.0.1" && "${DEVBITS_ALLOW_LOOPBACK_LOCAL_API:-0}" != "1" ]]; then
echo "Error: Local mode resolved loopback (127.0.0.1), which will fail on physical devices."
echo "Fix one of the following and try again:"
echo " 1) Run without sudo so network detection can read your user network context."
echo " 2) Set EXPO_PUBLIC_LOCAL_API_URL manually, e.g. http://192.168.x.y:${LOCAL_API_PORT}."
echo " 3) If using only simulator/emulator intentionally, set DEVBITS_ALLOW_LOOPBACK_LOCAL_API=1."
exit 1
fi

export EXPO_PUBLIC_USE_LOCAL_API=1
export EXPO_PUBLIC_LOCAL_API_URL="http://${LAN_IP}:${LOCAL_API_PORT}"
if [[ -z "${EXPO_PUBLIC_LOCAL_API_URL:-}" ]]; then
export EXPO_PUBLIC_LOCAL_API_URL="http://${LAN_IP}:${LOCAL_API_PORT}"
fi
echo "Using local backend: $EXPO_PUBLIC_LOCAL_API_URL"
else
export EXPO_PUBLIC_USE_LOCAL_API=0
unset EXPO_PUBLIC_LOCAL_API_URL || true
echo "Using production backend: https://devbits.ddns.net"
echo "Using live backend: https://devbits.app"
fi

cd "$FRONTEND_DIR"
Expand Down
38 changes: 38 additions & 0 deletions Bash-Scripts/sync-static.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Script: sync-static.sh
# Does: Copies compliance/static files from backend/api/static (source of truth) to frontend/public.
# Run this whenever the backend static files change to keep the frontend web build in sync.
# Use: ./sync-static.sh

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

SRC="$ROOT/backend/api/static"
DST="$ROOT/frontend/public"

FILES=(
apple-app-site-association
privacy-policy.html
account-deletion.html
)

for file in "${FILES[@]}"; do
src_path="$SRC/$file"
dst_path="$DST/$file"

if [[ ! -f "$src_path" ]]; then
echo "WARNING: Source file not found, skipping: $src_path"
continue
fi

if cmp -s "$src_path" "$dst_path" 2>/dev/null; then
echo "Up to date: $file"
else
cp "$src_path" "$dst_path"
echo "Synced: $file"
fi
done

echo "Sync complete."
48 changes: 38 additions & 10 deletions INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,50 @@

## Backend

> **Live/Deployed Stack**
> **AWS EC2 (Amazon Linux) Native Deploy**
>
> ```bash
> cd /path/to/DevBits/backend
> docker compose up -d
> docker compose logs -f db
> # On your EC2 instance
> sudo dnf update -y
> sudo dnf install -y git tar
> ```

> Rebuild and restart:
>
> Install Go 1.24.x (required by `backend/go.mod`):
>
> ```bash
> docker compose up -d --build
> curl -LO https://go.dev/dl/go1.24.2.linux-amd64.tar.gz
> sudo rm -rf /usr/local/go
> sudo tar -C /usr/local -xzf go1.24.2.linux-amd64.tar.gz
> echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
> source ~/.bashrc
> go version
> ```

>
> Clone and deploy:
>
> ```bash
> sudo mkdir -p /opt/devbits
> sudo chown -R "$USER":"$USER" /opt/devbits
> cd /opt/devbits
> git clone https://github.com/devbits-go/DevBits.git .
> git checkout aws-ready-main
> cd backend
> cp .env.example .env
> # edit .env with production values (DATABASE_URL, secrets, CORS, etc.)
> ./scripts/deploy-aws-native.sh
> ```
>
> Verify service:
>
> ```bash
> sudo systemctl status devbits-api --no-pager
> sudo journalctl -u devbits-api -n 120 --no-pager
> curl -i http://127.0.0.1:8080/health
> ```
>
> [!TIP]
> Check `backend/scripts/README.md` for database operations.
> AWS deploy uses native `systemd` (no Docker or nginx required in production).
> See `backend/docs/AWS_TRANSFER_NO_NGINX.md` for full runbook.

## Build

Expand Down Expand Up @@ -58,4 +86,4 @@

---

`Workflow: Backend Setup → EAS Build → EAS Submit`
`Workflow: AWS Backend Deploy → EAS Build → EAS Submit`
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ param(

$ErrorActionPreference = "Stop"

if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
exit
}

Write-Host "Creating deployment database backup..." -ForegroundColor Yellow

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Expand All @@ -21,23 +15,28 @@ try {
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null

$envFile = Join-Path $root ".env"
$dbUser = "devbits"
$dbName = "devbits"
if (Test-Path $envFile) {
$envRaw = Get-Content -Path $envFile -Raw
if ($envRaw -match "(?m)^POSTGRES_USER=(.+)$") {
$dbUser = $Matches[1].Trim()
}
if ($envRaw -match "(?m)^POSTGRES_DB=(.+)$") {
$dbName = $Matches[1].Trim()
}
if (-not (Test-Path $envFile)) {
throw "Missing $envFile. Create it from backend/.env.example and set DATABASE_URL."
}

$envRaw = Get-Content -Path $envFile -Raw
$dbUrl = $null
if ($envRaw -match "(?m)^DATABASE_URL=(.+)$") {
$dbUrl = $Matches[1].Trim()
}
if ([string]::IsNullOrWhiteSpace($dbUrl)) {
throw "Missing DATABASE_URL in $envFile"
}

if (-not (Get-Command pg_dump -ErrorAction SilentlyContinue)) {
throw "pg_dump not found in PATH. Install PostgreSQL client tools first."
}

$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$dbBackupFileName = "devbits-db-$timestamp.sql"
$dbBackupFile = Join-Path $backupPath $dbBackupFileName
docker compose exec -T db pg_dump -U $dbUser -d $dbName --no-owner --no-privileges | Out-File -FilePath $dbBackupFile -Encoding utf8

pg_dump $dbUrl --no-owner --no-privileges | Out-File -FilePath $dbBackupFile -Encoding utf8

if (-not (Test-Path $dbBackupFile)) {
throw "Database backup file was not created."
Expand Down Expand Up @@ -69,20 +68,11 @@ finally {
Pop-Location
}

$liveBackendState = "unavailable"
try {
$statusOutput = docker compose -f (Join-Path $root "docker-compose.yml") ps backend 2>$null
if ($LASTEXITCODE -eq 0) {
$liveBackendState = if (($statusOutput | Out-String) -match "Up") { "running" } else { "not running" }
}
}
catch {}

Write-Host ""
Write-Host "===== Summary =====" -ForegroundColor Cyan
Write-Host "Action: Deployment backup created"
Write-Host "Updated: Latest DB + uploads backup files retained"
Write-Host "Live backend: $liveBackendState"
Write-Host "Database backup target: DATABASE_URL"

if (-not $NoPause -and [Environment]::UserInteractive -and $Host.Name -eq "ConsoleHost") {
Read-Host "Press Enter to close"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,12 @@ Write-Host "Task removed." -ForegroundColor Green

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$root = Resolve-Path (Join-Path $scriptDir "..")
$liveBackendState = "unavailable"
try {
$statusOutput = docker compose -f (Join-Path $root "docker-compose.yml") ps backend 2>$null
if ($LASTEXITCODE -eq 0) {
$liveBackendState = if (($statusOutput | Out-String) -match "Up") { "running" } else { "not running" }
}
}
catch {}

Write-Host ""
Write-Host "===== Summary =====" -ForegroundColor Cyan
Write-Host "Action: Daily backup task removed"
Write-Host "Updated: Windows scheduled task '$TaskName' deleted"
Write-Host "Live backend: $liveBackendState"
Write-Host "Execution target removed: backup-deployment-db.ps1"

if (-not $NoPause -and [Environment]::UserInteractive -and $Host.Name -eq "ConsoleHost") {
Read-Host "Press Enter to close"
Expand Down
Loading
Loading