Development Guide#
This guide provides instructions for setting up the development environment and running tests for the Showcase application.
Prerequisites#
- Docker installed and running
- Docker Compose (usually included with Docker Desktop)
- Rust 1.70+ with Cargo
- Git
PostgreSQL Development Setup#
The application supports both SQLite (default) and PostgreSQL storage backends. For integration testing with PostgreSQL, you'll need to run a PostgreSQL instance locally.
Option 1: Docker Compose (Recommended)#
Create a docker-compose.yml file in the project root:
version: '3.8'
services:
postgres:
image: postgres:17-alpine
container_name: showcase_postgres
environment:
POSTGRES_DB: showcase_test
POSTGRES_USER: showcase
POSTGRES_PASSWORD: showcase_dev_password
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
ports:
- "5433:5432" # Using 5433 to avoid conflicts with system PostgreSQL
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U showcase -d showcase_test"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
postgres_data:
Start the PostgreSQL container:
# Start PostgreSQL in background
docker-compose up -d postgres
# Check logs to ensure it's running properly
docker-compose logs postgres
# Stop when done
docker-compose down
Option 2: Docker Run Command#
If you prefer to use Docker directly without Docker Compose:
# Create a Docker network (optional, for better container management)
docker network create showcase-dev
# Run PostgreSQL 17 container
docker run -d \
--name showcase_postgres \
--network showcase-dev \
-e POSTGRES_DB=showcase_test \
-e POSTGRES_USER=showcase \
-e POSTGRES_PASSWORD=showcase_dev_password \
-e POSTGRES_INITDB_ARGS="--encoding=UTF8 --locale=C" \
-p 5433:5432 \
-v showcase_postgres_data:/var/lib/postgresql/data \
postgres:17-alpine
# Verify the container is running
docker ps | grep showcase_postgres
# Check logs
docker logs showcase_postgres
# Stop and remove container when done
docker stop showcase_postgres
docker rm showcase_postgres
Database Initialization#
Create an optional init-db.sql file for additional database setup:
-- init-db.sql
-- Additional database setup if needed
-- Create extensions that might be useful for testing
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- Set timezone
SET timezone TO 'UTC';
-- Create additional test database for parallel testing
CREATE DATABASE showcase_test_parallel;
GRANT ALL PRIVILEGES ON DATABASE showcase_test_parallel TO showcase;
MinIO Object Storage Development Setup#
The application supports S3-compatible object storage for badge images using MinIO. This is useful for testing S3 functionality locally and for production deployments that use object storage instead of local file storage.
Setting up MinIO with Docker Compose#
Add MinIO service to your docker-compose.yml:
version: '3.8'
services:
postgres:
image: postgres:17-alpine
container_name: showcase_postgres
environment:
POSTGRES_DB: showcase_test
POSTGRES_USER: showcase
POSTGRES_PASSWORD: showcase_dev_password
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
ports:
- "5433:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U showcase -d showcase_test"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: showcase_minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: showcase_minio
MINIO_ROOT_PASSWORD: showcase_dev_secret
ports:
- "9000:9000" # MinIO API
- "9001:9001" # MinIO Console
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
restart: unless-stopped
volumes:
postgres_data:
minio_data:
Starting MinIO#
# Start MinIO and PostgreSQL
docker-compose up -d
# Check if MinIO is running
docker-compose logs minio
# Access MinIO Console at http://localhost:9001
# Username: showcase_minio
# Password: showcase_dev_secret
MinIO Bucket Setup#
-
Via MinIO Console (Web UI):
- Open http://localhost:9001 in your browser
- Login with
showcase_minio/showcase_dev_secret - Click "Buckets" → "Create Bucket"
- Create a bucket named
showcase-badges - Set bucket policy to allow public read access (for testing)
-
Via MinIO Client (mc):
# Install MinIO client curl https://dl.min.io/client/mc/release/linux-amd64/mc \ --create-dirs -o $HOME/minio-binaries/mc chmod +x $HOME/minio-binaries/mc export PATH=$PATH:$HOME/minio-binaries/ # Configure MinIO client mc alias set local http://localhost:9000 showcase_minio showcase_dev_secret # Create bucket mc mb local/showcase-badges # Set bucket policy for public read (optional, for testing) mc policy set download local/showcase-badges # List buckets mc ls local -
Via Docker:
# Create bucket using MinIO container docker-compose exec minio mc mb /data/showcase-badges # Set bucket policy docker-compose exec minio mc policy set download /data/showcase-badges
Alternative MinIO Setup (Docker Run)#
If you prefer not to use Docker Compose:
# Run MinIO container
docker run -d \
--name showcase_minio \
-p 9000:9000 \
-p 9001:9001 \
-e MINIO_ROOT_USER=showcase_minio \
-e MINIO_ROOT_PASSWORD=showcase_dev_secret \
-v showcase_minio_data:/data \
minio/minio:latest server /data --console-address ":9001"
# Verify MinIO is running
docker logs showcase_minio
# Create bucket (after MinIO is started)
docker exec showcase_minio mc mb /data/showcase-badges
# Stop MinIO when done
docker stop showcase_minio
docker rm showcase_minio
Environment Configuration#
For PostgreSQL Integration Tests#
Create a .env.test file for test-specific environment variables:
# .env.test - PostgreSQL test configuration
DATABASE_URL=postgresql://showcase:showcase_dev_password@localhost:5433/showcase_test
EXTERNAL_BASE=http://localhost:8080
BADGE_ISSUERS=did:plc:test1;did:plc:test2
HTTP_PORT=8080
BADGE_IMAGE_STORAGE=./test_badges
PLC_HOSTNAME=plc.directory
HTTP_CLIENT_TIMEOUT=10s
RUST_LOG=showcase=debug,info
For SQLite Development (Default)#
Create a .env.dev file for SQLite development:
# .env.dev - SQLite development configuration
DATABASE_URL=sqlite://showcase_dev.db
EXTERNAL_BASE=http://localhost:8080
BADGE_ISSUERS=did:plc:test1;did:plc:test2
HTTP_PORT=8080
BADGE_IMAGE_STORAGE=./badges
PLC_HOSTNAME=plc.directory
HTTP_CLIENT_TIMEOUT=10s
RUST_LOG=showcase=info,debug
For S3/MinIO Object Storage#
Create environment files for S3 object storage:
For MinIO Local Development (.env.minio):
# .env.minio - MinIO development configuration
DATABASE_URL=sqlite://showcase_dev.db
EXTERNAL_BASE=http://localhost:8080
BADGE_ISSUERS=did:plc:test1;did:plc:test2
HTTP_PORT=8080
BADGE_IMAGE_STORAGE=s3://showcase_minio:showcase_dev_secret@localhost:9000/showcase-badges
PLC_HOSTNAME=plc.directory
HTTP_CLIENT_TIMEOUT=10s
RUST_LOG=showcase=info,debug
For AWS S3 Production (.env.s3):
# .env.s3 - AWS S3 configuration
DATABASE_URL=postgresql://username:password@hostname:5432/database
EXTERNAL_BASE=https://your-domain.com
BADGE_ISSUERS=did:plc:production1;did:plc:production2
HTTP_PORT=8080
BADGE_IMAGE_STORAGE=s3://access_key:secret_key@s3.amazonaws.com/your-bucket/badges
PLC_HOSTNAME=plc.directory
HTTP_CLIENT_TIMEOUT=10s
RUST_LOG=showcase=info,warn
S3 URL Format:
The BADGE_IMAGE_STORAGE environment variable supports the following format for S3-compatible storage:
s3://[access_key]:[secret_key]@[hostname]/[bucket][/optional_prefix]
Examples:
- MinIO:
s3://minio_user:minio_pass@localhost:9000/my-bucket/badges - AWS S3:
s3://AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY@s3.amazonaws.com/my-bucket - DigitalOcean Spaces:
s3://access_key:secret_key@nyc3.digitaloceanspaces.com/my-space/images
Running Tests#
Unit Tests (SQLite - Default)#
# Run all tests with SQLite (default)
cargo test
# Run specific test module
cargo test storage::tests
# Run tests with output
cargo test -- --nocapture
# Run tests in single thread (useful for database tests)
cargo test -- --test-threads=1
Integration Tests with PostgreSQL#
-
Start PostgreSQL container:
docker-compose up -d postgres # Wait for PostgreSQL to be ready docker-compose exec postgres pg_isready -U showcase -d showcase_test -
Set environment variables:
# Load PostgreSQL test environment export $(cat .env.test | xargs) # Or use direnv (if installed) echo "dotenv .env.test" > .envrc direnv allow -
Run tests with PostgreSQL:
# Run all tests against PostgreSQL cargo test # Run specific storage tests cargo test --lib storage # Run with verbose output RUST_LOG=debug cargo test -- --nocapture -
Clean up:
# Stop PostgreSQL container docker-compose down # Remove test data (optional) docker-compose down -v
S3/MinIO Integration Tests#
Test the S3 file storage functionality:
-
Start MinIO container:
docker-compose up -d minio # Wait for MinIO to be ready timeout 30s bash -c 'until curl -f http://localhost:9000/minio/health/live; do sleep 2; done' -
Create test bucket:
# Using MinIO client docker-compose exec minio mc mb /data/showcase-badges # Or via API (requires mc client installed) mc alias set local http://localhost:9000 showcase_minio showcase_dev_secret mc mb local/showcase-badges -
Set environment and run tests:
# Load MinIO test environment export $(cat .env.minio | xargs) # Build with S3 feature cargo build --features s3 # Run tests with S3 feature cargo test --features s3 # Run specific file storage tests cargo test --features s3 file_storage -
Clean up:
# Stop MinIO container docker-compose down # Remove MinIO data (optional) docker-compose down -v
Testing S3 Feature without MinIO#
If you want to test the S3 implementation without running MinIO:
# Build with S3 feature to check compilation
cargo build --features s3
# Run unit tests that don't require actual S3 connection
cargo test --features s3 test_s3_file_storage_object_key_generation
# Check that the feature flag works correctly
cargo test --features s3 --lib
Integration Test Scripts#
Create helper scripts for common test scenarios:
scripts/test-postgres.sh:
#!/bin/bash
set -e
echo "Starting PostgreSQL container..."
docker-compose up -d postgres
echo "Waiting for PostgreSQL to be ready..."
timeout 30s bash -c 'until docker-compose exec postgres pg_isready -U showcase -d showcase_test; do sleep 1; done'
echo "Loading test environment..."
export $(cat .env.test | xargs)
echo "Running tests with PostgreSQL..."
cargo test
echo "Cleaning up..."
docker-compose down
scripts/test-sqlite.sh:
#!/bin/bash
set -e
echo "Loading SQLite test environment..."
export $(cat .env.dev | xargs)
echo "Running tests with SQLite..."
cargo test
echo "Cleaning up test databases..."
rm -f showcase_dev.db showcase_test.db
scripts/test-minio.sh:
#!/bin/bash
set -e
echo "Starting MinIO container..."
docker-compose up -d minio
echo "Waiting for MinIO to be ready..."
timeout 60s bash -c 'until curl -f http://localhost:9000/minio/health/live; do sleep 2; done'
echo "Creating test bucket..."
docker-compose exec minio mc mb /data/showcase-badges || echo "Bucket may already exist"
echo "Loading MinIO test environment..."
export $(cat .env.minio | xargs)
echo "Building with S3 features..."
cargo build --features s3
echo "Running tests with S3 features..."
cargo test --features s3
echo "Cleaning up..."
docker-compose down
scripts/test-all.sh:
#!/bin/bash
set -e
echo "Running all test suites..."
echo "=== SQLite Tests ==="
./scripts/test-sqlite.sh
echo "=== PostgreSQL Tests ==="
./scripts/test-postgres.sh
echo "=== S3/MinIO Tests ==="
./scripts/test-minio.sh
echo "All tests completed successfully!"
Make scripts executable:
chmod +x scripts/test-postgres.sh scripts/test-sqlite.sh scripts/test-minio.sh scripts/test-all.sh
Development Workflow#
1. Setting up for Development#
# Clone the repository
git clone <repository-url>
cd showcase
# Install Rust dependencies
cargo build
# Start PostgreSQL for development
docker-compose up -d postgres
# Load environment variables
export $(cat .env.test | xargs)
# Run database migrations
cargo run --bin showcase migrate # If migration command exists
2. Running the Application Locally#
With SQLite (Default):
export $(cat .env.dev | xargs)
cargo run --bin showcase
With PostgreSQL:
# Ensure PostgreSQL is running
docker-compose up -d postgres
# Load PostgreSQL environment
export $(cat .env.test | xargs)
# Run the application
cargo run --bin showcase
With MinIO Object Storage:
# Ensure MinIO is running
docker-compose up -d minio
# Wait for MinIO to be ready
timeout 30s bash -c 'until curl -f http://localhost:9000/minio/health/live; do sleep 2; done'
# Create bucket if it doesn't exist
docker-compose exec minio mc mb /data/showcase-badges || true
# Load MinIO environment
export $(cat .env.minio | xargs)
# Run the application with S3 features
cargo run --features s3 --bin showcase
3. Database Management#
View PostgreSQL logs:
docker-compose logs postgres -f
Connect to PostgreSQL for debugging:
# Using psql in container
docker-compose exec postgres psql -U showcase -d showcase_test
# Or using psql from host (if installed)
psql postgresql://showcase:showcase_dev_password@localhost:5433/showcase_test
Reset PostgreSQL database:
# Stop and remove with volumes
docker-compose down -v
# Start fresh
docker-compose up -d postgres
View SQLite database:
# Install sqlite3 if needed
sqlite3 showcase_dev.db
# View tables
.tables
# View schema
.schema
Continuous Integration#
For CI environments, use these commands:
# CI script for PostgreSQL tests
docker run -d \
--name ci_postgres \
-e POSTGRES_DB=showcase_test \
-e POSTGRES_USER=showcase \
-e POSTGRES_PASSWORD=ci_password \
-p 5432:5432 \
postgres:17-alpine
# Wait for PostgreSQL
timeout 60s bash -c 'until pg_isready -h localhost -p 5432 -U showcase; do sleep 2; done'
# Set CI environment
export DATABASE_URL=postgresql://showcase:ci_password@localhost:5432/showcase_test
export BADGE_ISSUERS=did:plc:ci1;did:plc:ci2
export EXTERNAL_BASE=http://localhost:8080
# Run tests
cargo test --all-features
# Cleanup
docker stop ci_postgres
docker rm ci_postgres
Troubleshooting#
PostgreSQL Connection Issues#
-
Port conflicts:
# Check if port 5433 is in use lsof -i :5433 # Use different port in docker-compose.yml ports: - "5434:5432" -
Container not starting:
# Check Docker logs docker-compose logs postgres # Remove and recreate container docker-compose down -v docker-compose up -d postgres -
Permission issues:
# Fix Docker volume permissions (Linux) sudo chown -R $(id -u):$(id -g) postgres_data/
Test Failures#
-
Database schema issues:
# Drop and recreate test database docker-compose exec postgres psql -U showcase -c "DROP DATABASE IF EXISTS showcase_test;" docker-compose exec postgres psql -U showcase -c "CREATE DATABASE showcase_test;" -
Environment variable issues:
# Verify environment variables are loaded env | grep DATABASE_URL env | grep BADGE_ISSUERS -
Dependency issues:
# Clean and rebuild cargo clean cargo build
Performance Issues#
-
Slow PostgreSQL startup:
# Use smaller PostgreSQL image for faster startup # In docker-compose.yml, change to: image: postgres:17-alpine -
Test timeouts:
# Increase test timeout cargo test -- --timeout 60 # Run tests with single thread for database tests cargo test -- --test-threads=1
MinIO/S3 Issues#
-
MinIO container not starting:
# Check MinIO logs docker-compose logs minio # Remove and recreate container docker-compose down -v docker-compose up -d minio -
S3 connection issues:
# Verify MinIO is accessible curl http://localhost:9000/minio/health/live # Check MinIO console open http://localhost:9001 # Test bucket access docker-compose exec minio mc ls /data/ -
Bucket permission issues:
# Set bucket policy to public read (for testing) docker-compose exec minio mc policy set download /data/showcase-badges # List bucket contents docker-compose exec minio mc ls /data/showcase-badges -
S3 URL parsing errors:
# Verify environment variable format echo $BADGE_IMAGE_STORAGE # Should match: s3://key:secret@hostname/bucket[/prefix] # Example: s3://showcase_minio:showcase_dev_secret@localhost:9000/showcase-badges -
Feature compilation issues:
# Ensure S3 feature is enabled when needed cargo build --features s3 # Check feature flags in code cargo expand --features s3 | grep -A5 -B5 "cfg.*s3" -
Credential issues:
# Test credentials manually mc alias set test http://localhost:9000 showcase_minio showcase_dev_secret mc ls test # Check if credentials are correctly parsed echo "URL: s3://showcase_minio:showcase_dev_secret@localhost:9000/showcase-badges" echo "Should parse to:" echo " Endpoint: http://localhost:9000" echo " Access Key: showcase_minio" echo " Secret Key: showcase_dev_secret" echo " Bucket: showcase-badges"