| 1 | # Grove — Full Development Stack |
| 2 | # |
| 3 | # Quick start: |
| 4 | # 1. Build Mononoke: cd sapling && docker build -f ../docker/Dockerfile.mononoke -t grove/mononoke . |
| 5 | # 2. Import a repo: ./scripts/import-repo.sh /path/to/git/repo grove |
| 6 | # 3. Start: docker compose up |
| 7 | # |
| 8 | # Or run just the app layer while developing: |
| 9 | # docker compose up grove-hub-api grove-api grove-web |
| 10 | |
| 11 | services: |
| 12 | # ─── Mononoke Layer ─────────────────────────────────────────────── |
| 13 | |
| 14 | # SLAPI Server — Sapling Remote API (primary data API) |
| 15 | mononoke-slapi: |
| 16 | image: ghcr.io/letterpress-labs/grove-mononoke:latest |
| 17 | container_name: grove-mononoke-slapi |
| 18 | command: |
| 19 | - --listening-host-port |
| 20 | - "0.0.0.0:8443" |
| 21 | - --config-path |
| 22 | - /config |
| 23 | - --test-instance |
| 24 | ports: |
| 25 | - "8443:8443" |
| 26 | volumes: |
| 27 | - ../config/mononoke:/config:ro |
| 28 | - mononoke-data:/data/mononoke |
| 29 | - ../config/certs:/certs:ro |
| 30 | healthcheck: |
| 31 | test: ["CMD", "curl", "-sf", "http://localhost:8443/health_check"] |
| 32 | interval: 10s |
| 33 | timeout: 5s |
| 34 | retries: 3 |
| 35 | restart: unless-stopped |
| 36 | |
| 37 | # Git Server — standard Git HTTP protocol for clone/push/pull |
| 38 | mononoke-git: |
| 39 | image: ghcr.io/letterpress-labs/grove-mononoke:latest |
| 40 | container_name: grove-mononoke-git |
| 41 | entrypoint: ["/usr/local/bin/git_server"] |
| 42 | command: |
| 43 | - --listening-host-port |
| 44 | - "0.0.0.0:8080" |
| 45 | - --config-path |
| 46 | - /config |
| 47 | - --test-instance |
| 48 | ports: |
| 49 | - "8080:8080" |
| 50 | volumes: |
| 51 | - ../config/mononoke:/config:ro |
| 52 | - mononoke-data:/data/mononoke |
| 53 | - ../config/certs:/certs:ro |
| 54 | depends_on: |
| 55 | mononoke-slapi: |
| 56 | condition: service_healthy |
| 57 | restart: unless-stopped |
| 58 | |
| 59 | # ─── Grove App Layer ────────────────────────────────────────────── |
| 60 | |
| 61 | # Hub API — identity provider (WebAuthn passkeys, PATs, instance management) |
| 62 | grove-hub-api: |
| 63 | build: |
| 64 | context: .. |
| 65 | dockerfile: docker/Dockerfile.grove-hub-api |
| 66 | container_name: grove-hub-api |
| 67 | ports: |
| 68 | - "4001:4000" |
| 69 | volumes: |
| 70 | - hub-data:/data |
| 71 | environment: |
| 72 | - PORT=4000 |
| 73 | - DATABASE_PATH=/data/hub.db |
| 74 | - JWT_SECRET=${JWT_SECRET:-grove-dev-secret} |
| 75 | - RP_ID=localhost |
| 76 | - ORIGIN=http://localhost:3000 |
| 77 | - CORS_ORIGIN=http://localhost:3000 |
| 78 | restart: unless-stopped |
| 79 | |
| 80 | # Instance API — repo browsing, diffs, CI/CD runner (verifies hub-signed JWTs) |
| 81 | grove-api: |
| 82 | build: |
| 83 | context: .. |
| 84 | dockerfile: docker/Dockerfile.grove-api |
| 85 | container_name: grove-api |
| 86 | ports: |
| 87 | - "4000:4000" |
| 88 | volumes: |
| 89 | - grove-data:/data |
| 90 | - repo-mirrors:/data/repos |
| 91 | environment: |
| 92 | - PORT=4000 |
| 93 | - DATABASE_PATH=/data/grove.db |
| 94 | - GROVE_HUB_API_URL=http://grove-hub-api:4000 |
| 95 | - MONONOKE_GIT_URL=http://mononoke-git:8080 |
| 96 | - REPOS_DIR=/data/repos |
| 97 | - JWT_SECRET=${JWT_SECRET:-grove-dev-secret} |
| 98 | - CORS_ORIGIN=http://localhost:3000 |
| 99 | healthcheck: |
| 100 | test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4000/health"] |
| 101 | interval: 10s |
| 102 | timeout: 3s |
| 103 | start_period: 15s |
| 104 | retries: 3 |
| 105 | depends_on: |
| 106 | mononoke-git: |
| 107 | condition: service_started |
| 108 | restart: unless-stopped |
| 109 | |
| 110 | # Web UI — Next.js frontend |
| 111 | grove-web: |
| 112 | build: |
| 113 | context: .. |
| 114 | dockerfile: docker/Dockerfile.grove-web |
| 115 | container_name: grove-web |
| 116 | ports: |
| 117 | - "3000:3000" |
| 118 | environment: |
| 119 | - GROVE_API_URL=http://grove-api:4000 |
| 120 | - GROVE_HUB_API_URL=http://grove-hub-api:4000 |
| 121 | depends_on: |
| 122 | - grove-api |
| 123 | - grove-hub-api |
| 124 | restart: unless-stopped |
| 125 | |
| 126 | volumes: |
| 127 | mononoke-data: |
| 128 | driver: local |
| 129 | hub-data: |
| 130 | driver: local |
| 131 | grove-data: |
| 132 | driver: local |
| 133 | repo-mirrors: |
| 134 | driver: local |
| 135 | |