Skip to content

Repository files navigation

ZapBB

ZapBB is a modern, high-performance bulletin board platform built with Next.js 16 and Rust (Axum). It features NextAuth.js sessions for web authentication, JWT-based API tokens, and role-based access control (RBAC).


Table of Contents


Features

  • Modern Forum: Categories, threads, posts, reactions, polls, and rich text editing
  • Authentication: NextAuth.js sessions + JWT API tokens with refresh flow
  • Authorization: Role-based access control (Admin, Moderator, Member, Guest)
  • Search: Full-text search powered by OpenSearch
  • Real-time: WebSocket support for live updates (planned)
  • Plugin System: Build-time plugins with UI slots and event hooks
  • Theme System: Configurable themes with light/dark mode support
  • Performance: Rust backend with sub-200ms cached responses

Tech Stack

Layer Technology
Frontend Next.js 16, React 19, TypeScript, Tailwind CSS 4
Backend Rust, Axum, sqlx (compile-time checked queries)
Database PostgreSQL 16
Cache Redis 7
Search OpenSearch 2.13
Auth NextAuth.js, JWT (jsonwebtoken crate)
API OpenAPI 3.1 (utoipa) → TypeScript hooks (OpenAPI-Qraft)
Tooling Bun, Biome, Cargo

Project Structure

ZapBB/
├── backend/              # Rust API server
│   ├── src/              # Application source code
│   ├── migrations/       # SQL migrations
│   ├── Cargo.toml        # Rust dependencies
│   └── .env.example      # Environment template
├── frontend/             # Next.js web application
│   ├── app/              # App Router pages
│   ├── components/       # React components
│   ├── lib/              # Utilities and API client
│   ├── plugins.config.ts # Plugin registrations
│   ├── theme.config.ts   # Theme definitions
│   └── .env.example      # Environment template
├── docs/                 # Documentation
├── specs/                # Technical specifications
├── scripts/              # Utility scripts
├── docker-compose.dev.yml
└── README.md

Prerequisites

For Native Development (Windows)

For Docker Development

  • Docker Desktop 4.0+ (docker.com)
  • Docker Compose v2+

Development Setup

Native Development (Windows)

This is the recommended approach for active development with hot-reload.

Step 1: Clone the Repository

git clone https://github.com/your-org/zapbb.git
cd zapbb

Step 2: Start Infrastructure Services

Start PostgreSQL, Redis, and OpenSearch. You can use Docker for just the services:

docker compose -f docker-compose.dev.yml up -d postgres redis opensearch

Or install them natively on Windows.

Step 3: Configure Environment

Backend:

cd backend
Copy-Item .env.example .env
# Edit .env with your local settings

Key backend variables:

DATABASE_URL=postgres://zapbb:devpassword@localhost:5432/zapbb_dev
REDIS_URL=redis://localhost:6379
OPENSEARCH_URL=http://localhost:9200
JWT_SECRET=your-dev-secret-key
RUST_LOG=debug,zapbb=trace

Frontend:

cd frontend
Copy-Item .env.example .env.local
# Edit .env.local with your local settings

Key frontend variables:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-nextauth-secret

Step 4: Run Database Migrations

cd backend
cargo install sqlx-cli --no-default-features --features postgres
sqlx database create
sqlx migrate run

Step 5: Start the Backend

cd backend
cargo run

The API server starts at http://localhost:8080.

Step 6: Start the Frontend

cd frontend
bun install
bun run dev

The web app starts at http://localhost:3000.


Docker Development

Use this for a consistent, isolated environment.

Step 1: Clone and Configure

git clone https://github.com/your-org/zapbb.git
cd zapbb

Step 2: Start All Services

docker compose -f docker-compose.dev.yml up --build

This starts:

  • PostgreSQL on port 5432
  • Redis on port 6379
  • OpenSearch on port 9200
  • Backend on port 8080
  • Frontend on port 3000

Step 3: View Logs

# All services
docker compose -f docker-compose.dev.yml logs -f

# Specific service
docker compose -f docker-compose.dev.yml logs -f backend

Step 4: Stop Services

docker compose -f docker-compose.dev.yml down

# Remove volumes (reset data)
docker compose -f docker-compose.dev.yml down -v

Production Deployment

Docker Production

Step 1: Create Production Docker Compose

Create docker-compose.prod.yml:

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    container_name: zapbb-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: zapbb-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  opensearch:
    image: opensearchproject/opensearch:2.13.0
    container_name: zapbb-opensearch
    restart: unless-stopped
    environment:
      - discovery.type=single-node
      - plugins.security.disabled=true
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
    volumes:
      - opensearch_data:/usr/share/opensearch/data
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: zapbb-backend
    restart: unless-stopped
    environment:
      DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379
      OPENSEARCH_URL: http://opensearch:9200
      JWT_SECRET: ${JWT_SECRET}
      RUST_LOG: info,zapbb=debug
    ports:
      - "8080:8080"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      opensearch:
        condition: service_healthy

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    container_name: zapbb-frontend
    restart: unless-stopped
    environment:
      NEXT_PUBLIC_API_URL: ${API_URL}
      NEXTAUTH_URL: ${SITE_URL}
      NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
    ports:
      - "3000:3000"
    depends_on:
      - backend

  nginx:
    image: nginx:alpine
    container_name: zapbb-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - frontend
      - backend

