From ac06a11c3ded27b8eda0c6a9c67196392fabad06 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Wed, 22 Apr 2026 01:19:50 -0700 Subject: [PATCH 1/2] docs: add CONTRIBUTING.md + local dev guide Issue #6 asked for a contributor doc covering Docker/env setup, migrations, embedding server setup, build commands, and a troubleshooting section. New CONTRIBUTING.md covers: - Prerequisites (Node 20+, Docker Compose, npm) - Clone + install (root + embedding-server separately) - Environment (template copy, the four required keys matching .env.example: EMBEDDING_API_URL, EMBEDDING_VERSION, EMAILOCTOPUS_API_KEY, EMAILOCTOPUS_LIST_ID) - docker compose up --build for the all-in-one path, or 'docker compose up -d postgres' + 'npm run dev' when you want the API to run outside Docker - Prisma migrations (prisma:generate, prisma:migrate, prisma:push for quick sync) - Starting embedding-server/ locally on port 3001 and pointing EMBEDDING_API_URL at it; notes the default mock vector behaviour - Build/start - Troubleshooting for ECONNREFUSED from inside Docker (host.docker.internal), database-not-exist on first run (-v reset + createdb), stale Prisma client after branch switch, and port conflicts on 3000/3001 Zoho OAuth guidance from the issue is intentionally left out - there's no Zoho integration in the current codebase yet. That troubleshooting entry can land alongside the Zoho feature when it merges. All commands documented were verified against package.json, docker-compose.yml, .env.example, and embedding-server/index.js. Fixes #6 --- CONTRIBUTING.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c7c2c73 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,144 @@ +# Contributing to trood-leader + +Thanks for helping out. This guide gets you from a fresh checkout to a running +local API with a working database and embedding server in a few minutes. + +## Prerequisites + +- **Node.js 20+** (the Dockerfile targets `node:20-alpine`) +- **Docker + Docker Compose** (for the Postgres + API containers) +- **npm** (ships with Node) + +## 1. Clone and install dependencies + +```bash +git clone https://github.com/TroodInc/trood-leader +cd trood-leader +npm install +``` + +`npm install` runs in the repo root. The embedding server is a separate npm +package under `embedding-server/` — install its dependencies too if you plan +to run it locally (see step 4): + +```bash +(cd embedding-server && npm install) +``` + +## 2. Configure environment + +Copy the template and fill the three API-key values: + +```bash +cp .env.example .env +``` + +`DATABASE_URL` in `.env.example` already points at the Postgres service +declared in `docker-compose.yml`. Values you must set before `/import` or +`/export` endpoints work: + +| Variable | Purpose | +|-------------------------|----------------------------------------------------------| +| `EMBEDDING_API_URL` | URL of your embedding service (e.g. `http://localhost:3001`) | +| `EMBEDDING_VERSION` | Version tag stored alongside each embedding | +| `EMAILOCTOPUS_API_KEY` | API key for EmailOctopus exports | +| `EMAILOCTOPUS_LIST_ID` | Target list ID for EmailOctopus exports | + +## 3. Run the database and API + +The easiest path is Docker Compose, which brings up Postgres and the API +together: + +```bash +docker compose up --build +``` + +The API listens on `http://localhost:3000`. Postgres listens on +`localhost:5432` with user/password/database `trood/trood/trood_leader` +(matches `docker-compose.yml`). + +If you want to run the API outside Docker while keeping Postgres in Docker: + +```bash +docker compose up -d postgres +npm run dev # ts-node-dev, reloads on save +``` + +## 4. Run migrations + +Prisma generates the client and applies migrations: + +```bash +npm run prisma:generate # prisma generate +npm run prisma:migrate # prisma migrate dev (creates tables) +``` + +For quick iteration against an empty dev database you can use +`npm run prisma:push` instead of `prisma:migrate` — it syncs the schema +without creating a migration file. + +## 5. Start the embedding server (local dev) + +`embedding-server/` is a small Express service that speaks the `/embed` +contract the API expects. It's useful for local dev so you don't need to +point at a real embedding provider: + +```bash +cd embedding-server +npm start +``` + +It listens on `http://localhost:3001`. Set `EMBEDDING_API_URL` in `.env` to +that URL so the API picks it up. + +The default implementation returns a deterministic 384-dimension mock vector +per text input, which is fine for end-to-end tests but obviously not a real +embedding. + +## 6. Build for production + +```bash +npm run build # tsc -> dist/ +npm start # node dist/index.js +``` + +## Troubleshooting + +**`ECONNREFUSED` on the embedding URL.** The API expects +`EMBEDDING_API_URL` to point at a reachable embedding service. In Docker, +`localhost` from inside the API container is the container itself, not your +Mac — use `host.docker.internal:3001` or add the embedding server to +`docker-compose.yml` so they share the network. + +**Prisma: `database "trood_leader" does not exist`.** The Postgres container +creates the database from `POSTGRES_DB` on first start. If you ran Postgres +without it, either `docker compose down -v` to reset the volume or +`createdb -U trood trood_leader` manually. + +**`npm run prisma:migrate` hangs.** Usually means Postgres isn't up yet. +`docker compose up -d postgres` first, wait ~2 seconds, then re-run the +migrate command. + +**Port 3000 or 3001 already in use.** The API uses `PORT` from `.env` +(default 3000); the embedding server hard-codes 3001. Free the port or +change the API's `PORT` (the embedding server would need a small code edit +at `embedding-server/index.js` to honour a different port). + +**Schema drift after a merge.** Run `npm run prisma:generate` after pulling +— the generated client lives under `node_modules/.prisma` and is not +checked in, so rebasing or switching branches often leaves it stale. + +## Where to put changes + +- API routes: `src/` (Express + TypeScript) +- Prisma schema + migrations: `prisma/` +- Embedding mock: `embedding-server/` +- Dev/CI config: root (`tsconfig.json`, `docker-compose.yml`, `Dockerfile`) + +Before opening a PR, make sure: + +1. `npm run build` succeeds (TypeScript compiles cleanly) +2. Prisma migrations you added apply cleanly from an empty database +3. Your change has a one-line note in the PR description about which + endpoints / tables it touches, so reviewers can spot reply-tracking or + classification regressions early From c51724b4ce696cdd1da4113dc8840c40bc39440f Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sun, 5 Jul 2026 07:51:01 -0700 Subject: [PATCH 2/2] docs(contributing): fix host DATABASE_URL, migration note, and setup corrections Host-side commands (npm run dev, prisma migrate/push) now use a localhost DATABASE_URL rather than the Docker-only 'postgres' hostname. Adds a note that Docker Compose does not auto-apply migrations. Corrects node:20 base image, the values count, EMBEDDING_API_URL host.docker.internal for Docker mode, and the ENOTFOUND (crash, not hang) troubleshooting entry. --- CONTRIBUTING.md | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7c2c73..8d36800 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ local API with a working database and embedding server in a few minutes. ## Prerequisites -- **Node.js 20+** (the Dockerfile targets `node:20-alpine`) +- **Node.js 20+** (the Dockerfile targets `node:20`) - **Docker + Docker Compose** (for the Postgres + API containers) - **npm** (ships with Node) @@ -27,19 +27,26 @@ to run it locally (see step 4): ## 2. Configure environment -Copy the template and fill the three API-key values: +Copy the template and fill the four service values: ```bash cp .env.example .env ``` -`DATABASE_URL` in `.env.example` already points at the Postgres service -declared in `docker-compose.yml`. Values you must set before `/import` or -`/export` endpoints work: +`DATABASE_URL` in `.env.example` points at the Postgres service declared in +`docker-compose.yml`, which is correct inside the Docker Compose network. For +host-side commands such as `npm run dev`, `npm run prisma:migrate`, or +`npm run prisma:push`, use `localhost` instead: + +```bash +DATABASE_URL=postgresql://trood:trood@localhost:5432/trood_leader +``` + +Values you must set before `/import` or `/export` endpoints work: | Variable | Purpose | |-------------------------|----------------------------------------------------------| -| `EMBEDDING_API_URL` | URL of your embedding service (e.g. `http://localhost:3001`) | +| `EMBEDDING_API_URL` | URL of your embedding service (e.g. `http://host.docker.internal:3001` when the API runs in Docker) | | `EMBEDDING_VERSION` | Version tag stored alongside each embedding | | `EMAILOCTOPUS_API_KEY` | API key for EmailOctopus exports | | `EMAILOCTOPUS_LIST_ID` | Target list ID for EmailOctopus exports | @@ -57,6 +64,9 @@ The API listens on `http://localhost:3000`. Postgres listens on `localhost:5432` with user/password/database `trood/trood/trood_leader` (matches `docker-compose.yml`). +Docker Compose does not apply Prisma migrations automatically. On a fresh +database, run step 4 once before using API endpoints. + If you want to run the API outside Docker while keeping Postgres in Docker: ```bash @@ -64,9 +74,13 @@ docker compose up -d postgres npm run dev # ts-node-dev, reloads on save ``` +Before running `npm run dev` on your host, make sure `DATABASE_URL` uses +`localhost` as shown in step 2, not the Docker-only `postgres` hostname. + ## 4. Run migrations -Prisma generates the client and applies migrations: +Prisma generates the client and applies migrations. These commands run on your +host, so make sure `DATABASE_URL` uses `localhost` as shown in step 2: ```bash npm run prisma:generate # prisma generate @@ -88,8 +102,10 @@ cd embedding-server npm start ``` -It listens on `http://localhost:3001`. Set `EMBEDDING_API_URL` in `.env` to -that URL so the API picks it up. +It listens on `http://localhost:3001`. If the API runs on your host, set +`EMBEDDING_API_URL` in `.env` to that URL. If the API runs in Docker Compose, +use `http://host.docker.internal:3001` so the container can reach the host +service. The default implementation returns a deterministic 384-dimension mock vector per text input, which is fine for end-to-end tests but obviously not a real @@ -115,9 +131,11 @@ creates the database from `POSTGRES_DB` on first start. If you ran Postgres without it, either `docker compose down -v` to reset the volume or `createdb -U trood trood_leader` manually. -**`npm run prisma:migrate` hangs.** Usually means Postgres isn't up yet. -`docker compose up -d postgres` first, wait ~2 seconds, then re-run the -migrate command. +**`npm run prisma:migrate` fails with `getaddrinfo ENOTFOUND postgres`.** You +are running Prisma on your host while `DATABASE_URL` still points at the +Docker-only `postgres` hostname. Use +`postgresql://trood:trood@localhost:5432/trood_leader`, start Postgres with +`docker compose up -d postgres`, then re-run the migrate command. **Port 3000 or 3001 already in use.** The API uses `PORT` from `.env` (default 3000); the embedding server hard-codes 3001. Free the port or