diff --git a/.env.example b/.env.example index bd4dce6d..3888db48 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,23 @@ # Postgres -POSTGRES_USER= -POSTGRES_PASSWORD= +# These defaults match docker-compose.infra.yml, which is the stack +# launched by `./infra/scripts/setup.sh`. Override for production. +POSTGRES_USER=dev +POSTGRES_PASSWORD=dev POSTGRES_DB=molecule -DATABASE_URL=postgres://USER:PASS@postgres:5432/molecule?sslmode=disable +# DATABASE_URL points at the host-published Postgres port so that +# `go run ./cmd/server` on the host (the README quickstart path) can +# connect. When running the platform *inside* docker-compose.yml, the +# compose file builds a DATABASE_URL with host `postgres` automatically +# from POSTGRES_USER/PASSWORD/DB above — that path ignores this value. +DATABASE_URL=postgres://dev:dev@localhost:5432/molecule?sslmode=disable -# Redis -REDIS_URL=redis://redis:6379 +# Redis — same host-vs-container story as DATABASE_URL above. +REDIS_URL=redis://localhost:6379 # Platform +# PORT only applies to the Go platform (workspace-server). The Canvas pins +# itself to 3000 in canvas/package.json, so sourcing this file before +# `npm run dev` won't accidentally make Next.js try to bind 8080. PORT=8080 # ---- Admin credential — REQUIRED to close issue #684 (AdminAuth bearer bypass) ---- # When ADMIN_TOKEN is set, only this value is accepted on /admin/* and /approvals/* routes. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efa043f8..dd8ce1a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: echo "platform=$(echo "$DIFF" | grep -qE '^workspace-server/|^\.github/workflows/ci\.yml$' && echo true || echo false)" >> "$GITHUB_OUTPUT" echo "canvas=$(echo "$DIFF" | grep -qE '^canvas/|^\.github/workflows/ci\.yml$' && echo true || echo false)" >> "$GITHUB_OUTPUT" echo "python=$(echo "$DIFF" | grep -qE '^workspace/|^\.github/workflows/ci\.yml$' && echo true || echo false)" >> "$GITHUB_OUTPUT" - echo "scripts=$(echo "$DIFF" | grep -qE '^tests/e2e/|^scripts/|^\.github/workflows/ci\.yml$' && echo true || echo false)" >> "$GITHUB_OUTPUT" + echo "scripts=$(echo "$DIFF" | grep -qE '^tests/e2e/|^scripts/|^infra/scripts/|^\.github/workflows/ci\.yml$' && echo true || echo false)" >> "$GITHUB_OUTPUT" platform-build: name: Platform (Go) @@ -207,10 +207,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Run shellcheck on tests/e2e/*.sh + - name: Run shellcheck on tests/e2e/*.sh and infra/scripts/*.sh # shellcheck is pre-installed on ubuntu-latest runners (via apt). + # infra/scripts/ is included because setup.sh + nuke.sh gate the + # README quickstart — a shellcheck regression there silently breaks + # new-user onboarding. scripts/ is intentionally excluded until its + # pre-existing SC3040/SC3043 warnings are cleaned up. run: | - find tests/e2e -type f -name '*.sh' -print0 \ + find tests/e2e infra/scripts -type f -name '*.sh' -print0 \ | xargs -0 shellcheck --severity=warning canvas-deploy-reminder: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7edfcb9d..e7cf4d45 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,16 +17,19 @@ development workflow, conventions, and how to get your changes merged. ```bash # Clone the repo -git clone https://github.com/Molecule-AI/molecule-monorepo.git -cd molecule-monorepo +git clone https://github.com/Molecule-AI/molecule-core.git +cd molecule-core # Install git hooks git config core.hooksPath .githooks +# Copy and edit .env (generate ADMIN_TOKEN + SECRETS_ENCRYPTION_KEY) +cp .env.example .env + # Start infrastructure (Postgres, Redis, Langfuse, Temporal) ./infra/scripts/setup.sh -# Build and run the platform +# Build and run the platform — applies pending migrations on first boot cd workspace-server go run ./cmd/server diff --git a/README.md b/README.md index c550c434..5bd76ae7 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ Workspace Runtime

-[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https://github.com/Molecule-AI/molecule-monorepo) -[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/Molecule-AI/molecule-monorepo) +[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https://github.com/Molecule-AI/molecule-core) +[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/Molecule-AI/molecule-core) @@ -249,8 +249,12 @@ Workspace Runtime (Python image with adapters) ## Quick Start ```bash -git clone https://github.com/Molecule-AI/molecule-monorepo.git -cd molecule-monorepo +git clone https://github.com/Molecule-AI/molecule-core.git +cd molecule-core + +cp .env.example .env +# Defaults boot the stack locally out of the box. See .env.example for +# production hardening knobs (ADMIN_TOKEN, SECRETS_ENCRYPTION_KEY, etc.). ./infra/scripts/setup.sh # Boots Postgres (:5432), Redis (:6379), Langfuse (:3001), @@ -259,7 +263,7 @@ cd molecule-monorepo # no auth on localhost — dev-only; production must gate it. cd workspace-server -go run ./cmd/server +go run ./cmd/server # applies pending migrations on first boot cd ../canvas npm install diff --git a/README.zh-CN.md b/README.zh-CN.md index eaefed04..7538c5c9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -38,8 +38,8 @@ Workspace Runtime

-[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https://github.com/Molecule-AI/molecule-monorepo) -[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/Molecule-AI/molecule-monorepo) +[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https://github.com/Molecule-AI/molecule-core) +[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/Molecule-AI/molecule-core) @@ -248,8 +248,12 @@ Workspace Runtime (Python image with adapters) ## 快速开始 ```bash -git clone https://github.com/Molecule-AI/molecule-monorepo.git -cd molecule-monorepo +git clone https://github.com/Molecule-AI/molecule-core.git +cd molecule-core + +cp .env.example .env +# 默认值即可在本地启动整套服务。.env.example 里有针对生产部署的 +# 安全配置说明(ADMIN_TOKEN、SECRETS_ENCRYPTION_KEY 等)。 ./infra/scripts/setup.sh # 启动 Postgres (:5432)、Redis (:6379)、Langfuse (:3001) @@ -258,7 +262,7 @@ cd molecule-monorepo # 仅用于本地开发;生产环境必须加 mTLS / API Key。 cd workspace-server -go run ./cmd/server +go run ./cmd/server # 首次启动会自动跑 schema_migrations 里未应用的迁移 cd ../canvas npm install diff --git a/canvas/package.json b/canvas/package.json index 3f35b2b9..7e6c82b7 100644 --- a/canvas/package.json +++ b/canvas/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev --turbopack -p 3000", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/docker-compose.infra.yml b/docker-compose.infra.yml index d6ce7392..2b8922ff 100644 --- a/docker-compose.infra.yml +++ b/docker-compose.infra.yml @@ -1,5 +1,3 @@ -version: "3.9" - services: postgres: image: postgres:16-alpine @@ -106,10 +104,13 @@ services: condition: service_completed_successfully environment: DATABASE_URL: postgres://${POSTGRES_USER:-dev}:${POSTGRES_PASSWORD:-dev}@postgres:5432/langfuse - CLICKHOUSE_URL: clickhouse://langfuse:${CLICKHOUSE_PASSWORD:-langfuse-dev}@clickhouse:9000/langfuse + # Langfuse v2 expects the HTTP interface (port 8123). The previous + # clickhouse://...:9000 native-protocol URL is rejected with + # "ClickHouse URL protocol must be either http or https". + CLICKHOUSE_URL: http://clickhouse:8123 + CLICKHOUSE_MIGRATION_URL: clickhouse://clickhouse:9000 CLICKHOUSE_USER: langfuse CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-langfuse-dev} - LANGFUSE_AUTO_CLICKHOUSE_MIGRATION_DISABLED: "true" NEXTAUTH_SECRET: ${LANGFUSE_SECRET:-changeme-langfuse-secret} NEXTAUTH_URL: http://localhost:3001 SALT: ${LANGFUSE_SALT:-changeme-langfuse-salt} diff --git a/docker-compose.yml b/docker-compose.yml index 6659b7f0..c9c88d7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,10 +82,13 @@ services: condition: service_completed_successfully environment: DATABASE_URL: postgres://${POSTGRES_USER:-dev}:${POSTGRES_PASSWORD:-dev}@postgres:5432/langfuse - CLICKHOUSE_URL: clickhouse://langfuse:langfuse@langfuse-clickhouse:9000/langfuse + # Langfuse v2 expects the HTTP interface (port 8123). The previous + # clickhouse://...:9000 native-protocol URL is rejected with + # "ClickHouse URL protocol must be either http or https". + CLICKHOUSE_URL: http://langfuse-clickhouse:8123 + CLICKHOUSE_MIGRATION_URL: clickhouse://langfuse-clickhouse:9000 CLICKHOUSE_USER: langfuse CLICKHOUSE_PASSWORD: langfuse - LANGFUSE_AUTO_CLICKHOUSE_MIGRATION_DISABLED: "true" NEXTAUTH_SECRET: ${LANGFUSE_SECRET:-changeme-langfuse-secret} NEXTAUTH_URL: http://localhost:3001 SALT: ${LANGFUSE_SALT:-changeme-langfuse-salt} diff --git a/infra/scripts/setup.sh b/infra/scripts/setup.sh index 6cf83b81..5ee20d84 100755 --- a/infra/scripts/setup.sh +++ b/infra/scripts/setup.sh @@ -26,23 +26,30 @@ echo "==> Verifying Redis KEA config..." KEA=$(docker compose -f "$ROOT_DIR/docker-compose.infra.yml" exec -T redis redis-cli config get notify-keyspace-events | tail -1) echo " notify-keyspace-events = $KEA" -echo "==> Running migrations..." -MIGRATIONS_DIR="$ROOT_DIR/workspace-server/migrations" -if [ -d "$MIGRATIONS_DIR" ]; then - for f in "$MIGRATIONS_DIR"/*.sql; do - echo " Applying $(basename "$f")..." - docker compose -f "$ROOT_DIR/docker-compose.infra.yml" exec -T postgres \ - psql -U "${POSTGRES_USER:-dev}" -d "${POSTGRES_DB:-molecule}" -f - < "$f" - done - echo " Migrations complete." -else - echo " No migrations directory found, skipping." -fi +# Migrations are intentionally not applied here. The platform's own runner +# (workspace-server/internal/db/postgres.go::RunMigrations) tracks applied +# files in `schema_migrations` on every boot. Applying them out-of-band via +# psql leaves that table empty, so the platform re-applies everything and +# fails on non-idempotent ALTER TABLE statements. Let `go run ./cmd/server` +# handle it. echo "==> Infrastructure ready!" echo " Postgres: localhost:5432" echo " Redis: localhost:6379" echo " Langfuse: localhost:3001" +echo " Temporal: localhost:7233 (gRPC) / localhost:8233 (UI)" +echo "" +echo " Next: cd workspace-server && go run ./cmd/server" +echo " (the platform applies pending migrations on first boot)" + +# Source .env if it exists so the ADMIN_TOKEN check below reflects what the +# platform will actually see at startup, not just the current shell env. +if [ -f "$ROOT_DIR/.env" ]; then + set -a + # shellcheck disable=SC1091 + . "$ROOT_DIR/.env" + set +a +fi # Security check — issue #684 (AdminAuth bearer bypass, PR #729). # Without ADMIN_TOKEN, any valid workspace bearer token can call /admin/* routes.