Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.19.6
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
FROM node:14-alpine
FROM node:20-alpine3.18

ENV NODE_ENV=production
RUN mkdir /app
COPY yarn.lock /app
COPY package.json /app
WORKDIR /app

RUN apk add --no-cache postgresql-client
RUN NODE_ENV=development yarn install
COPY . /app
RUN yarn run build
RUN mkdir -p /app/dist
COPY ./docker-entrypoint.sh /docker-entrypoint.sh
CMD /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
CMD ["/docker-entrypoint.sh"]
123 changes: 123 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Local Development and Full Test

This runbook gives you one reliable path to boot the stack and verify GraphQL flows end to end.

## 1) Runtime and install

```bash
nvm use
# or: asdf shell nodejs 20.19.6

yarn install
```

Node version targets:
- `.nvmrc`: `20.19.6`
- `.node-version`: `20`

## 2) Start dependencies

Start PostgreSQL + Elasticsearch first:

```bash
docker compose up -d postgres elasticsearch
```

Check health:

```bash
docker compose ps
```

Both services should be `healthy` before launching the app.

## 3) App environment variables

Set these variables in your shell (or `.env`) before starting the app.

```bash
export NODE_ENV=development
export PORT=5000
export DATABASE_URL='postgresql://advisors:advisors@localhost:55432/advisors?schema=public'
export DISABLE_AUTOMATION=true

export AUTH_SECRET='local-dev-secret'
export AUTH_AUDIENCE='event-test-2025'

export UPLOADER_BASE='http://localhost:3000'
export UPLOADER_SECRET='local-dev-secret'
export GOTENBERG_BASE='http://localhost:3001'

export EMAIL_HOST='localhost'
export EMAIL_PORT='1025'
export EMAIL_USER='local'
export EMAIL_PASS='local'
export EMAIL_FROM='local@example.com'

export TWILIO_ACCOUNT_SID='AC00000000000000000000000000000000'
export TWILIO_AUTH_TOKEN='local-dev-secret'
export TWILIO_PHONE='+15555555555'
```

Notes:
- `AUTH_SECRET` and `AUTH_AUDIENCE` must match what your local token/test scripts use.
- `DATABASE_URL` should use `localhost:55432` when running the app outside Docker.

## 4) Build and start app

```bash
yarn build
yarn dev
```

GraphQL endpoint:
- `http://localhost:5000/graphql`

## 5) Seed test data

In another terminal:

```bash
yarn seed-dummy
```

This creates deterministic local test records, including:
- advisor id `advisor-alice-test`
- advisor id `advisor-bob-test`
- request id `request-test-2025`

## 6) Run full local end-to-end test

With the app running, execute:

```bash
yarn test-local
```

This runs:
1. `yarn seed-dummy`
2. Public GraphQL query
3. Admin-auth query (`submittedRequests`)
4. Advisor-auth query (`getRequest`)
5. Advisor mutation (`respondRequest`)
6. Verification query (`getRequestAssignment`)

If all pass, your local backend path is working end to end.

## 7) Quick troubleshooting

- `Prisma` connection errors:
- Confirm Postgres is healthy: `docker compose ps`
- Re-check `DATABASE_URL` host/port (`localhost:55432` outside Docker)

- Auth errors (`Unauthorized`, audience/secret issues):
- Re-check `AUTH_SECRET`
- Re-check `AUTH_AUDIENCE`

- GraphQL upload typing/build issues:
- Re-run `yarn install`
- Re-run `yarn build`

- Seed/test query failures:
- Ensure app is running on port `5000`
- Re-run `yarn seed-dummy`
73 changes: 73 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
services:
postgres:
image: postgres:15-alpine
ports:
- "55432:5432"
environment:
POSTGRES_DB: advisors
POSTGRES_USER: advisors
POSTGRES_PASSWORD: advisors
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U advisors -d advisors"]
interval: 5s
timeout: 5s
retries: 20

elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9
ports:
- "9200:9200"
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ES_JAVA_OPTS: -Xms512m -Xmx512m
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
healthcheck:
test: ["CMD-SHELL", "curl -fs http://localhost:9200/_cluster/health >/dev/null"]
interval: 10s
timeout: 5s
retries: 30

