Getting Started

Install and run Pumpkin Hub in a development environment.

Prerequisites

ToolMinimum VersionUsage
Docker + Docker Compose24.x / v2Service orchestration
RustEdition 2021 (1.70+)API compilation
Node.js20.xFrontend build
Git2.xVersion control

Installation

Clone the repository and navigate to the directory:

git clone https://github.com/FabLrc/pumpkin-hub.git
cd pumpkin-hub

Environment Setup

Pumpkin Hub uses two separate .env files depending on how you run the project. Understanding which one to fill is the most common source of confusion.

FileUsed byWhen
.env (project root) Docker Compose When running docker compose up. Compose reads this file for variable substitution (${GITHUB_CLIENT_ID}, etc.).
api/.env Rust API directly When running cargo run inside api/ without Docker. Loaded by the dotenvy crate at startup.
Common Pitfall
Only the root .env is needed for Docker Compose. If GITHUB_CLIENT_ID is set in api/.env but the root .env is missing or empty, Docker Compose will inject an empty string into the container — causing GitHub OAuth to return a 404.

Minimal root .env (Docker Compose)

Create this file at the project root (same directory as docker-compose.yml):

# Required — create at https://github.com/settings/developers
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret

# Optional — enables Google / Discord login
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=

# JWT secret (change in production)
JWT_SECRET=dev_jwt_secret_change_me_in_production

# Optional — enables GitHub App features (repo linking, auto-publish, publish-from-GitHub)
# Create at https://github.com/settings/apps
GITHUB_APP_ID=
GITHUB_APP_PRIVATE_KEY=     # PEM content with literal \n between lines
GITHUB_APP_WEBHOOK_SECRET=

All other variables (database URL, Meilisearch, MinIO, SMTP) are already hardcoded in docker-compose.yml for local development and do not need to appear in the root .env.

Launch with Docker Compose

The recommended method for development. Docker Compose orchestrates 6 services:

# Build and start all services
docker compose up --build

# Or in the background
docker compose up --build -d

# View logs in real-time
docker compose logs -f api-dev
Note
The API waits for PostgreSQL and Meilisearch to be healthy before starting, thanks to the healthcheck configured in the compose file.

Services and Ports

ServiceLocal URLDescription
Frontendhttp://localhost:3000Next.js interface
APIhttp://localhost:8080Axum backend
PostgreSQLlocalhost:5432Database
Meilisearchhttp://localhost:7700Search engine
MinIOhttp://localhost:9000Object storage (binary artifacts)
MinIO Consolehttp://localhost:9001MinIO admin console
Mailpithttp://localhost:8025Email testing web UI

Local Launch (without Docker)

To develop a service individually, it can be run outside Docker:

Rust API

cd api

# Check compilation
cargo check

# Run in development mode
cargo run

# With hot-reload (requires cargo-watch)
cargo install cargo-watch
cargo watch -x run

Next.js Frontend

cd frontend

# Install dependencies
npm install

# Start development server
npm run dev

# Check linting
npm run lint

# Production build
npm run build

Environment Variables Reference

Full reference of all variables accepted by the API. In Docker mode, most are already set by docker-compose.yml — only the secrets listed in the Environment Setup section need to be provided via the root .env. When running with cargo run directly, set all required variables in api/.env.