volumes:
  postgres_data:
  redis_data:
  opensearch_data:

Step 2: Create Production Dockerfiles

Backend Dockerfile (backend/Dockerfile):

# Stage 1: Builder
FROM rust:1.82-slim as builder

WORKDIR /app

RUN apt-get update && apt-get install -y \
    pkg-config \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release
RUN rm -rf src

COPY . .
RUN cargo build --release

# Stage 2: Runtime
FROM debian:bookworm-slim

WORKDIR /app

RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/zapbb /usr/local/bin/

RUN useradd -r -u 1001 zapbb && chown -R zapbb:zapbb /app
USER zapbb

EXPOSE 8080
CMD ["zapbb"]

Frontend Dockerfile (frontend/Dockerfile):

# Stage 1: Dependencies
FROM oven/bun:1.2 as deps
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile

# Stage 2: Builder
FROM oven/bun:1.2 as builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN bun run build

# Stage 3: Runner
FROM oven/bun:1.2-slim as runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["bun", "server.js"]

Step 3: Configure Production Environment

Create .env.prod:

# Database
DB_USER=zapbb
DB_PASSWORD=secure-production-password
DB_NAME=zapbb_prod

# Redis
REDIS_PASSWORD=secure-redis-password

# Authentication
JWT_SECRET=your-production-jwt-secret-min-32-chars
NEXTAUTH_SECRET=your-production-nextauth-secret

# URLs
API_URL=https://api.yourdomain.com
SITE_URL=https://yourdomain.com

Step 4: Deploy

# Load environment
export $(cat .env.prod | xargs)

# Build and start
docker compose -f docker-compose.prod.yml up -d --build

# Run migrations
docker compose -f docker-compose.prod.yml exec backend sqlx migrate run

# View logs
docker compose -f docker-compose.prod.yml logs -f

Manual Deployment

For VPS or bare-metal servers without Docker.

Backend

# Build release binary
cd backend
cargo build --release

# Copy binary to server
scp target/release/zapbb user@server:/opt/zapbb/

# Create systemd service
sudo tee /etc/systemd/system/zapbb-backend.service << EOF
[Unit]
Description=ZapBB Backend
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=zapbb
WorkingDirectory=/opt/zapbb
ExecStart=/opt/zapbb/zapbb
Restart=always
EnvironmentFile=/opt/zapbb/.env

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable zapbb-backend
sudo systemctl start zapbb-backend

Frontend

# Build production bundle
cd frontend
bun install
bun run build

# Copy to server
rsync -avz .next/standalone/ user@server:/opt/zapbb/frontend/
rsync -avz .next/static/ user@server:/opt/zapbb/frontend/.next/static/
rsync -avz public/ user@server:/opt/zapbb/frontend/public/

# Create systemd service
sudo tee /etc/systemd/system/zapbb-frontend.service << EOF
[Unit]
Description=ZapBB Frontend
After=network.target

[Service]
Type=simple
User=zapbb
WorkingDirectory=/opt/zapbb/frontend
ExecStart=/usr/local/bin/bun server.js
Restart=always
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=/opt/zapbb/frontend/.env

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable zapbb-frontend
sudo systemctl start zapbb-frontend

Configuration

Backend Environment Variables

Variable Description Default
DATABASE_URL PostgreSQL connection string Required
REDIS_URL Redis connection string Required
OPENSEARCH_URL OpenSearch URL Required
JWT_SECRET Secret for JWT signing (min 32 chars) Required
RUST_LOG Log level info
HOST Bind address 0.0.0.0
PORT Listen port 8080

Frontend Environment Variables

Variable Description Default
NEXT_PUBLIC_API_URL Backend API URL Required
NEXTAUTH_URL Canonical site URL Required
NEXTAUTH_SECRET NextAuth.js secret Required
NEXT_PUBLIC_SITE_NAME Site display name ZapBB Forum

See backend/.env.example and frontend/.env.example for full variable lists.


Documentation

Document Description
PRD Product requirements and MVP scope
Technical Architecture System design overview
Database Schema All tables and relationships
API Specification Endpoint contracts
Security & Auth Authentication flows, RBAC
Deployment Full deployment guide
Plugin Authoring Build custom plugins
Theme Authoring Create custom themes

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please read our contributing guidelines and code of conduct.


License

This project is licensed under the MIT License. See LICENSE for details.

About

ZapBB is a modern bulletin board webapp built on Next.js and Rust for fast performance.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages