From 9f1553d67fbc6912178ea70f20e2e1328af134d3 Mon Sep 17 00:00:00 2001 From: Connor Etherington Date: Tue, 17 Mar 2026 21:02:10 +0200 Subject: [PATCH] fix: Make Echo seamless to run locally Made local development first-run seamless by auto-bootstrapping control env vars during predev, adding Docker/Compose preflight checks, aligning local DB defaults across control/server, and updating r --- README.md | 31 ++++++++++++- packages/app/control/README.md | 33 ++++---------- packages/app/control/package.json | 2 +- packages/app/control/scripts/predev.sh | 26 +++++++++++ packages/app/control/scripts/setup.sh | 63 +++++++++++++++++++++----- packages/app/control/setup-db.sh | 10 ++-- packages/app/server/.env.example | 2 +- packages/app/server/README.md | 31 ++++++------- packages/app/server/src/server.ts | 4 +- 9 files changed, 142 insertions(+), 60 deletions(-) create mode 100755 packages/app/control/scripts/predev.sh diff --git a/README.md b/README.md index 54d3f0c7b..adf3bc1f4 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,36 @@ Or run `npx echo-start my-app` to choose interactively. # Development -Fill out `packages/app/control/.env` and `packages/app/server/.env`. Then... +## Prerequisites + +- Node.js 18+ (Node 20 recommended) +- pnpm 10+ +- Docker + Docker Compose plugin (`docker compose`) + +## First run + +From repo root: - `pnpm i` - `pnpm dev` + +What `pnpm dev` does automatically on first run: + +- Creates `packages/app/control/.env` (from `.env.example`) if missing +- Generates a local `AUTH_SECRET` and local `DATABASE_URL` if they are empty +- Starts local Postgres via Docker Compose (`echo-control-postgres-v2` on `localhost:5469`) +- Runs Prisma generate + migrations for control +- Starts: + - Echo Control at `http://localhost:3000` + - Echo Server at `http://localhost:3069` + +## Optional local config + +- `packages/app/server/.env` is optional for booting locally. +- To test real provider calls, add provider keys in `packages/app/server/.env` (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.). +- To test OAuth providers in control, set provider credentials in `packages/app/control/.env`. + +## Troubleshooting + +- If `pnpm dev` says Docker is missing, install Docker Desktop (or Docker Engine + Compose plugin). +- If Docker is installed but not running, start Docker and run `pnpm dev` again. diff --git a/packages/app/control/README.md b/packages/app/control/README.md index 99d3dce93..83b0ee71c 100644 --- a/packages/app/control/README.md +++ b/packages/app/control/README.md @@ -46,44 +46,31 @@ A comprehensive Next.js application for managing Echo applications, API keys, an ### Prerequisites - Node.js 18+ -- PostgreSQL database - pnpm +- Docker + Docker Compose plugin (`docker compose`) ### Installation -1. **Clone and navigate to the project**: - - ```bash - cd echo-control - ``` - -2. **Install dependencies**: +1. **Install dependencies (from repo root)**: ```bash pnpm install ``` -3. **Create .env file**: - - ```bash - # Generate .env file - pnpm local-setup - ``` - -4. **Run database migrations**: +2. **Run local setup + dev server**: ```bash - npx prisma generate - npx prisma db push + pnpm dev ``` -5. **Start the development server**: + `pnpm dev` now handles local bootstrap automatically: - ```bash - pnpm run dev - ``` +- Creates `packages/app/control/.env` if it does not exist +- Generates local `AUTH_SECRET` + `DATABASE_URL` defaults if missing/empty +- Starts Postgres in Docker (`echo-control-postgres-v2`) +- Runs Prisma generate + migrations -6. **Open the application**: +3. **Open the application**: Visit [http://localhost:3000](http://localhost:3000) ## Features Overview diff --git a/packages/app/control/package.json b/packages/app/control/package.json index d9e68b3b4..1bbf43bc3 100644 --- a/packages/app/control/package.json +++ b/packages/app/control/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "predev": "docker compose -f docker-local-db.yml up -d && sleep 3 && prisma generate && prisma migrate deploy", + "predev": "pnpm run local-setup && ./scripts/predev.sh", "dev": "next dev --turbopack", "local-setup": "./scripts/setup.sh", "prebuild": "prisma generate", diff --git a/packages/app/control/scripts/predev.sh b/packages/app/control/scripts/predev.sh new file mode 100755 index 000000000..8c3fb76da --- /dev/null +++ b/packages/app/control/scripts/predev.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -euo pipefail + +if ! command -v docker &> /dev/null; then + echo "Error: Docker is required to run Echo locally." + echo "Install Docker Desktop (or Docker Engine + Compose plugin), then retry." + exit 1 +fi + +if ! docker compose version &> /dev/null; then + echo "Error: Docker Compose plugin is required." + echo "Make sure 'docker compose' is available, then retry." + exit 1 +fi + +if ! docker info &> /dev/null; then + echo "Error: Docker daemon is not running." + echo "Start Docker and run 'pnpm dev' again." + exit 1 +fi + +docker compose -f docker-local-db.yml up -d +sleep 3 +pnpm exec prisma generate +pnpm exec prisma migrate deploy diff --git a/packages/app/control/scripts/setup.sh b/packages/app/control/scripts/setup.sh index c7e3e89b7..1646c50b0 100755 --- a/packages/app/control/scripts/setup.sh +++ b/packages/app/control/scripts/setup.sh @@ -1,20 +1,59 @@ #!/bin/bash -# Check if .env file exists and if AUTH_SECRET is already set -if [ -f .env ] && grep -q "^AUTH_SECRET=" .env; then - echo "AUTH_SECRET already exists in .env file. Skipping generation." +set -euo pipefail + +ENV_FILE=".env" +DEFAULT_DATABASE_URL="postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public" + +if [ ! -f "$ENV_FILE" ]; then + if [ -f .env.example ]; then + cp .env.example "$ENV_FILE" + echo "Created .env from .env.example." + else + touch "$ENV_FILE" + echo "Created empty .env." + fi +fi + +get_env_value() { + local key="$1" + local raw_value + + raw_value="$(grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f2- || true)" + raw_value="${raw_value%\"}" + raw_value="${raw_value#\"}" + raw_value="${raw_value%\'}" + raw_value="${raw_value#\'}" + + echo "$raw_value" +} + +set_env_value() { + local key="$1" + local value="$2" + + if grep -qE "^${key}=" "$ENV_FILE"; then + sed -i "s|^${key}=.*|${key}=\"${value}\"|" "$ENV_FILE" + else + printf '\n%s="%s"\n' "$key" "$value" >> "$ENV_FILE" + fi +} + +auth_secret_value="$(get_env_value "AUTH_SECRET")" +if [ -z "$auth_secret_value" ]; then + generated_auth_secret="$(node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))")" + set_env_value "AUTH_SECRET" "$generated_auth_secret" + echo "Generated AUTH_SECRET." else - echo "Generating AUTH_SECRET..." - AUTH_SECRET=$(node -e "console.log('AUTH_SECRET=' + require('crypto').randomBytes(32).toString('base64'))") - echo $AUTH_SECRET - echo $AUTH_SECRET >> .env + echo "AUTH_SECRET already set." fi -# Check if DATABASE_URL is already set -if [ -f .env ] && grep -q "^DATABASE_URL=" .env; then - echo "DATABASE_URL already exists in .env file. Skipping." +database_url_value="$(get_env_value "DATABASE_URL")" +if [ -z "$database_url_value" ]; then + set_env_value "DATABASE_URL" "$DEFAULT_DATABASE_URL" + echo "Set DATABASE_URL to local default." else - echo "DATABASE_URL='postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public'" >> .env + echo "DATABASE_URL already set." fi -echo "Setup complete! You can now run 'pnpm dev' to start the development server." +echo "Local setup complete." diff --git a/packages/app/control/setup-db.sh b/packages/app/control/setup-db.sh index 1989a4312..7006f69ab 100755 --- a/packages/app/control/setup-db.sh +++ b/packages/app/control/setup-db.sh @@ -7,7 +7,7 @@ if [ ! -f .env ]; then echo "📝 Creating .env file..." cat > .env << 'EOF' # Database - Docker PostgreSQL -DATABASE_URL="postgresql://echo_user:echo_password@localhost:5469/echo_control?schema=public" +DATABASE_URL="postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public" # Stripe (Mocked for now) STRIPE_SECRET_KEY="mock_stripe_secret_key" @@ -25,7 +25,7 @@ fi # Start PostgreSQL container echo "🐳 Starting PostgreSQL container..." -docker-compose -f docker-local-db.yml up -d postgres +docker compose -f docker-local-db.yml up -d postgres # Wait for PostgreSQL to be ready # No need for manual health check since docker-local-db.yml already has healthcheck configured @@ -46,7 +46,7 @@ pnpm exec prisma db push echo "🎉 Database setup complete!" echo "" echo "📊 You can now run:" -echo " npm run dev # Start the application" +echo " pnpm dev # Start the application" echo " pnpm exec prisma studio # View the database" -echo " docker logs local-postgres # View database logs" -echo " docker stop local-postgres # Stop the database" \ No newline at end of file +echo " docker logs echo-control-postgres-v2 # View database logs" +echo " docker stop echo-control-postgres-v2 # Stop the database" diff --git a/packages/app/server/.env.example b/packages/app/server/.env.example index 97011ebdb..7f93c8882 100644 --- a/packages/app/server/.env.example +++ b/packages/app/server/.env.example @@ -18,7 +18,7 @@ OPENROUTER_API_KEY= # Database # ---------- -DATABASE_URL="postgresql://echo_user:echo_password@localhost:5469/echo_control?schema=public" +DATABASE_URL="postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public" # ---------- diff --git a/packages/app/server/README.md b/packages/app/server/README.md index 54d1888bd..029ea64f6 100644 --- a/packages/app/server/README.md +++ b/packages/app/server/README.md @@ -2,36 +2,35 @@ ## Prerequisites -This server depends on the generated Prisma client from the `echo-control` project. Before running the server, you need to ensure the Prisma client is copied locally. +- Node.js 18+ +- pnpm +- For full local stack: Docker + Docker Compose plugin (`docker compose`) ## Development -### First Time Setup +### Recommended (from repo root) -1. Make sure the `echo-control` project has generated its Prisma client: - - ```bash - cd ../control - pnpm run build # or whatever command generates the Prisma client - ``` +```bash +pnpm install +pnpm dev +``` -2. Copy the generated Prisma client: - ```bash - pnpm run copy-prisma - ``` +The root `pnpm dev` command starts both `echo-control` and `echo-server`. ### Running the Server ```bash -# Development mode (automatically copies Prisma client) +# In this package only: pnpm run dev -# Production mode +# Build + start pnpm run build pnpm start ``` -The `dev` and `start` scripts automatically run `copy-prisma` as a pre-hook, so you don't need to run it manually. +The server scripts automatically copy Prisma schema/client artifacts from `echo-control` before build/start. +If `DATABASE_URL` is not set, the server uses a local default: +`postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public`. ## Docker Considerations @@ -78,4 +77,4 @@ CMD ["pnpm", "start"] ## Error Handling -If the generated Prisma client is not found, the server will throw a descriptive error message asking you to run `pnpm run copy-prisma`. +If the generated Prisma client artifacts are missing, run `pnpm run copy-prisma` and retry. diff --git a/packages/app/server/src/server.ts b/packages/app/server/src/server.ts index ff7d58c3b..44d053501 100644 --- a/packages/app/server/src/server.ts +++ b/packages/app/server/src/server.ts @@ -51,7 +51,9 @@ const upload = multer({ export const prisma = new PrismaClient({ datasources: { db: { - url: env.DATABASE_URL ?? 'postgresql://localhost:5469/echo', + url: + env.DATABASE_URL ?? + 'postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public', }, }, log: ['warn', 'error'],