From 3d2ad10b82770fd9be607bfb62fcaab81e5c6a84 Mon Sep 17 00:00:00 2001 From: BroUnion Date: Sun, 29 Mar 2026 19:17:57 +0000 Subject: [PATCH 1/3] feat: enhance Docker setup and documentation for local development and self-hosted deployment --- .env.example | 121 ++++++------- apps/dashboard/Dockerfile | 56 ++++++ docker-compose.production.yml | 259 ++++++++++++--------------- docker-compose.self-hosted.yml | 86 ++++----- docker-compose.yml | 128 ++++--------- docs/docker-setup.md | 169 +++++++++++++++++ docs/getting-started/installation.md | 124 ++++++++----- packages/server/Dockerfile | 9 +- 8 files changed, 555 insertions(+), 397 deletions(-) create mode 100644 apps/dashboard/Dockerfile create mode 100644 docs/docker-setup.md diff --git a/.env.example b/.env.example index c917b6c..d410697 100644 --- a/.env.example +++ b/.env.example @@ -6,98 +6,93 @@ # ============================================================================ # ---------------------------------------------------------------------------- -# Required: Database +# Database (PostgreSQL) # ---------------------------------------------------------------------------- -# PostgreSQL connection string (for postgres, neon, supabase) -# Format: postgresql://user:password@host:port/database -DATABASE_URL=postgres://user:password@localhost:5432/betterbase - -# Or for Neon (serverless PostgreSQL) -# DATABASE_URL=postgres://user:password@ep-xxx.us-east-1.aws.neon.tech/neondb?sslmode=require +POSTGRES_USER=betterbase +POSTGRES_PASSWORD=your_secure_password_here +POSTGRES_DB=betterbase -# Or for Turso (libSQL) -# TURSO_URL=libsql://your-database.turso.io -# TURSO_AUTH_TOKEN=your-auth-token +# Connection string for applications +# Format: postgresql://user:password@host:port/database +DATABASE_URL=postgresql://betterbase:your_secure_password_here@localhost:5432/betterbase # ---------------------------------------------------------------------------- -# Required: Authentication +# Authentication # ---------------------------------------------------------------------------- # Generate a secure secret: openssl rand -base64 32 -AUTH_SECRET=your-super-secret-key-min-32-chars-long-change-in-production +AUTH_SECRET=your-super-secret-key-min-32-chars-long AUTH_URL=http://localhost:3000 # ---------------------------------------------------------------------------- -# Optional: Storage (S3-compatible) +# MinIO (S3-compatible storage for local development) # ---------------------------------------------------------------------------- -# Provider: s3, r2, backblaze, minio -STORAGE_PROVIDER=r2 -STORAGE_BUCKET=betterbase-storage -STORAGE_REGION=auto -STORAGE_ENDPOINT=https://your-r2-endpoint.r2.cloudflarestorage.com -STORAGE_ACCESS_KEY_ID=your-access-key -STORAGE_SECRET_ACCESS_KEY=your-secret-key +MINIO_ROOT_USER=minioadmin +MINIO_ROOT_PASSWORD=minioadmin_password + +STORAGE_ENDPOINT=http://localhost:9000 +STORAGE_ACCESS_KEY=minioadmin +STORAGE_SECRET_KEY=minioadmin_password +STORAGE_BUCKET=betterbase # ---------------------------------------------------------------------------- -# Optional: Email (SMTP) +# Inngest (Durable Workflow Engine) # ---------------------------------------------------------------------------- -SMTP_HOST=smtp.example.com -SMTP_PORT=587 -SMTP_USER=your-smtp-user -SMTP_PASS=your-smtp-password -SMTP_FROM=noreply@your-domain.com +INNGEST_LOG_LEVEL=info +# Generate signing key: openssl rand -hex 32 +INNGEST_SIGNING_KEY= +# Generate event key: openssl rand -hex 16 +INNGEST_EVENT_KEY= # ---------------------------------------------------------------------------- -# Optional: OAuth Providers +# Application Settings # ---------------------------------------------------------------------------- -# GitHub -# GITHUB_CLIENT_ID=your-github-client-id -# GITHUB_CLIENT_SECRET=your-github-client-secret +NODE_ENV=development +PORT=3001 +HOST=0.0.0.0 -# Google -# GOOGLE_CLIENT_ID=your-google-client-id -# GOOGLE_CLIENT_SECRET=your-google-client-secret +CORS_ORIGIN=http://localhost:3000,http://localhost:5173 -# Discord -# DISCORD_CLIENT_ID=your-discord-client-id -# DISCORD_CLIENT_SECRET=your-discord-client-secret +LOG_LEVEL=debug # ---------------------------------------------------------------------------- -# Optional: Phone Auth (Twilio) +# Production Settings # ---------------------------------------------------------------------------- -# TWILIO_ACCOUNT_SID=your-twilio-sid -# TWILIO_AUTH_TOKEN=your-twilio-token -# TWILIO_PHONE_NUMBER=+1234567890 +# HTTP port for nginx proxy (default: 80) +# HTTP_PORT=80 + +# Use external managed services instead of Docker (uncomment): +# DATABASE_URL=postgres://user:password@host:5432/database +# STORAGE_ENDPOINT=https://your-r2-endpoint.r2.cloudflarestorage.com +# STORAGE_ACCESS_KEY=your-access-key +# STORAGE_SECRET_KEY=your-secret-key # ---------------------------------------------------------------------------- -# Application Settings +# Email (optional) # ---------------------------------------------------------------------------- -NODE_ENV=development -PORT=3000 -HOST=0.0.0.0 +# SMTP_HOST=smtp.example.com +# SMTP_PORT=587 +# SMTP_USER=your-smtp-user +# SMTP_PASS=your-smtp-password +# SMTP_FROM=noreply@your-domain.com -# Comma-separated list of allowed CORS origins -CORS_ORIGIN=http://localhost:3000,http://localhost:5173 +# ---------------------------------------------------------------------------- +# OAuth Providers (optional) +# ---------------------------------------------------------------------------- +# GITHUB_CLIENT_ID=your-github-client-id +# GITHUB_CLIENT_SECRET=your-github-client-secret -# Logging -LOG_LEVEL=debug +# GOOGLE_CLIENT_ID=your-google-client-id +# GOOGLE_CLIENT_SECRET=your-google-client-secret # ---------------------------------------------------------------------------- -# Vector Search (optional) +# Phone Auth (optional - Twilio) # ---------------------------------------------------------------------------- -# VECTOR_PROVIDER=openai -# OPENAI_API_KEY=your-openai-api-key +# TWILIO_ACCOUNT_SID=your-twilio-sid +# TWILIO_AUTH_TOKEN=your-twilio-token +# TWILIO_PHONE_NUMBER=+1234567890 # ---------------------------------------------------------------------------- -# Inngest (Durable Workflow Engine) +# Vector Search (optional) # ---------------------------------------------------------------------------- -# For local development with Inngest Docker: -# INNGEST_BASE_URL=http://localhost:8288 -# -# For self-hosted production: -# INNGEST_BASE_URL=http://inngest:8288 -# Generate signing key: openssl rand -hex 32 -# INNGEST_SIGNING_KEY=change-me-to-a-random-hex-string -# Generate event key: openssl rand -hex 16 -# INNGEST_EVENT_KEY=change-me-to-another-random-hex-string -# Log level (debug | info | warn | error) -# INNGEST_LOG_LEVEL=info +# VECTOR_PROVIDER=openai +# OPENAI_API_KEY=your-openai-api-key \ No newline at end of file diff --git a/apps/dashboard/Dockerfile b/apps/dashboard/Dockerfile new file mode 100644 index 0000000..5dd1cd0 --- /dev/null +++ b/apps/dashboard/Dockerfile @@ -0,0 +1,56 @@ +# ============================================================================ +# Betterbase Dashboard Dockerfile +# +# Builds the React dashboard and serves it with nginx. +# Used in production self-hosted deployments. +# +# Build: +# docker build -f apps/dashboard/Dockerfile -t betterbase-dashboard . +# ============================================================================ + +FROM oven/bun:1.3.9-debian AS builder + +WORKDIR /app + +COPY package.json bun.lock* ./ + +RUN bun install --frozen-lockfile + +COPY . . + +ARG VITE_API_URL=http://localhost:3001 +ENV VITE_API_URL=$VITE_API_URL + +RUN bun run build + +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +RUN cat > /etc/nginx/conf.d/default.conf << 'EOF' +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Cache static assets + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA fallback - all routes go to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; +} +EOF + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 7c1fdf6..c6d913e 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -1,163 +1,132 @@ # ============================================================================ # Betterbase Production Docker Compose # -# Production-ready configuration with: -# - PostgreSQL (managed externally or via this compose) -# - S3-compatible storage (Cloudflare R2, MinIO, etc.) -# - Health checks -# - Proper security settings +# Production-ready configuration with all services. +# Requires .env file with proper values. # # Usage: -# docker-compose -f docker-compose.production.yml up -d -# -# For production, it's recommended to: -# 1. Use external managed database (Neon, Supabase, RDS, etc.) -# 2. Use external S3 storage (R2, S3, B2) -# 3. Use a reverse proxy (Caddy, Nginx, Traefik) -# 4. Enable SSL/TLS +# cp .env.example .env +# # Edit .env with your values +# docker compose -f docker-compose.production.yml up -d # ============================================================================ services: - # -------------------------------------------------------------------------- - # Betterbase Application - # -------------------------------------------------------------------------- - app: - build: - context: . - dockerfile: Dockerfile.project - args: - # Build arguments - NODE_ENV: production - expose: - - "3000" + postgres: + image: postgres:16-alpine + container_name: betterbase-postgres + restart: unless-stopped environment: - # Database - UPDATE THIS for your managed PostgreSQL - DATABASE_URL: ${DATABASE_URL} - - # Auth - IMPORTANT: Generate a secure secret in production - AUTH_SECRET: ${AUTH_SECRET} - AUTH_URL: ${AUTH_URL:-https://your-domain.com} - - # Storage - S3-compatible - STORAGE_PROVIDER: ${STORAGE_PROVIDER:-r2} - STORAGE_BUCKET: ${STORAGE_BUCKET:-betterbase-storage} - STORAGE_REGION: ${STORAGE_REGION:-auto} - # For R2/S3-compatible - STORAGE_ENDPOINT: ${STORAGE_ENDPOINT:-https://your-r2-endpoint.r2.cloudflarestorage.com} - STORAGE_ACCESS_KEY_ID: ${STORAGE_ACCESS_KEY_ID} - STORAGE_SECRET_ACCESS_KEY: ${STORAGE_SECRET_ACCESS_KEY} - - # Node environment - NODE_ENV: production - PORT: "3000" - HOST: "0.0.0.0" - - # Security - CORS_ORIGIN: ${CORS_ORIGIN:-https://your-domain.com} - - # Optional: Logging - LOG_LEVEL: ${LOG_LEVEL:-info} - - restart: always + POSTGRES_USER: ${POSTGRES_USER:-betterbase} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-betterbase} + POSTGRES_DB: ${POSTGRES_DB:-betterbase} + volumes: + - postgres_data:/var/lib/postgresql/data healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-betterbase}"] + interval: 10s + timeout: 5s + retries: 5 networks: - - betterbase-prod + - betterbase-network - # -------------------------------------------------------------------------- - # Optional: Self-hosted PostgreSQL (if not using managed) - # Remove this service if using Neon, Supabase, RDS, etc. - # -------------------------------------------------------------------------- - # postgres: - # image: postgres:16-alpine - # environment: - # POSTGRES_USER: ${DB_USER:-betterbase} - # POSTGRES_PASSWORD: ${DB_PASSWORD} - # POSTGRES_DB: ${DB_NAME:-betterbase} - # volumes: - # - postgres_data:/var/lib/postgresql/data - # restart: always - # healthcheck: - # test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-betterbase} -d ${DB_NAME:-betterbase}"] - # interval: 10s - # timeout: 5s - # retries: 5 - # networks: - # - betterbase-prod - # # Only expose ports if needed for debugging - # # ports: - # # - "5432:5432" + minio: + image: minio/minio:latest + container_name: betterbase-minio + restart: unless-stopped + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${STORAGE_ACCESS_KEY:-minioadmin} + MINIO_ROOT_PASSWORD: ${STORAGE_SECRET_KEY:-minioadmin} + volumes: + - minio_data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - betterbase-network - # -------------------------------------------------------------------------- - # Optional: MinIO for self-hosted S3 storage - # Remove this service if using R2, S3, B2 - # -------------------------------------------------------------------------- - # minio: - # image: minio/minio:latest - # command: server /data --console-address ":9001" - # environment: - # MINIO_ROOT_USER: ${MINIO_ROOT_USER} - # MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} - # volumes: - # - minio_data:/data - # restart: always - # networks: - # - betterbase-prod + minio-init: + image: minio/mc:latest + container_name: betterbase-minio-init + depends_on: + minio: + condition: service_healthy + entrypoint: > + /bin/sh -c " + mc alias set local http://minio:9000 ${STORAGE_ACCESS_KEY:-minioadmin} ${STORAGE_SECRET_KEY:-minioadmin}; + mc mb --ignore-existing local/betterbase; + echo 'MinIO bucket initialized.'; + " + networks: + - betterbase-network - # -------------------------------------------------------------------------- - # Optional: Traefik reverse proxy (uncomment for automatic HTTPS) - # -------------------------------------------------------------------------- - # traefik: - # image: traefik:v3.0 - # command: - # - "--api.insecure=true" - # - "--providers.docker=true" - # - "--providers.docker.exposedbydefault=false" - # - "--entrypoints.web.address=:80" - # - "--entrypoints.websecure.address=:443" - # - "--certificatesresolvers.letsencrypt.acme.email=your@email.com" - # - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - # - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - # ports: - # - "80:80" - # - "443:443" - # - "8080:8080" - # volumes: - # - /var/run/docker.sock:/var/run/docker.sock:ro - # - letsencrypt_data:/letsencrypt - # networks: - # - betterbase-prod + inngest: + image: inngest/inngest:v1.17.5 + container_name: betterbase-inngest + restart: unless-stopped + command: inngest dev --host 0.0.0.0 --port 8288 + environment: + INNGEST_LOG_LEVEL: ${INNGEST_LOG_LEVEL:-info} + volumes: + - inngest_data:/data + networks: + - betterbase-network - # -------------------------------------------------------------------------- - # Optional: Caddy reverse proxy (simpler than Traefik) - # -------------------------------------------------------------------------- - # caddy: - # image: caddy:2-alpine - # volumes: - # - ./Caddyfile:/etc/caddy/Caddyfile - # - caddy_data:/data - # ports: - # - "80:80" - # - "443:443" - # networks: - # - betterbase-prod + betterbase-server: + build: + context: . + dockerfile: packages/server/Dockerfile + container_name: betterbase-server + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + minio: + condition: service_healthy + minio-init: + condition: service_completed_successfully + inngest: + condition: service_started + environment: + DATABASE_URL: postgresql://${POSTGRES_USER:-betterbase}:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/${POSTGRES_DB:-betterbase} + AUTH_SECRET: ${AUTH_SECRET:-change-this-in-production} + AUTH_URL: ${AUTH_URL:-http://localhost:3000} + STORAGE_ENDPOINT: http://minio:9000 + STORAGE_ACCESS_KEY: ${STORAGE_ACCESS_KEY:-minioadmin} + STORAGE_SECRET_KEY: ${STORAGE_SECRET_KEY:-minioadmin} + STORAGE_BUCKET: betterbase + PORT: "3001" + NODE_ENV: production + CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost} + INNGEST_BASE_URL: http://inngest:8288 + INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY:-} + INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY:-} + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3001/health || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - betterbase-network -# ---------------------------------------------------------------------------- -# Networks -# ---------------------------------------------------------------------------- -networks: - betterbase-prod: - driver: bridge + dashboard: + image: nginx:alpine + container_name: betterbase-dashboard + restart: unless-stopped + volumes: + - ./apps/dashboard/dist:/usr/share/nginx/html:ro + depends_on: + - betterbase-server + networks: + - betterbase-network -# ---------------------------------------------------------------------------- -# Volumes -# ---------------------------------------------------------------------------- volumes: - # postgres_data: - # minio_data: - # letsencrypt_data: - # caddy_data: + postgres_data: + minio_data: + inngest_data: + +networks: + betterbase-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.self-hosted.yml b/docker-compose.self-hosted.yml index d00a15a..1bbd9b6 100644 --- a/docker-compose.self-hosted.yml +++ b/docker-compose.self-hosted.yml @@ -1,34 +1,49 @@ -version: "3.9" +# ============================================================================ +# Betterbase Self-Hosted Production Docker Compose +# +# Full self-hosted deployment with all services. +# No external dependencies required. +# +# Usage: +# 1. Build the project: bun run build +# 2. cp .env.example .env +# 3. docker compose -f docker-compose.self-hosted.yml up -d +# +# Services: +# - PostgreSQL: http://localhost:5432 +# - MinIO: http://localhost:9000 (console: http://localhost:9001) +# - Inngest: http://localhost:8288 +# - Server: http://localhost:3000 +# - Dashboard: http://localhost:3000 (root) +# ============================================================================ services: - # ─── Postgres ────────────────────────────────────────────────────────────── postgres: image: postgres:16-alpine container_name: betterbase-postgres restart: unless-stopped environment: - POSTGRES_USER: betterbase + POSTGRES_USER: ${POSTGRES_USER:-betterbase} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-betterbase} - POSTGRES_DB: betterbase + POSTGRES_DB: ${POSTGRES_DB:-betterbase} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U betterbase"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-betterbase}"] interval: 10s timeout: 5s retries: 5 networks: - betterbase-internal - # ─── MinIO (S3-compatible storage) ───────────────────────────────────────── minio: - image: minio/minio:RELEASE.2024-01-16T16-07-38Z + image: minio/minio:latest container_name: betterbase-minio restart: unless-stopped command: server /data --console-address ":9001" environment: - MINIO_ROOT_USER: ${STORAGE_ACCESS_KEY:-minioadmin} - MINIO_ROOT_PASSWORD: ${STORAGE_SECRET_KEY:-minioadmin} + MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin} volumes: - minio_data:/data healthcheck: @@ -39,28 +54,26 @@ services: networks: - betterbase-internal - # ─── MinIO bucket init (runs once, exits) ────────────────────────────────── minio-init: - image: minio/mc:RELEASE.2024-01-06T18-51-57Z + image: minio/mc:latest container_name: betterbase-minio-init depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " - mc alias set local http://minio:9000 ${STORAGE_ACCESS_KEY:-minioadmin} ${STORAGE_SECRET_KEY:-minioadmin}; + mc alias set local http://minio:9000 ${MINIO_ROOT_USER:-minioadmin} ${MINIO_ROOT_PASSWORD:-minioadmin}; mc mb --ignore-existing local/betterbase; echo 'MinIO bucket initialized.'; " networks: - betterbase-internal - # ─── Inngest (Durable Workflow Engine) ──────────────────────────────────── inngest: image: inngest/inngest:latest container_name: betterbase-inngest restart: unless-stopped - command: inngest start --host 0.0.0.0 --port 8288 + command: inngest dev --host 0.0.0.0 --port 8288 environment: INNGEST_LOG_LEVEL: ${INNGEST_LOG_LEVEL:-info} volumes: @@ -73,7 +86,6 @@ services: networks: - betterbase-internal - # ─── Betterbase Server ───────────────────────────────────────────────────── betterbase-server: build: context: . @@ -90,62 +102,56 @@ services: inngest: condition: service_healthy environment: - DATABASE_URL: postgresql://betterbase:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/betterbase - BETTERBASE_JWT_SECRET: ${BETTERBASE_JWT_SECRET:?JWT secret required - set BETTERBASE_JWT_SECRET in .env} - BETTERBASE_ADMIN_EMAIL: ${BETTERBASE_ADMIN_EMAIL:-} - BETTERBASE_ADMIN_PASSWORD: ${BETTERBASE_ADMIN_PASSWORD:-} - BETTERBASE_PUBLIC_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost} + DATABASE_URL: postgresql://${POSTGRES_USER:-betterbase}:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/${POSTGRES_DB:-betterbase} + AUTH_SECRET: ${AUTH_SECRET:?JWT secret required - set AUTH_SECRET in .env} + AUTH_URL: ${AUTH_URL:-http://localhost:3000} STORAGE_ENDPOINT: http://minio:9000 - STORAGE_ACCESS_KEY: ${STORAGE_ACCESS_KEY:-minioadmin} - STORAGE_SECRET_KEY: ${STORAGE_SECRET_KEY:-minioadmin} + STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin} + STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin} + STORAGE_BUCKET: betterbase PORT: "3001" NODE_ENV: production - CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost} + CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost} INNGEST_BASE_URL: http://inngest:8288 - INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY} - INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY} - networks: - - betterbase-internal + INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY:-} + INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY:-} healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:3001/health || exit 1"] interval: 10s timeout: 5s retries: 5 + networks: + - betterbase-internal - # ─── Dashboard ───────────────────────────────────────────────────────────── - betterbase-dashboard: - build: - context: . - dockerfile: apps/dashboard/Dockerfile # Dashboard Dockerfile — see SH-25 - args: - VITE_API_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost} + dashboard: + image: nginx:alpine container_name: betterbase-dashboard restart: unless-stopped + volumes: + - ./apps/dashboard/dist:/usr/share/nginx/html:ro depends_on: - betterbase-server: - condition: service_healthy + - betterbase-server networks: - betterbase-internal - # ─── Nginx Reverse Proxy ─────────────────────────────────────────────────── nginx: image: nginx:alpine container_name: betterbase-nginx restart: unless-stopped depends_on: - betterbase-server - - betterbase-dashboard + - dashboard ports: - "${HTTP_PORT:-80}:80" volumes: - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - networks: - - betterbase-internal healthcheck: test: ["CMD", "nginx", "-t"] interval: 30s timeout: 10s retries: 3 + networks: + - betterbase-internal volumes: postgres_data: diff --git a/docker-compose.yml b/docker-compose.yml index 02dc018..ed4d91c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,132 +1,66 @@ # ============================================================================ -# Betterbase Docker Compose +# Betterbase Local Development Docker Compose # -# Development environment with PostgreSQL and the Betterbase application. +# Quick start for local development. Starts PostgreSQL, MinIO, and Inngest. +# Betterbase server runs locally with hot-reload. # # Usage: -# docker-compose up -d # Start all services -# docker-compose logs -f app # View app logs -# docker-compose down # Stop all services -# docker-compose down -v # Stop and remove volumes +# docker compose up -d postgres minio inngest +# bun run dev # ============================================================================ services: - # -------------------------------------------------------------------------- - # Betterbase Application - # -------------------------------------------------------------------------- - app: - build: - context: . - dockerfile: Dockerfile.project - ports: - - "3000:3000" - environment: - # Database - connect to postgres service - DATABASE_URL: postgres://betterbase:betterbase_secret@postgres:5432/betterbase - - # Auth - AUTH_SECRET: ${AUTH_SECRET:-your-super-secret-key-min-32-chars-long-change-in-production} - AUTH_URL: http://localhost:3000 - - # Storage (MinIO for S3-compatible storage) - STORAGE_PROVIDER: minio - STORAGE_ENDPOINT: http://minio:9000 - STORAGE_BUCKET: betterbase - STORAGE_ACCESS_KEY: minioadmin - STORAGE_SECRET_KEY: minioadmin - - # Node environment - NODE_ENV: ${NODE_ENV:-development} - PORT: "3000" - - # CORS - CORS_ORIGIN: http://localhost:3000,http://localhost:5173 - - volumes: - # Mount source for hot reload in development - - ./src:/app/src - # Storage volume for uploaded files - - betterbase_storage:/app/storage - depends_on: - postgres: - condition: service_healthy - minio: - condition: service_started - restart: unless-stopped - networks: - - betterbase-network - - # -------------------------------------------------------------------------- # PostgreSQL Database - # -------------------------------------------------------------------------- postgres: image: postgres:16-alpine + container_name: betterbase-postgres-local + restart: unless-stopped environment: POSTGRES_USER: betterbase - POSTGRES_PASSWORD: betterbase_secret + POSTGRES_PASSWORD: betterbase_dev_password POSTGRES_DB: betterbase - volumes: - - postgres_data:/var/lib/postgresql/data - # Initialize with schema on first run (optional) - # - ./init-schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro ports: - "5432:5432" + volumes: + - postgres_local_data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U betterbase -d betterbase"] + test: ["CMD-SHELL", "pg_isready -U betterbase"] interval: 5s timeout: 5s retries: 5 - restart: unless-stopped - networks: - - betterbase-network - # -------------------------------------------------------------------------- - # MinIO for S3-compatible storage (development) - # -------------------------------------------------------------------------- + # MinIO (S3-compatible storage) minio: image: minio/minio:latest + container_name: betterbase-minio-local + restart: unless-stopped command: server /data --console-address ":9001" environment: - MINIO_ROOT_USER: minioadmin - MINIO_ROOT_PASSWORD: minioadmin - volumes: - - minio_data:/data + MINIO_ROOT_USER: betterbase + MINIO_ROOT_PASSWORD: betterbase_dev_password ports: - "9000:9000" - "9001:9001" + volumes: + - minio_local_data:/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 10s timeout: 5s retries: 5 - networks: - - betterbase-network - # -------------------------------------------------------------------------- - # Optional: Mailhog for email testing (development) - # -------------------------------------------------------------------------- - # mailhog: - # image: mailhog/mailhog:latest - # ports: - # - "1025:1025" # SMTP - # - "8025:8025" # Web UI - # networks: - # - betterbase-network - -# ---------------------------------------------------------------------------- -# Networks -# ---------------------------------------------------------------------------- -networks: - betterbase-network: - driver: bridge + # Inngest (Durable Workflow Engine) + inngest: + image: inngest/inngest:v1.17.5 + container_name: betterbase-inngest-local + restart: unless-stopped + command: inngest dev --host 0.0.0.0 --port 8288 + ports: + - "8288:8288" + volumes: + - inngest_local_data:/data -# ---------------------------------------------------------------------------- -# Volumes -# ---------------------------------------------------------------------------- volumes: - postgres_data: - driver: local - betterbase_storage: - driver: local - minio_data: - driver: local + postgres_local_data: + minio_local_data: + inngest_local_data: \ No newline at end of file diff --git a/docs/docker-setup.md b/docs/docker-setup.md new file mode 100644 index 0000000..a0e0b80 --- /dev/null +++ b/docs/docker-setup.md @@ -0,0 +1,169 @@ +# Docker Setup Guide + +Quick start guides for running Betterbase with Docker. + +## Quick Start (Local Development) + +The simplest way to get started: + +```bash +# Start infrastructure (PostgreSQL, MinIO, Inngest) +docker compose up -d + +# Run Betterbase server locally with hot-reload +bun run dev +``` + +That's it! Your server will be available at `http://localhost:3001`. + +### Services Started + +| Service | URL | Purpose | +|---------|-----|---------| +| PostgreSQL | localhost:5432 | Database | +| MinIO | localhost:9000 | S3-compatible storage | +| MinIO Console | localhost:9001 | Storage management UI | +| Inngest | localhost:8288 | Workflow engine | +| Betterbase | localhost:3001 | API server | + +### Environment Variables + +For local development, the default values in `docker-compose.yml` should work. +Create a `.env` file if you need custom values: + +```bash +cp .env.example .env +``` + +## Production Self-Hosted + +Deploy all services on your own infrastructure: + +```bash +# 1. Build the project +bun run build + +# 2. Configure environment +cp .env.example .env +# Edit .env with your values + +# 3. Start all services +docker compose -f docker-compose.self-hosted.yml up -d +``` + +### Required Environment Variables + +```bash +# Generate a secure auth secret +AUTH_SECRET=$(openssl rand -base64 32) + +# Generate Inngest keys (optional for development) +INNGEST_SIGNING_KEY=$(openssl rand -hex 32) +INNGEST_EVENT_KEY=$(openssl rand -hex 16) +``` + +### Accessing Services + +| Service | URL | Credentials | +|---------|-----|--------------| +| Betterbase API | http://localhost | Through nginx | +| Dashboard | http://localhost | Admin login | +| MinIO Console | http://localhost:9001 | minioadmin/minioadmin_password | + +## Common Issues + +### PostgreSQL Connection Failed + +```bash +# Check if PostgreSQL is running +docker compose ps postgres + +# View logs +docker compose logs postgres +``` + +### MinIO Bucket Not Found + +The `minio-init` service creates the bucket automatically. If it fails: + +```bash +# Manually create bucket +docker compose exec minio mc alias set local http://localhost:9000 minioadmin minioadmin_password +docker compose exec minio mc mb local/betterbase +``` + +### Port Already in Use + +If a port is already bound: + +```bash +# Check what's using the port +lsof -i :5432 + +# Change the port in docker-compose.yml +``` + +### Build Fails with "Cannot find module" + +Make sure to run `bun install` before building: + +```bash +bun install +bun run build +``` + +### Permission Issues + +On Linux, you may need to set ownership: + +```bash +sudo chown -R $(id -u):$(id -g) . +``` + +## Docker Commands Reference + +```bash +# Start services +docker compose up -d + +# Stop services +docker compose down + +# Stop and remove volumes (clean slate) +docker compose down -v + +# View logs +docker compose logs -f + +# View logs for specific service +docker compose logs -f postgres + +# Restart a service +docker compose restart postgres + +# Rebuild a service +docker compose up -d --build betterbase-server +``` + +## Development vs Production + +| Feature | Development | Production | +|---------|-------------|------------| +| Runs locally | Yes | Self-hosted server | +| Hot reload | Yes (server runs in terminal) | No | +| Database | Docker PostgreSQL | Docker or managed | +| Storage | Docker MinIO | Docker, R2, S3, or B2 | +| SSL/TLS | Not needed | Required (use Traefik/Caddy) | +| Inngest | Dev mode | Production mode | + +## Alternative: External Services + +Instead of running everything with Docker, you can use managed services: + +```yaml +# docker-compose.production.yml +# Use external PostgreSQL (Neon, Supabase, RDS) +# Use external storage (Cloudflare R2, AWS S3) +``` + +See `docker-compose.production.yml` for a configuration that assumes external services. \ No newline at end of file diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index c28cb2f..a0b633c 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,14 +1,14 @@ # Installation -This guide covers how to install and set up BetterBase in your development environment. +This guide covers how to install and set up Betterbase in your development environment. ## Prerequisites -Before installing BetterBase, ensure you have the following: +Before installing Betterbase, ensure you have the following: -- **Bun** (v1.0+) - The JavaScript runtime powering BetterBase +- **Docker** & **Docker Compose** - For running infrastructure services +- **Bun** (v1.0+) - The JavaScript runtime powering Betterbase - **Git** - For version control -- **Node.js** (v18+) - Required for some optional tools ### Installing Bun @@ -34,6 +34,27 @@ Verify the installation: bun --version ``` +### Installing Docker + +BetterBase uses Docker for local development infrastructure (PostgreSQL, MinIO, Inngest). + +Install Docker Desktop for macOS/Windows, or on Linux: + +```bash +# Ubuntu/Debian +curl -fsSL https://get.docker.com | sh + +# Verify Docker +docker --version +docker compose version +``` + +Verify the installation: + +```bash +bun --version +``` + ## Installing BetterBase CLI The BetterBase CLI (`bb`) is your primary tool for managing projects and deployments. @@ -91,46 +112,53 @@ bun add @betterbase/client Create your first BetterBase project: ```bash -# Create a new project -bb init my-app - -# Navigate to the project -cd my-app +# Clone the repository +git clone https://github.com/betterbase/betterbase.git +cd betterbase # Install dependencies bun install + +# Start infrastructure (PostgreSQL, MinIO, Inngest) +docker compose up -d + +# Start development server with hot-reload +bun run dev ``` This creates the following project structure: ``` -my-app/ -├── betterbase.config.ts # Project configuration -├── drizzle.config.ts # Database configuration -├── src/ -│ ├── db/ -│ │ ├── schema.ts # Database schema -│ │ └── migrate.ts # Migration utilities -│ ├── functions/ # Serverless functions -│ ├── auth/ # Authentication setup -│ └── routes/ # API routes -└── package.json +betterbase/ +├── packages/ +│ ├── core/ # Core framework +│ ├── cli/ # CLI tools +│ ├── client/ # Client SDK +│ ├── server/ # Server implementation +│ └── shared/ # Shared utilities +├── apps/ +│ └── dashboard/ # Admin dashboard +├── docker-compose.yml # Local development services +└── docs/ # Documentation ``` -## Environment Setup +## Quick Start with Docker -### Development Environment - -For local development, BetterBase uses SQLite by default: +For the simplest setup, start infrastructure services with Docker: ```bash -# Start development server -bb dev +# Start PostgreSQL, MinIO, and Inngest +docker compose up -d + +# Run the server locally (with hot-reload) +bun run dev ``` -Your API will be available at `http://localhost:3000`. +Your API will be available at `http://localhost:3001`. + +See [Docker Setup Guide](../docker-setup.md) for detailed instructions. -### Production Environment +## Production Environment Set up environment variables for production: @@ -138,11 +166,11 @@ Set up environment variables for production: # Database DATABASE_URL=postgresql://user:password@host:5432/db -# Authentication +# Authentication - Generate: openssl rand -base64 32 AUTH_SECRET=your-secret-key-min-32-chars AUTH_URL=https://your-domain.com -# Storage (optional) +# Storage (optional - uses MinIO by default) STORAGE_PROVIDER=s3 STORAGE_BUCKET=your-bucket AWS_ACCESS_KEY_ID=your-key @@ -151,33 +179,31 @@ AWS_SECRET_ACCESS_KEY=your-secret See the [Configuration Guide](./configuration.md) for all available options. -## Supported Databases - -BetterBase supports multiple database providers: - -| Provider | Use Case | Connection String | -|----------|----------|-------------------| -| **SQLite** | Local development | `file:./dev.db` | -| **PostgreSQL** | Production | `postgres://...` | -| **Neon** | Serverless | `postgres://...` | -| **Turso** | Edge/Serverless | libSQL URL | -| **PlanetScale** | Serverless MySQL | MySQL URL | -| **Supabase** | Supabase hosted | `postgres://...` | - ## Verifying Your Setup -Run the health check to verify everything is working: +Once Docker services are running and the server is started: ```bash -# The development server should show: -# - http://localhost:3000 - API root -# - http://localhost:3000/graphql - GraphQL playground -# - http://localhost:3000/api/auth/* - Auth endpoints -# - http://localhost:3000/storage/* - Storage endpoints +# Check Docker services are healthy +docker compose ps + +# Check the server is running +curl http://localhost:3001/health ``` +You should see: +- Docker services: `postgres`, `minio`, `inngest` - all running +- Server health check: returns successful response + +Available endpoints: +- `http://localhost:3001` - API root +- `http://localhost:3001/graphql` - GraphQL playground +- `http://localhost:3001/api/auth/*` - Auth endpoints +- `http://localhost:3001/storage/*` - Storage endpoints + ## Next Steps - [Quick Start Guide](./quick-start.md) - Get running in 5 minutes - [Your First Project](./your-first-project.md) - Build a complete application - [Configuration](./configuration.md) - Customize your setup +- [Docker Setup Guide](../docker-setup.md) - Detailed Docker configuration diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index 1a0cf9b..aa55dcc 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -1,7 +1,9 @@ -FROM oven/bun:1.2-alpine AS builder +FROM oven/bun:1.3.9-alpine AS builder WORKDIR /app +RUN apk add --no-cache git + # Copy monorepo structure (only what server needs) COPY package.json turbo.json bun.lock ./ COPY packages/server/package.json ./packages/server/ @@ -18,12 +20,13 @@ COPY tsconfig.base.json ./ RUN cd packages/server && bun build src/index.ts --outdir dist --target bun # --- Runtime stage --- -FROM oven/bun:1.2-alpine +FROM oven/bun:1.3.9-alpine WORKDIR /app +RUN apk add --no-cache wget + COPY --from=builder /app/packages/server/dist ./dist -COPY --from=builder /app/packages/server/migrations ./migrations # Health check HEALTHCHECK --interval=10s --timeout=5s --start-period=30s --retries=3 \ From b9708168968924a7af5398e41da10be76908978c Mon Sep 17 00:00:00 2001 From: BroUnion Date: Sun, 29 Mar 2026 20:02:14 +0000 Subject: [PATCH 2/3] docs: update README and add CONTRIBUTING guide --- CONTRIBUTING.md | 84 +++++++++++++++++ README.md | 236 ++++++++++++++++++++++++++++-------------------- 2 files changed, 222 insertions(+), 98 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d4ca892 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,84 @@ +# Contributing to Betterbase + +Thank you for your interest in contributing to Betterbase! + +## Getting Started + +1. **Fork** the repository +2. **Clone** your fork: `git clone https://github.com/your-username/betterbase.git` +3. **Install** dependencies: `bun install` +4. **Create** a branch: `git checkout -b feature/my-feature` + +## Development Setup + +```bash +# Install dependencies +bun install + +# Build all packages +bun run build + +# Run tests +bun test + +# Run linting +bun run lint +``` + +## Code Style + +We use Biome for code formatting and linting: + +```bash +# Format code +bun run format + +# Lint code +bun run lint + +# Fix auto-fixable issues +bun run lint:fix +``` + +## Testing + +```bash +# Run all tests +bun test + +# Run tests for specific package +bun test --filter=@betterbase/cli + +# Run tests in watch mode +bun test --watch +``` + +## Commit Messages + +Follow Conventional Commits: + +``` +feat: add new feature +fix: resolve bug +docs: update documentation +refactor: restructure code +test: add tests +chore: maintenance +``` + +## Submitting Changes + +1. Push your branch: `git push origin feature/my-feature` +2. Open a **Pull Request** +3. Fill out the PR template +4. Wait for review + +## Good First Issues + +Looking for a way to contribute? Check out our [Good First Issues](https://github.com/weroperking/Betterbase/labels/good-first-issue) label on GitHub. + +## Community + +Join our community: +- **Discord**: https://discord.gg/R6Dm6Cgy2E +- **GitHub Discussions**: https://github.com/weroperking/Betterbase/discussions diff --git a/README.md b/README.md index 15febfb..e4f7190 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,71 @@ -# Betterbase -
+[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/weroperking/Betterbase) + +``` +██████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗ ███████╗ ██████╗ ██╗ ██╗███████╗ +██╔══██╗██║ ██║██╔════╝██╔═══██╗██║ ██╔════╝ ██╔═══██╗██║ ██║██╔════╝ +██████╔╝███████║██║ ██║ ██║██║ █████╗ ██║ ██║██║ █╗ ██║█████╗ +██╔══██╗██╔══██║██║ ██║ ██║██║ ██╔══╝ ██║ ██║██║███╗██║██╔══╝ +██║ ██║██║ ██║╚██████╗╚██████╔╝███████╗███████╗ ╚██████╔╝╚███╔███╔╝███████╗ +╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚══╝ ╚══╝ ╚══════╝ +``` + **The AI-Native Backend-as-a-Service Platform** -Betterbase is an open-source alternative to Supabase, built with Bun for blazing-fast performance. It provides database, authentication, realtime subscriptions, storage, and serverless functions with sub-100ms local dev using Bun + SQLite. +Blazing-fast backend development with Sub-100ms Local Dev — Built on Bun + SQLite, deploy anywhere with PostgreSQL support. -**Last Updated: 2026-03-28** +*Database • Authentication • Realtime Subscriptions • Storage • Serverless Functions • Vector Search* -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/weroperking/Betterbase) +**Last Updated: 2026-03-29**
--- -## Why Betterbase? - -Traditional backend development is slow. You spend weeks setting up databases, authentication, APIs, and infrastructure before writing business logic. Betterbase changes that. - -``` -┌────────────────────────────────────────────────────────────────────────────────┐ -│ BETTERBASE ARCHITECTURE │ -├────────────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────┐ ┌──────-──────────────────────┐ ┌────────────┐ │ -│ │ Frontend │ │ Betterbase Core │ │ Database │ │ -│ │ (React, │─────▶ | │───▶│ (SQLite, │ │ -│ │ Vue, │ │ Auth │ Realtime │ Storage │ │ Postgres)│ │ -│ │ Mobile) │ │ RLS │ Vector │ Functions│ └────────────┘ │ -│ └─────────────────┘ └────────────────────────────┘ │ -│ │ │ -│ ┌──────▼──────┐ │ -│ │ IaC Layer │ (Convex-inspired) │ -│ │ betterbase/ │ (Convex-inspired) │ -│ └─────────────┘ │ -└────────────────────────────────────────────────────────────────────────────────┘ -``` +## Why Choose Betterbase? + +``` +┌─────────────────────────────────────────────────────────────────────────────────────────────┐ +│ ✦ BETTERBASE ARCHITECTURE ✦ │ +├─────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────────────────────┐ ┌─────────┐ │ +│ │ Frontend │ │ │ │ │ │ +│ │ (React, Vue, │──────────▶│ BETTERBASE CORE │──────────▶│ DB │ │ +│ │ Mobile, │ │ │ │ SQLite/ │ │ +│ │ Svelte) │ │ Auth │ Realtime │ Storage │ │ Postgres│ │ +│ └──────────────┘ │ RLS │ Vector │ Fns │ └─────────┘ │ +│ └──────────────────────────────┘ │ │ +│ │ │ │ +│ ┌──────▼──────┐ │ │ +│ │ IaC │◀──── (Infrastructure as Code) │ │ +│ │ Layer │ │ │ +│ │ Convex-ish │ │ │ +│ └───────────┘ │ │ +│ │ │ +│ ┌──────▼──────┐│ +│ │ Inngest ││ +│ │ Workflows ││ +│ └────────────┘│ +└─────────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +| | TraditionalBAAS | Betterbase | +|--|------------------|------------| +| ⚡ | Slow local dev | **Sub-100ms dev** with Bun + SQLite | +| 🗄️ | Black box DB | **Full PostgreSQL** with raw SQL access | +| 🔍 | Basic search | **Full-text + Vector search** built-in | +| 🚀 | Cloud lock-in | **Self-host anywhere** with Docker | +| 📊 | Limited analytics | **Full observability** out of the box | +| 🔐 | Closed source | **100% open source** - deploy anywhere | --- ## Quick Start ```bash -# Install CLI +# Install the CLI bun install -g @betterbase/cli # Create a new project (IaC mode - recommended) @@ -52,36 +75,6 @@ bun install bb dev ``` -## Inngest Integration - -Betterbase uses [Inngest](https://www.inngest.com/) for durable workflows and background jobs. - -### Deployment Modes - -| Mode | Inngest Backend | Used By | -|------|----------------|---------| -| Cloud | `https://api.inngest.com` | BetterBase Cloud offering | -| Self-Hosted | `http://inngest:8288` | Docker deployment | -| Local Dev | `http://localhost:8288` | Development and testing | - -### Environment Variables - -```bash -# For local development -INNGEST_BASE_URL=http://localhost:8288 - -# For self-hosted production -INNGEST_BASE_URL=http://inngest:8288 -INNGEST_SIGNING_KEY=your-signing-key -INNGEST_EVENT_KEY=your-event-key -``` - -### Features - -- **Webhook Delivery**: Retryable, observable webhook delivery with automatic backoff -- **Notification Rules**: Cron-based metric polling with fan-out notifications -- **Background Exports**: Async CSV export with progress tracking - Your project structure: ``` @@ -163,22 +156,7 @@ Your backend runs at `http://localhost:3000`. The dashboard is at `http://localh --- -## BetterBase vs Convex - -| Feature | Convex | BetterBase | -|---------|--------|------------| -| Database | Black box | Full PostgreSQL | -| Raw SQL | Not available | `ctx.db.execute()` | -| Full-Text Search | Not built-in | PostgreSQL FTS | -| Vector Search | Limited | pgvector + HNSW | -| Self-Hosting | Not supported | Docker to your infra | -| Migration | — | `bb migrate from-convex` | - -**BetterBase gives you Convex simplicity with full SQL power.** - ---- - -## Features +## Key Features | Feature | Description | |---------|-------------| @@ -198,9 +176,56 @@ Your backend runs at `http://localhost:3000`. The dashboard is at `http://localh --- +## Betterbase vs Convex + +| Feature | Convex | Betterbase | +|---------|--------|------------| +| Database | Black box | Full PostgreSQL | +| Raw SQL | Not available | `ctx.db.execute()` | +| Full-Text Search | Not built-in | PostgreSQL FTS | +| Vector Search | Limited | pgvector + HNSW | +| Self-Hosting | Not supported | Docker to your infra | +| Migration | — | `bb migrate from-convex` | + +**Betterbase gives you Convex simplicity with full SQL power.** + +--- + +## Inngest Integration + +Betterbase uses [Inngest](https://www.inngest.com/) for durable workflows and background jobs. + +### Deployment Modes + +| Mode | Inngest Backend | Used By | +|------|----------------|---------| +| Cloud | `https://api.inngest.com` | BetterBase Cloud offering | +| Self-Hosted | `http://inngest:8288` | Docker deployment | +| Local Dev | `http://localhost:8288` | Development and testing | + +### Environment Variables + +```bash +# For local development +INNGEST_BASE_URL=http://localhost:8288 + +# For self-hosted production +INNGEST_BASE_URL=http://inngest:8288 +INNGEST_SIGNING_KEY=your-signing-key +INNGEST_EVENT_KEY=your-event-key +``` + +### Features + +- **Webhook Delivery**: Retryable, observable webhook delivery with automatic backoff +- **Notification Rules**: Cron-based metric polling with fan-out notifications +- **Background Exports**: Async CSV export with progress tracking + +--- + ## Project Structure -BetterBase supports two patterns: +Betterbase supports two patterns: ### 1. IaC Pattern (Recommended) @@ -211,7 +236,7 @@ my-app/ │ ├── queries/ # query() functions │ ├── mutations/ # mutation() functions │ ├── actions/ # action() functions -│ └── cron.ts # scheduled functions +│ └── cron.ts # scheduled functions ├── betterbase.config.ts # Optional config └── package.json ``` @@ -225,7 +250,7 @@ my-app/ │ │ ├── schema.ts # Drizzle schema │ │ └── migrate.ts # Migration runner │ ├── routes/ # Hono routes -│ └── functions/ # Serverless functions +│ └── functions/ # Serverless functions ├── betterbase.config.ts └── package.json ``` @@ -397,6 +422,28 @@ This ensures users can only access their own data. --- +## Ask Deepwiki + +> *Your AI-powered development assistant, integrated directly into Betterbase.* + +Ask Deepwiki provides intelligent context for AI-assisted development: + +- **Smart Code Context**: Automatic `.betterbase-context.json` generation +- **IaC Analysis**: Understand your schema, queries, and mutations +- **Query Optimization**: Get recommendations for better performance +- **Documentation Generation**: Auto-generate docs from your code + +**Deepwiki Badge**: The badge at the top of this README links to [Ask Deepwiki](https://deepwiki.com/weroperking/Betterbase), where you can chat with an AI that understands your entire Betterbase project. + +### Using Ask Deepwiki + +1. **Development**: Get instant answers about your IaC layer +2. **Debugging**: Understand query behavior and optimization +3. **Onboarding**: New team members can ask about your architecture +4. **Refactoring**: Get AI suggestions for improving your code + +--- + ## Contributing We welcome contributions! Please follow these steps: @@ -431,11 +478,11 @@ betterbase/ ├── apps/ │ └── test-project/ # Example/test project ├── packages/ -│ ├── cli/ # @betterbase/cli -│ ├── client/ # @betterbase/client -│ └── core/ # @betterbase/core -├── templates/ # Project templates -└── turbo.json # Turborepo configuration +│ ├── cli/ # @betterbase/cli +│ ├── client/ # @betterbase/client +│ └── core/ # @betterbase/core +├── templates/ # Project templates +└── turbo.json # Turborepo configuration ``` ### Code Style @@ -521,6 +568,7 @@ All notable changes to this project will be documented in this section. ### [1.0.0] - 2026-03-19 #### Added + - **AI Context Generation**: Automatic `.betterbase-context.json` generation for AI-assisted development - **Branch Management**: New `bb branch` command for creating isolated preview environments - **Vector Search**: pgvector-powered similarity search with embeddings support @@ -528,12 +576,14 @@ All notable changes to this project will be documented in this section. - **Enhanced CLI**: Added 12 commands including branch, webhook management, and storage operations #### Updated + - Updated copyright year to 2026 - Improved documentation with Last Updated timestamp - Verified all features against current codebase structure - Removed deprecated @betterbase/shared package references #### Security + - Improved webhook signature verification - Enhanced RLS policy engine @@ -575,26 +625,16 @@ SOFTWARE. | Resource | Link | |----------|------| -| **Documentation** | [docs.betterbase.io](https://docs.betterbase.io) | -| **Discord** | [discord.gg/betterbase](https://discord.gg/betterbase) | -| **GitHub Issues** | [github.com/betterbase/betterbase/issues](https://github.com/betterbase/betterbase/issues) | -| **Stack Overflow** | [stackoverflow.com/questions/tagged/betterbase](https://stackoverflow.com/questions/tagged/betterbase) | - -### Stay Updated - -| Channel | Link | -|---------|------| -| **Twitter** | [@betterbase](https://twitter.com/betterbase) | -| **Blog** | [blog.betterbase.io](https://blog.betterbase.io) | -| **Newsletter** | [subscribe.betterbase.io](https://subscribe.betterbase.io) | +| **Discord** | [Discord](https://discord.gg/R6Dm6Cgy2E) | +| **GitHub Issues** | [GitHub Issues](https://github.com/weroperking/Betterbase/issues) | ### Contribute | Resource | Link | |----------|------| -| **GitHub** | [github.com/betterbase/betterbase](https://github.com/betterbase/betterbase) | +| **GitHub** | [GitHub](https://github.com/weroperking/Betterbase) | | **Contributing Guide** | [CONTRIBUTING.md](CONTRIBUTING.md) | -| **Good First Issues** | [github.com/betterbase/betterbase/labels/good%20first%20issue](https://github.com/betterbase/betterbase/labels/good%20first%20issue) | +| **Good First Issues** | [Good First Issues](https://github.com/weroperking/Betterbase/labels/good-first-issue) | --- @@ -602,6 +642,6 @@ SOFTWARE. **Built with ❤️ by Weroperking** -[Website](https://betterbase.io) • [Documentation](https://docs.betterbase.io) • [Discord](https://discord.gg/betterbase) • [Twitter](https://twitter.com/betterbase) +[Website](#) • [Documentation](docs/README.md) • [Discord](https://discord.gg/R6Dm6Cgy2E) • [GitHub](https://github.com/weroperking/Betterbase) • [Twitter](#) - + \ No newline at end of file From 96560987f06890e17fc28396050a14b7b562c70d Mon Sep 17 00:00:00 2001 From: BroUnion Date: Sun, 29 Mar 2026 20:31:43 +0000 Subject: [PATCH 3/3] fix: docker local setup improvements - .env.example: Add trailing newline, use dynamic DATABASE_URL template, rename auth vars to match env.ts schema (BETTERBASE_JWT_SECRET, BETTERBASE_PUBLIC_URL, CORS_ORIGINS) - docker-compose.yml: Use env var interpolation for MinIO credentials, add minio-init service for automatic bucket creation - docker-compose.self-hosted.yml: Pin MinIO images to specific releases, rename auth env vars, add dashboard build step documentation - apps/dashboard/Dockerfile: Build specifically for dashboard with correct WORKDIR and COPY paths, add non-root nginx user, healthcheck endpoint, and /health location in nginx config - packages/server/Dockerfile: Pin wget to Alpine 3.22 version 1.25.0-r1 - docs/docker-setup.md: Clarify MinIO credentials for local-dev vs self-hosted environments - docs/getting-started/installation.md: Add text language specifier to project tree code block for MD040 compliance --- .env.example | 10 +++++----- apps/dashboard/Dockerfile | 20 +++++++++++++++++--- docker-compose.self-hosted.yml | 18 ++++++++++-------- docker-compose.yml | 18 ++++++++++++++++-- docs/docker-setup.md | 10 +++++++--- docs/getting-started/installation.md | 2 +- packages/server/Dockerfile | 2 +- 7 files changed, 57 insertions(+), 23 deletions(-) diff --git a/.env.example b/.env.example index d410697..7947d04 100644 --- a/.env.example +++ b/.env.example @@ -14,14 +14,14 @@ POSTGRES_DB=betterbase # Connection string for applications # Format: postgresql://user:password@host:port/database -DATABASE_URL=postgresql://betterbase:your_secure_password_here@localhost:5432/betterbase +DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB} # ---------------------------------------------------------------------------- # Authentication # ---------------------------------------------------------------------------- # Generate a secure secret: openssl rand -base64 32 -AUTH_SECRET=your-super-secret-key-min-32-chars-long -AUTH_URL=http://localhost:3000 +BETTERBASE_JWT_SECRET=your-super-secret-key-min-32-chars-long +BETTERBASE_PUBLIC_URL=http://localhost:3000 # ---------------------------------------------------------------------------- # MinIO (S3-compatible storage for local development) @@ -50,7 +50,7 @@ NODE_ENV=development PORT=3001 HOST=0.0.0.0 -CORS_ORIGIN=http://localhost:3000,http://localhost:5173 +CORS_ORIGINS=http://localhost:3000,http://localhost:5173 LOG_LEVEL=debug @@ -95,4 +95,4 @@ LOG_LEVEL=debug # Vector Search (optional) # ---------------------------------------------------------------------------- # VECTOR_PROVIDER=openai -# OPENAI_API_KEY=your-openai-api-key \ No newline at end of file +# OPENAI_API_KEY=your-openai-api-key diff --git a/apps/dashboard/Dockerfile b/apps/dashboard/Dockerfile index 5dd1cd0..45e3c23 100644 --- a/apps/dashboard/Dockerfile +++ b/apps/dashboard/Dockerfile @@ -10,9 +10,9 @@ FROM oven/bun:1.3.9-debian AS builder -WORKDIR /app +WORKDIR /app/apps/dashboard -COPY package.json bun.lock* ./ +COPY apps/dashboard/package.json apps/dashboard/bun.lock* ./ RUN bun install --frozen-lockfile @@ -25,7 +25,11 @@ RUN bun run build FROM nginx:alpine -COPY --from=builder /app/dist /usr/share/nginx/html +RUN addgroup -g 101 -S nginx && adduser -S nginx -u 101 + +COPY --from=builder /app/apps/dashboard/dist /usr/share/nginx/html + +RUN chown -R nginx:nginx /usr/share/nginx/html RUN cat > /etc/nginx/conf.d/default.conf << 'EOF' server { @@ -34,6 +38,12 @@ server { root /usr/share/nginx/html; index index.html; + # Health check endpoint + location /health { + return 200 'OK'; + add_header Content-Type text/plain; + } + # Cache static assets location /assets/ { expires 1y; @@ -53,4 +63,8 @@ EOF EXPOSE 80 +HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 CMD wget -qO- http://localhost:80/health || exit 1 + +USER nginx + CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker-compose.self-hosted.yml b/docker-compose.self-hosted.yml index 1bbd9b6..2f22a27 100644 --- a/docker-compose.self-hosted.yml +++ b/docker-compose.self-hosted.yml @@ -5,9 +5,11 @@ # No external dependencies required. # # Usage: -# 1. Build the project: bun run build -# 2. cp .env.example .env -# 3. docker compose -f docker-compose.self-hosted.yml up -d +# 1. Build the dashboard: bun --cwd apps/dashboard run build +# (Produces ./apps/dashboard/dist - required before starting) +# 2. Build the server: bun run build +# 3. cp .env.example .env +# 4. docker compose -f docker-compose.self-hosted.yml up -d # # Services: # - PostgreSQL: http://localhost:5432 @@ -37,7 +39,7 @@ services: - betterbase-internal minio: - image: minio/minio:latest + image: minio/minio:RELEASE.2024-11-07T19-31-41Z container_name: betterbase-minio restart: unless-stopped command: server /data --console-address ":9001" @@ -55,7 +57,7 @@ services: - betterbase-internal minio-init: - image: minio/mc:latest + image: minio/mc:RELEASE.2024-11-08T03-47-05Z container_name: betterbase-minio-init depends_on: minio: @@ -103,15 +105,15 @@ services: condition: service_healthy environment: DATABASE_URL: postgresql://${POSTGRES_USER:-betterbase}:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/${POSTGRES_DB:-betterbase} - AUTH_SECRET: ${AUTH_SECRET:?JWT secret required - set AUTH_SECRET in .env} - AUTH_URL: ${AUTH_URL:-http://localhost:3000} + BETTERBASE_JWT_SECRET: ${BETTERBASE_JWT_SECRET:?JWT secret required - set BETTERBASE_JWT_SECRET in .env} + BETTERBASE_PUBLIC_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost:3000} STORAGE_ENDPOINT: http://minio:9000 STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin} STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin} STORAGE_BUCKET: betterbase PORT: "3001" NODE_ENV: production - CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost} + CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost} INNGEST_BASE_URL: http://inngest:8288 INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY:-} INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY:-} diff --git a/docker-compose.yml b/docker-compose.yml index ed4d91c..111aa14 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,8 +36,8 @@ services: restart: unless-stopped command: server /data --console-address ":9001" environment: - MINIO_ROOT_USER: betterbase - MINIO_ROOT_PASSWORD: betterbase_dev_password + MINIO_ROOT_USER: ${MINIO_ROOT_USER:-betterbase} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-betterbase_dev_password} ports: - "9000:9000" - "9001:9001" @@ -49,6 +49,20 @@ services: timeout: 5s retries: 5 + # MinIO Init (Create bucket on startup) + minio-init: + image: minio/mc:latest + container_name: betterbase-minio-init-local + depends_on: + minio: + condition: service_healthy + entrypoint: > + /bin/sh -c " + mc alias set local http://minio:9000 ${MINIO_ROOT_USER:-betterbase} ${MINIO_ROOT_PASSWORD:-betterbase_dev_password}; + mc mb --ignore-existing local/betterbase; + echo 'MinIO bucket initialized.'; + " + # Inngest (Durable Workflow Engine) inngest: image: inngest/inngest:v1.17.5 diff --git a/docs/docker-setup.md b/docs/docker-setup.md index a0e0b80..1a6287d 100644 --- a/docs/docker-setup.md +++ b/docs/docker-setup.md @@ -68,7 +68,7 @@ INNGEST_EVENT_KEY=$(openssl rand -hex 16) |---------|-----|--------------| | Betterbase API | http://localhost | Through nginx | | Dashboard | http://localhost | Admin login | -| MinIO Console | http://localhost:9001 | minioadmin/minioadmin_password | +| MinIO Console | http://localhost:9001 | Local dev: `betterbase/betterbase_dev_password`
Self-hosted: `minioadmin/minioadmin` | ## Common Issues @@ -87,8 +87,12 @@ docker compose logs postgres The `minio-init` service creates the bucket automatically. If it fails: ```bash -# Manually create bucket -docker compose exec minio mc alias set local http://localhost:9000 minioadmin minioadmin_password +# For local development (docker-compose.yml) +docker compose exec minio mc alias set local http://localhost:9000 betterbase betterbase_dev_password +docker compose exec minio mc mb local/betterbase + +# For self-hosted (docker-compose.self-hosted.yml) +docker compose exec minio mc alias set local http://localhost:9000 minioadmin minioadmin docker compose exec minio mc mb local/betterbase ``` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index a0b633c..d127bc4 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -128,7 +128,7 @@ bun run dev This creates the following project structure: -``` +```text betterbase/ ├── packages/ │ ├── core/ # Core framework diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index aa55dcc..bd832bc 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -24,7 +24,7 @@ FROM oven/bun:1.3.9-alpine WORKDIR /app -RUN apk add --no-cache wget +RUN apk add --no-cache wget=1.25.0-r1 COPY --from=builder /app/packages/server/dist ./dist