diff --git a/.env.example b/.env.example index d286b4c..f097000 100644 --- a/.env.example +++ b/.env.example @@ -12,17 +12,19 @@ POSTGRES_USER=betterbase POSTGRES_PASSWORD=your_secure_password_here POSTGRES_DB=betterbase -DATABASE_URL=postgresql://betterbase:your_secure_password_here@localhost:5432/betterbase +# Connection string for applications +# Format: postgresql://user:password@host:port/database +DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB} # ---------------------------------------------------------------------------- # Authentication # ---------------------------------------------------------------------------- -# Generate: openssl rand -base64 32 -AUTH_SECRET=your-super-secret-key-min-32-chars-long -AUTH_URL=http://localhost:3000 +# Generate a secure secret: openssl rand -base64 32 +BETTERBASE_JWT_SECRET=your-super-secret-key-min-32-chars-long +BETTERBASE_PUBLIC_URL=http://localhost:3000 # ---------------------------------------------------------------------------- -# MinIO (S3-compatible storage) +# MinIO (S3-compatible storage for local development) # ---------------------------------------------------------------------------- MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=minioadmin_password @@ -36,9 +38,9 @@ STORAGE_BUCKET=betterbase # Inngest (Durable Workflow Engine) # ---------------------------------------------------------------------------- INNGEST_LOG_LEVEL=info -# Generate: openssl rand -hex 32 +# Generate signing key: openssl rand -hex 32 INNGEST_SIGNING_KEY= -# Generate: openssl rand -hex 16 +# Generate event key: openssl rand -hex 16 INNGEST_EVENT_KEY= # ---------------------------------------------------------------------------- @@ -48,19 +50,21 @@ 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 # ---------------------------------------------------------------------------- -# Storage (S3-compatible - for production with external services) +# Production Settings # ---------------------------------------------------------------------------- -# STORAGE_PROVIDER=r2 -# STORAGE_BUCKET=betterbase-storage -# STORAGE_REGION=auto +# 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_ID=your-access-key -# STORAGE_SECRET_ACCESS_KEY=your-secret-key +# STORAGE_ACCESS_KEY=your-access-key +# STORAGE_SECRET_KEY=your-secret-key # ---------------------------------------------------------------------------- # Email (optional) @@ -83,12 +87,15 @@ LOG_LEVEL=debug # ---------------------------------------------------------------------------- # Phone Auth (optional - Twilio) # ---------------------------------------------------------------------------- -# TWILIO_ACCOUNT_SID=your-twilio-sid -# TWILIO_AUTH_TOKEN=your-twilio-token -# TWILIO_PHONE_NUMBER=+1234567890 +# 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 # ---------------------------------------------------------------------------- # 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/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 diff --git a/apps/dashboard/Dockerfile b/apps/dashboard/Dockerfile index 5cf0545..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,15 +38,24 @@ 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; 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; } @@ -50,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.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 f792916..e2ad9cd 100644 --- a/docker-compose.self-hosted.yml +++ b/docker-compose.self-hosted.yml @@ -5,16 +5,18 @@ # No external dependencies required. # # Usage: -# 1. Build: bun run build -# 2. cp .env.example .env && edit .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: localhost:5432 -# - MinIO: localhost:9000 (console: localhost:9001) -# - Inngest: localhost:8288 -# - Server: localhost:3001 -# - Dashboard: localhost (via nginx) +# - 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: @@ -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: @@ -98,8 +100,8 @@ services: condition: service_started 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} diff --git a/docker-compose.yml b/docker-compose.yml index e76a2c1..111aa14 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ # Betterbase server runs locally with hot-reload. # # Usage: -# docker compose up -d +# docker compose up -d postgres minio inngest # bun run dev # ============================================================================ @@ -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 8148b17..88c0a43 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 ``` @@ -154,4 +158,16 @@ docker compose up -d --build betterbase-server | 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 | \ No newline at end of file +| 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. diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 6219169..6482dce 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -49,6 +49,12 @@ 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. @@ -122,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 53a5941..9a74de5 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -4,6 +4,7 @@ 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/ COPY packages/core/package.json ./packages/core/ @@ -18,11 +19,12 @@ COPY tsconfig.base.json ./ RUN cd packages/server && bun build src/index.ts --outdir dist --target bun +# --- Runtime stage --- 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