Skip to content

docker-compose local startup #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 30, 2025
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
5 changes: 4 additions & 1 deletion .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ jobs:
run: |
docker --version
docker info
- run: ./scripts/start_local_db.sh
- name: Start local database with environment
run: |
cp .env.example .env.local
docker compose up -d db
- name: setup binstall
uses: taiki-e/install-action@cargo-binstall
- name: Install forc for tests
Expand Down
53 changes: 42 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ export PATH="${HOME}/.cargo/bin:${PATH}"

You will also need to install [Node.js](https://nodejs.org/en/learn/getting-started/how-to-install-nodejs).

To run the Postgres database locally, you will need [Docker](https://docs.docker.com/engine/install/).
To run the application locally, you will need [Docker](https://docs.docker.com/engine/install/) with Docker Compose.

To connect to the database, you will need the [Diesel CLI](https://diesel.rs/guides/getting-started).
To connect to the database for development, you may optionally install the [Diesel CLI](https://diesel.rs/guides/getting-started).

Diesel is the Rust ORM used to create and run database migrations. It requires a separate C library called `libpq` to be installed as well.

Expand Down Expand Up @@ -75,29 +75,59 @@ cargo run --bin forc.pub

### Running the `forc.pub` server

Before starting the server, the local database must be up and running.
The easiest way to run the complete application stack locally is using Docker Compose, which will start the database, backend server, and pgAdmin interface.

First, set up the environment by creating a `.env.local` file with your configuration. You'll need to add your Pinata test gateway details and Github App env (if testing github login functionality).

Now start all services with:

```sh
./scripts/start_local_db.sh
./scripts/start-local-server.sh
```

Next, set up the environment by copying `.env.example` to `.env.local`, and modifying `.env.local` with your Pinata test gateway details and Github App env (if testing github login functionality).
This will start:
- **PostgreSQL database** on port `${POSTGRES_PORT:-5432}`
- **Backend server** on port `8080`
- **pgAdmin** (database admin UI) on port `${PGADMIN_PORT:-5050}`

You can access:
- Backend API: http://localhost:8080
- pgAdmin interface: http://localhost:5050

Now we can run the server with:
**Database Access**: When connecting to the database server through pgAdmin, use password in `.env.local` (default: `localpw`).

To force rebuild the application image:

```sh
cargo run
./scripts/start-local-server.sh -f
```

Alternatively, the server can be run locally with Docker, as it is in the deployed environment.
To view logs:

```sh
./scripts/start_local_server.sh
docker compose logs -f
```

To stop all services:

# Force the server image to be rebuilt
./scripts/start_local_server.sh -f
```sh
docker compose down
```

### Alternative: Running components separately

If you prefer to run components separately for development:

1. Start just the database and pgAdmin:
```sh
docker compose up -d db pgadmin
```

2. Run the backend server locally:
```sh
cargo run
```

### Manually trigger the APIs

You can manually trigger the APIs with curl, for example:
Expand All @@ -115,6 +145,7 @@ The frontend requires npm and node to be installed.
```sh
cd app
npm i
npm run build
npm start
```

Expand Down
73 changes: 73 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
services:
db:
image: postgres:latest
container_name: forc-pub-db
env_file:
- .env.local
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB_NAME}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- forc-pub-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB_NAME}"]
interval: 10s
timeout: 5s
retries: 5

app:
build:
context: .
dockerfile: deployment/Dockerfile
container_name: forc-pub
env_file:
- .env.local
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_URI: db
POSTGRES_DB_NAME: ${POSTGRES_DB_NAME}
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
networks:
- forc-pub-net

pgadmin:
image: dpage/pgadmin4:latest
container_name: forc-pub-pgadmin
env_file:
- .env.local
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL:-admin@forc.pub}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin}
PGADMIN_CONFIG_SERVER_MODE: 'False'
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False'
PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION: 'False'
PGADMIN_CONFIG_WTF_CSRF_ENABLED: 'False'
PGADMIN_SERVER_JSON_FILE: '/pgadmin4/servers.json'
ports:
- "${PGADMIN_PORT:-5050}:80"
volumes:
- pgadmin_data:/var/lib/pgadmin
- ./scripts/pgadmin-servers.json:/pgadmin4/servers.json:ro
depends_on:
db:
condition: service_healthy
networks:
- forc-pub-net

volumes:
postgres_data:
pgadmin_data:

networks:
forc-pub-net:
driver: bridge
18 changes: 18 additions & 0 deletions scripts/pgadmin-servers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"Servers": {
"1": {
"Name": "forc.pub Database",
"Group": "Servers",
"Host": "db",
"Port": 5432,
"MaintenanceDB": "forc_pub",
"Username": "postgres",
"Password": "localpw",
"SSLMode": "prefer",
"Timeout": 10,
"UseSSHTunnel": 0,
"TunnelPort": "22",
"TunnelAuthentication": 0
}
}
}
109 changes: 109 additions & 0 deletions scripts/start-local-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/bin/bash