VariableRequiredDefaultDescription
DATABASE_URLYesPostgreSQL connection URL
MEILISEARCH_URLYesMeilisearch server URL
MEILISEARCH_KEYYesMeilisearch master key
SERVER_HOSTNo0.0.0.0Bind IP address
SERVER_PORTNo8080Listening port
ALLOWED_ORIGINSNohttp://localhost:3000CORS origins (comma-separated)
RUST_LOGNopumpkin_hub_api=infoLog verbosity level
NEXT_PUBLIC_API_URLNoAPI URL for the frontend (browser-side)
NEXT_INTERNAL_API_URLNoAPI URL for server-side proxy routes (Docker internal network)
S3_ENDPOINT_URLYesInternal S3-compatible endpoint used by the API for uploads & deletes (e.g. http://minio-dev:9000 inside Docker)
S3_PUBLIC_URLStrongly recommendedS3_ENDPOINT_URLBrowser-reachable URL used to sign presigned download URLs. Must be reachable by the end-user. See S3 configuration notes.
S3_BUCKETYesS3 bucket name for binary storage
S3_ACCESS_KEY_IDYesS3 access key ID
S3_SECRET_ACCESS_KEYYesS3 secret access key
S3_REGIONNous-east-1S3 region. MinIO ignores it; use auto for Cloudflare R2
S3_FORCE_PATH_STYLENofalseSet to true for MinIO (path-style addressing). Must be false for Cloudflare R2
S3_USE_DIRECT_URLSNofalseServe files via direct public URLs (no presigning). Use for public R2 buckets.

Security & Cookies

VariableRequiredDefaultDescription
COOKIE_SECURENoAuto-detectedForce Secure flag on auth cookies. Auto-enabled when any ALLOWED_ORIGINS uses HTTPS.
COOKIE_DOMAINNoShared cookie domain for cross-subdomain auth (e.g., .pumpkinhub.org for pumpkinhub.org + api.pumpkinhub.org).

Authentication & JWT

VariableRequiredDefaultDescription
JWT_SECRETYesSecret key for signing JWT tokens
JWT_TTL_SECONDSNo86400JWT token lifetime (default: 24 hours)
API_PUBLIC_URLNohttp://localhost:8080Publicly reachable API base URL (used in email links)
GITHUB_CLIENT_IDYesGitHub OAuth App client ID
GITHUB_CLIENT_SECRETYesGitHub OAuth App client secret
GITHUB_REDIRECT_URINo…/auth/github/callbackGitHub OAuth redirect URI
GOOGLE_CLIENT_IDNoGoogle OAuth client ID (enables Google login)
GOOGLE_CLIENT_SECRETNoGoogle OAuth client secret
GOOGLE_REDIRECT_URINo…/auth/google/callbackGoogle OAuth redirect URI
DISCORD_CLIENT_IDNoDiscord OAuth client ID (enables Discord login)
DISCORD_CLIENT_SECRETNoDiscord OAuth client secret
DISCORD_REDIRECT_URINo…/auth/discord/callbackDiscord OAuth redirect URI

GitHub App

The GitHub App variables are optional. When configured they unlock repository linking, webhook-based auto-publishing, and the Publish from GitHub flow. Create an App at github.com/settings/apps.

VariableRequiredDefaultDescription
GITHUB_APP_IDNo*GitHub App numeric ID. Enables App features when set.
GITHUB_APP_PRIVATE_KEYIf APP_ID setRSA private key (PEM). Use literal \n between lines in .env files.
GITHUB_APP_WEBHOOK_SECRETIf APP_ID setWebhook secret for HMAC-SHA256 signature verification.

SMTP (Email)

SMTP is optional. When configured, the API sends email verification and password recovery emails. If omitted, email features degrade gracefully (new accounts are auto-verified).

VariableRequiredDefaultDescription
SMTP_HOSTNo*SMTP server hostname (e.g. localhost, smtp.gmail.com). Enables email features when set.
SMTP_PORTNo587SMTP server port
SMTP_USERNAMEIf SMTP_HOST setSMTP authentication username
SMTP_PASSWORDIf SMTP_HOST setSMTP authentication password
SMTP_FROM_ADDRESSIf SMTP_HOST setSender email address (e.g. noreply@pumpkinhub.dev)

Rate Limiting

VariableRequiredDefaultDescription
RATE_LIMIT_GENERAL_PER_SECONDNo1Token replenish interval (seconds) for general routes
RATE_LIMIT_GENERAL_BURST_SIZENo30Max burst size for general routes
RATE_LIMIT_AUTH_PER_SECONDNo4Token replenish interval (seconds) for auth routes (stricter)
RATE_LIMIT_AUTH_BURST_SIZENo5Max burst size for auth routes (stricter)

Example api/.env (local development without Docker)

DATABASE_URL=postgres://pumpkin_user:dev_password@localhost:5432/pumpkin_hub_dev
MEILISEARCH_URL=http://localhost:7700
MEILISEARCH_KEY=dev_master_key
SERVER_PORT=8080
ALLOWED_ORIGINS=http://localhost:3000
RUST_LOG=pumpkin_hub_api=debug,tower_http=debug

# Authentication
JWT_SECRET=your-super-secret-key-change-in-prod
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

# GitHub App (optional — enables repo linking & auto-publish)
# GITHUB_APP_ID=
# GITHUB_APP_PRIVATE_KEY=
# GITHUB_APP_WEBHOOK_SECRET=

# Object storage (MinIO — local outside Docker)
S3_ENDPOINT_URL=http://localhost:9000
S3_PUBLIC_URL=http://localhost:9000
S3_BUCKET=pumpkin-hub-binaries
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_FORCE_PATH_STYLE=true

# SMTP (optional — uses Mailpit in Docker)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_USERNAME=pumpkin
SMTP_PASSWORD=pumpkin
SMTP_FROM_ADDRESS=noreply@pumpkinhub.dev

S3 / R2 Configuration Guide

Pumpkin Hub uses an S3-compatible object store for binary artifacts. Two separate S3 clients are instantiated internally: one for server-side operations (upload, delete) using the internal endpoint, and one for generating presigned download URLs using the public endpoint.

Why S3_PUBLIC_URL matters
AWS SigV4 embeds the Host header in the request signature. If a presigned URL is generated for host minio-dev:9000 (Docker-internal) but opened by a browser at localhost:9000, the store returns a SignatureDoesNotMatch error. S3_PUBLIC_URL tells the API which host to use when signing download URLs, ensuring the signed host matches the host the browser will contact.

Local Development (Docker + MinIO)

Inside Docker, the API reaches MinIO at http://minio-dev:9000 while the browser reaches it at http://localhost:9000. Set both variables to different values:

S3_ENDPOINT_URL=http://minio-dev:9000     # used by the API container
S3_PUBLIC_URL=http://localhost:9000       # used for presigned URL signing
S3_FORCE_PATH_STYLE=true                  # required for MinIO

Production (Cloudflare R2)

With Cloudflare R2, upload traffic goes through the private R2 endpoint while download links are signed for your public R2 subdomain (or custom domain). Note that R2 requires S3_REGION=auto and virtual-hosted style addressing (S3_FORCE_PATH_STYLE=false).

S3_ENDPOINT_URL=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
S3_PUBLIC_URL=https://pub-<HASH>.r2.dev   # or your custom domain
S3_BUCKET=pumpkin-hub-binaries
S3_ACCESS_KEY_ID=<R2_TOKEN_ID>
S3_SECRET_ACCESS_KEY=<R2_TOKEN_SECRET>
S3_REGION=auto
S3_FORCE_PATH_STYLE=false

Email Testing (Mailpit)

In the Docker development environment, a Mailpit instance captures all outgoing emails. No real email is ever sent during development.

When you register a new account or trigger a password reset, the email will appear instantly in the Mailpit web interface. Click the verification/reset link from there to complete the flow.

Installation Verification

Once the services are running, verify that the API responds:

curl http://localhost:8080/api/v1/health

Expected response:

{
  "status": "ok",
  "service": "pumpkin-hub-api",
  "version": "0.1.0",
  "database": "connected"
}
CI/CD
The continuous integration pipeline (GitHub Actions) automatically runs on each PR: lint + type-check + build for the frontend, and cargo fmt + cargo clippy + cargo test for the API.