app:
build: .
ports:
- "5000:5000"
depends_on:
postgres:
condition: service_healthy
elasticsearch:
condition: service_healthy
environment:
NODE_ENV: development
PORT: 5000
DATABASE_URL: postgresql://advisors:advisors@postgres:5432/advisors?schema=public
DISABLE_AUTOMATION: "true"
AUTH_SECRET: local-dev-secret
AUTH_AUDIENCE: event-test-2025
UPLOADER_BASE: http://localhost:3000
UPLOADER_SECRET: local-dev-secret
GOTENBERG_BASE: http://localhost:3001
EMAIL_HOST: localhost
EMAIL_PORT: 1025
EMAIL_USER: local
EMAIL_PASS: local
EMAIL_FROM: local@example.com
TWILIO_ACCOUNT_SID: AC00000000000000000000000000000000
TWILIO_AUTH_TOKEN: local-dev-secret
TWILIO_PHONE: +15555555555
healthcheck:
test:
[
"CMD-SHELL",
"node -e \"fetch('http://localhost:5000/graphql', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ query: '{__typename}' }) }).then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))\"",
]
interval: 10s
timeout: 5s
retries: 30

volumes:
postgres_data:
elasticsearch_data:
24 changes: 13 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@
"start": "node dist",
"clean": "rm -rf dist",
"prisma": "prisma format && prisma generate",
"build": "npm -s run clean && yarn run prisma && tsc && cpy '**/*' '!**/*.ts' ../dist/ --cwd=src/ --no-overwrite --parents",
"build": "yarn clean && yarn prisma && tsc && cp -r src/. dist/ && find dist -name '*.ts' -delete",
"dev": "ts-node-dev --no-notify --respawn --exit-child --transpile-only src",
"debug": "ts-node-dev --no-notify --respawn src"
"debug": "ts-node-dev --no-notify --respawn src",
"seed-dummy": "ts-node scripts/seedDummy.ts",
"generate-token": "ts-node scripts/generateToken.ts",
"test-queries": "ts-node scripts/testQueries.ts",
"test-local": "yarn seed-dummy && ts-node scripts/fullLocalTest.ts"
},
"dependencies": {
"@codeday/eslint-config-typescript": "^2.1.7",
"@codeday/uploader-node": "^1.0.1",
"@prisma/client": "^4.3.1",
"@prisma/client": "^6.16.0",
"@types/email-validator": "^1.0.6",
"apollo-server": "^2.16.1",
"apollo-server-express": "^2.16.1",
"apollo-server-express": "^3.13.0",
"class-validator": "^0.12.2",
"dotenv": "^8.2.0",
"email-validator": "^2.0.4",
Expand All @@ -27,7 +30,7 @@
"front-matter": "^4.0.2",
"graphql": "^15.3.0",
"graphql-type-json": "^0.3.2",
"graphql-upload": "^12.0.0",
"graphql-upload": "^13.0.0",
"handlebars": "^4.7.7",
"html-entities": "^2.3.2",
"ical-expander": "^3.0.0",
Expand All @@ -38,7 +41,7 @@
"node-fetch": "^2.6.0",
"nodemailer": "^6.6.2",
"pdfkit": "^0.12.3",
"prisma": "^4.3.1",
"prisma": "^6.16.0",
"reflect-metadata": "^0.1.13",
"twilio": "^3.65.0",
"type-graphql": "^1.0.0-rc.3",
Expand All @@ -54,10 +57,9 @@
"@types/nodemailer": "^6.4.2",
"@types/pdfkit": "^0.12.0",
"@types/phone": "^2.4.1",
"cpy-cli": "^3.1.1",
"eslint": "^7.6.0",
"ts-node": "^8.10.2",
"ts-node": "^10.9.2",
"ts-node-dev": "^1.0.0-pre.56",
"typescript": "^4.3.4"
"typescript": "^5.7.3"
}
}
}
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ model RequestAssignment {
requestId String

responseFile String?
response Json?
response Json?

@@id([advisorId, requestId])
}
Expand Down
Loading
Loading