# Script best practices
set -euo pipefail # Exit on error, undefined vars, pipe failures
IFS=$'\n\t' # Secure Internal Field Separator

# Color codes for logging
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly GRAY='\033[0;90m'
readonly LIGHT_GRAY='\033[0;37m'
readonly CYAN='\033[0;36m'
readonly WHITE='\033[1;37m'
readonly NC='\033[0m' # No Color

# Logging functions
log_info() {
printf "${BLUE}[INFO]${NC} %s\n" "$1" >&2
}

log_success() {
printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" >&2
}

log_warning() {
printf "${YELLOW}[WARNING]${NC} %s\n" "$1" >&2
}

log_error() {
printf "${RED}[ERROR]${NC} %s\n" "$1" >&2
}

log_debug() {
if [[ "${DEBUG:-}" == "true" ]]; then
printf "${GRAY}[DEBUG]${NC} ${LIGHT_GRAY}%s${NC}\n" "$1" >&2
fi
}

# Error handler
error_handler() {
local line_number=$1
log_error "Script failed at line ${line_number}"
exit 1
}

# Set up error handling
trap 'error_handler ${LINENO}' ERR

# Initialize variables
FORCE_REBUILD=false
DEBUG=false

# Parse arguments first
while getopts "fhd" opt; do
case ${opt} in
f) FORCE_REBUILD=true ;;
h) echo "Usage: $0 [-f] [-h] [-d]"; echo " -f: Force rebuild"; echo " -h: Help"; echo " -d: Debug"; exit 0 ;;
d) DEBUG=true ;;
*) log_error "Invalid option: -$OPTARG"; exit 1 ;;
esac
done

# Check if Docker and Docker Compose are installed
if ! command -v docker &> /dev/null; then
log_error "Docker is not installed"
exit 1
fi

if ! docker compose version &> /dev/null 2>&1; then
log_error "Docker Compose is not available. Please ensure you have Docker with Compose plugin installed."
exit 1
fi

COMPOSE_CMD=("docker" "compose")
log_debug "Using Docker Compose"

# Load environment variables
if [[ -f .env.local ]]; then
log_info "Loading environment from .env.local"
source .env.local
else
log_warning ".env.local not found. Create one with required variables"
fi



# Build if needed
if [[ "$FORCE_REBUILD" == "true" ]]; then
log_info "Force rebuilding application image..."
"${COMPOSE_CMD[@]}" build --no-cache app
log_success "Application image rebuilt"
fi

# Start services
log_info "Starting services with Docker Compose..."
"${COMPOSE_CMD[@]}" up -d

log_success "Services started!"
log_info "Database: PostgreSQL on port ${POSTGRES_PORT:-5432}"
log_info "Application: forc.pub on port 8080"
log_info "pgAdmin: Database admin UI on port ${PGADMIN_PORT:-5050}"
printf "\n${CYAN}Access URLs:${NC}\n"
printf " backend: http://localhost:8080\n"
printf " pgAdmin: http://localhost:${PGADMIN_PORT:-5050}\n"
printf "\n${CYAN}Commands:${NC}\n"
printf " View logs: docker compose logs -f\n"
printf " Stop services: docker compose down\n"
36 changes: 0 additions & 36 deletions scripts/start_local_db.sh

This file was deleted.

Loading
Loading