Skip to content

Day One — Developer Setup Runbook

Welcome to Evospin. By the end of this page you will have the entire platform running locally, a test bet placed, and a trace visible in Jaeger. Every command is copy-pasteable.


1. Prerequisites

Install these before you begin:

Tool Version Why
Docker (with the compose plugin) 24+ The unified compose file boots the entire stack
Node.js 22 LTS NestJS 11 + Prisma 7 require Node 22 (≥20.19 minimum); used for host-side tooling
pnpm 9.11.0 Package manager for ebit-fe and ebit-admin-fe
npm 10+ Package manager for ebit-api (do not use pnpm there)
git 2.40+ Three sibling repos
AWS CLI v2 latest ECR pulls when working against perf infra
Doppler CLI latest Secrets fetch (optional — see §3 Option B if you don't have access)
k6 0.50+ Smoke perf test on week 1 (curriculum.md §"Operational toolkit")
jq latest JSON wrangling in verification scripts
gh (GitHub CLI) optional Convenient for PR workflows

Hardware: 16 GB RAM recommended (8 GB absolute minimum). First build peaks at ~7 GB; steady state is ~3.7 GB. You need at least 40 GB free disk for images + Postgres volume growth.

Verify everything is installed (each line should print a version, not "command not found"):

docker compose version   # must show v2.x
docker info | grep "Total Memory"   # confirm >= 8 GiB
node -v                  # v22.x
pnpm -v                  # 9.11.0
npm -v                   # 10+
aws --version
doppler --version
k6 version
jq --version
git --version

2. Clone the workspace

The workspace is three sibling repos under one parent directory, plus shared infrastructure files at the root:

cd /home/ubuntu
git clone <your-ebit-api-repo-url>   ebit/ebit-api
git clone <your-ebit-fe-repo-url>    ebit/ebit-fe
git clone <your-ebit-admin-fe-repo-url> ebit/ebit-admin-fe

The root-level files (docker-compose.yml, .env.example, README.md, observability/, docs/, tests-e2e/) live in the parent ebit/ directory. If you received the workspace as a single archive, everything is already in place.


3. Environment setup

Option A: Doppler (internal team)

If you have Doppler access:

doppler login                                              # opens browser
doppler projects                                           # confirm "ebit" appears
doppler configs --project ebit                             # confirm "dev_perf" appears
doppler secrets --project ebit --config dev_perf | head -5 # confirm read access
export DOPPLER_TOKEN=$(doppler configs tokens create dev-local --max-age 0 --plain)

If doppler projects doesn't list ebit, workspace membership has to be granted manually — ping your team lead. You can fall back to Option B below for local-only work, but you'll hit a wall on week 1 when perf scripts run.

Option B: Plain .env (external hires / no Doppler)

The compose file works without Doppler. Copy the example and you are done:

cd /home/ubuntu/ebit
cp .env.example .env

The .env.example ships with safe local defaults: JWT_SECRET, ADMIN_DEFAULT_PASSWORD=admin, placeholder reCAPTCHA keys, and all host port mappings. Review README.md for the full variable reference.

The NestJS backend also reads ebit-api/.local.env — this file is already committed and requires no changes for local development.


4. Build and boot

cd /home/ubuntu/ebit
docker compose up -d --build

First build takes 12-15 minutes cold (layer cache cuts subsequent rebuilds to ~1 minute per image). Boot proceeds in stages enforced by depends_on — verify each stage reached (healthy) before expecting the next one to work.

Stage 1 — Infrastructure

Postgres, Redis (cache), Redis (bot), RabbitMQ.

docker compose ps ebit-db ebit-redis ebit-redis-bot ebit-rabbitmq
# STATUS column should read "(healthy)" for all four

Stage 2 — Prisma migrate + seed

ebit-prisma-migrate runs prisma migrate deploy && prisma db seed with DEBUG_SEED_LOCAL=true, then exits with code 0. This creates the schema, seeds house games, permissions, site config, and the local test accounts.

docker compose logs -f ebit-prisma-migrate   # tail until container exits
docker compose ps ebit-prisma-migrate        # STATUS should read "Exited (0)"

Stage 3 — NestJS apps

ebit-api (:4000), ebit-rt (:4001), ebit-bj (:4002), ebit-bo (:4003), ebit-speed-roulette (:4004) start in parallel.

docker compose logs ebit-api | grep "Nest application successfully started"
docker compose ps ebit-api ebit-rt ebit-bj ebit-bo ebit-speed-roulette
# all five should be "(healthy)"

Stage 4 — Frontends

ebit-fe (:3000) and ebit-admin-fe (Vite SPA — host :5173 / compose :3003) start once ebit-api is healthy.

docker compose ps ebit-fe ebit-admin-fe

Stage 5 — Observability

otel-collector, jaeger, prometheus, loki, grafana boot alongside the apps.

docker compose ps otel-collector jaeger prometheus loki grafana

All five stages reaching (healthy) typically takes 3-5 minutes after the build completes. If any service is stuck unhealthy, see the Troubleshooting section below.


5. Verify the stack

Open each URL and confirm it loads:

What URL Expected
REST API http://localhost:4000/swagger Swagger UI with all endpoints listed
Public site (dropbet) http://localhost:3000 Casino homepage with game tiles
Admin panel http://localhost:3003 Login page (Vite SPA from compose)
Jaeger (traces) http://localhost:16686 Service dropdown lists ebit-api after first request
Grafana (dashboards) http://localhost:3003 Login: admin / grafananote port collision with admin-fe compose; use only one at a time, or run admin-fe on host with pnpm dev at :5173
Prometheus http://localhost:9090 Query interface

Known sharp edge — admin panel sign-in. The admin-fe has four stacked integration bugs that block dashboard rendering after sign-in (cookie-name mismatch access_token vs jwt_access_token, missing OTel instrumentation, no propagateContextUrls, hard-coded API host). You'll see a blank page after sign-in. The API works fine — use Swagger (http://localhost:4000/swagger) for admin operations until the integration bugs are fixed. Full details: docs/flows/admin-sign-in.md.

If any service is unhealthy, check its logs:

docker compose logs --tail=50 ebit-api       # or any service name
docker compose ps                            # shows restart count + health status

See the Troubleshooting section in the workspace README for common issues (CORS errors, port conflicts, OOM during build).


6. Seeded test accounts

The Prisma seed (libs/_prisma/src/seed/index.ts) creates these accounts when DEBUG_SEED_LOCAL=true (set automatically by the compose migrate job):

Public site — dropbet (http://localhost:3000)

Field Value
Email local@example.com
Password password
Username local
Starting balance 1,000 DBC
KYC level LEVEL_0
Email verified yes

Nine additional accounts (local-1@example.com through local-9@example.com, same password) are also seeded for multi-user testing.

Source: libs/_prisma/src/seed/debug/rich-user.ts:5-42 (seedRichUser).

Admin panel (http://localhost:3001)

Field Value
Username admin
Password admin (from ADMIN_DEFAULT_PASSWORD in .env)

A second admin account with 2FA enabled is also seeded:

Field Value
Email admin-1@admin.com
Password admin
Username admin-1
TOTP secret O4JWQM2YBARTYJBZ
Role SuperAdmin

Source: libs/_prisma/src/seed/debug/rich-user.ts:44-80 (seed2faAdminUser).

Resetting corrupted seed data

If you accidentally ban the test user, corrupt the password hash, or otherwise break the seeded state:

docker compose run --rm ebit-prisma-migrate sh -c "npm run db:reset"

This drops all tables, re-runs migrations, and re-seeds. All data is destroyed — only use this when you need a clean slate. For a lighter touch, restart just the seed:

docker compose run --rm ebit-prisma-migrate sh -c "npm run db:seed"

The seed uses upsert with update: {}, so re-running it is safe — existing accounts are left untouched, missing ones are created.


7. Place your first bet

This walkthrough proves the full stack is working: frontend, API, Prisma, Redis, BullMQ, and OTel traces.

  1. Sign in — open http://localhost:3000, click Sign In, enter local@example.com / password.

  2. Navigate to Dice — from the homepage, find the Dice game tile (under Original Games or Casino) and click it.

  3. Place a bet — set a small bet amount (e.g., 1 DBC), choose your threshold and direction (over/under), and click Roll.

  4. Check the result — the UI shows your roll outcome, multiplier, and updated balance.

  5. Find the trace in Jaeger — open http://localhost:16686:

  6. Service dropdown → ebit-api
  7. Operation dropdown → POST /casino/games/house/dice/bets
  8. Click Find Traces, open the most recent one

The full span waterfall: - HTTP middleware + guards (~4 ms) - @PlaceBetLock Redis mutex acquisition - prisma:client:operation — balance deduction + bet INSERT inside a transaction - popUserSeed — fairness seed retrieval - Dice RNG computation + settlement - bet_settled_queue BullMQ enqueue (ioredis EVALSHA span)

Known trace gap. ebit-bj and ebit-speed-roulette are called via Nest's Redis pub/sub transport (@ExternalControllerClient) — that transport doesn't propagate W3C traceparent, so callee spans appear as orphan roots, not children of the originating request. Don't panic: this is documented (AF-2 in docs/architecture.md) and used as a triage cue in the incident runbook.

If the trace is missing entirely, follow docs/runbooks/trace-missing.md.

  1. Check Grafana — open http://localhost:3003, navigate to the "Service Overview" dashboard. Your bet should appear as a data point on the ebit-api rate/error/duration panels.

For a deeper understanding of the bet pipeline, read docs/flows/dropbet-bet-place.md.


8. Explore the architecture

Now that you have a working stack and a traced bet, read the architecture doc for the full picture:

  • docs/architecture.md — C4 diagrams (context, container, component), runtime scenario index, data model overview, observability catalog, and aggregated known weaknesses.

  • docs/observability.md — how traces, metrics, and logs are produced, correlated, and queried.

  • docs/flows/ — 15 individual flow docs, each with sequence diagrams, Jaeger trace IDs, span timings, and failure-mode analysis. Start with:

  • dropbet-sign-in.md — auth flow, cookie contract, 2FA
  • dropbet-bet-place.md — the shared bet pipeline you just exercised
  • rt-websocket.md — socket.io real-time events

9. Sharp edges to remember beyond day one

You met the admin-fe sign-in issue (§5) and the orphan-trace gap (§7) inline. A few more that will bite you later in week 1 if you're not warned:

The "users online" counter is intentionally inflated

The websocket broadcast UsersOnlineUpdated adds a fakeUserOnline padding (starts at 500, drifts by ±5 every 10 seconds, floor 180) to the real Redis ONLINE_USERS_KEY zcard. The number in the UI is cosmetic, not operational. See docs/flows/rt-websocket.md §6.3.

Package manager discipline

Repo Use Do NOT use
ebit-api/ npm install pnpm install (corrupts lockfile)
ebit-fe/ pnpm install npm install (corrupts lockfile)
ebit-admin-fe/ pnpm install npm install (corrupts lockfile)

Prisma commands need env-cmd

Never call npx prisma directly in ebit-api/. Always use the npm scripts (npm run db:migrate:dev, npm run db:seed, npm run db:reset, npm run prisma:generate) — they wrap prisma with env-cmd -f .env so the database URL is set correctly.

RabbitMQ is running but unused

The ebit-rabbitmq container starts and passes healthchecks, but receives zero traffic. The Fast Track integration module is stubbed with disabled = true. This is intentional — see the comment block above the service in docker-compose.yml and AF-6 in docs/architecture.md.


10. Exit checklist

You are done with day-one setup when all of these are true:

  • [ ] All required CLI tools installed (docker, node 22, pnpm 9.11, aws, doppler, k6, jq, git)
  • [ ] (Option A only) doppler projects lists ebit, dev_perf config is readable
  • [ ] All three repos cloned under ~/ebit/
  • [ ] docker compose ps shows all services as (healthy) with zero restarts
  • [ ] Swagger loads at http://localhost:4000/swagger
  • [ ] Dropbet loads at http://localhost:3000 and you can sign in with local@example.com / password
  • [ ] You placed a bet and saw the balance update
  • [ ] The bet trace appears in Jaeger at http://localhost:16686 under ebit-api operation POST /casino/games/house/dice/bets
  • [ ] Grafana loads at http://localhost:3003 (admin / grafana)
  • [ ] You have read docs/architecture.md sections 1-4 (context, containers, components, runtime scenarios)

Next step: the two-week curriculum — its "Operational toolkit" subsection covers the week-1 perf/Grafana/outage-drill work that previously lived in handover/onboarding-day-7.md.