Complete local setup for a new machine that only has Git installed and authenticated. Follow this document top to bottom.
| Component | Path | Role | Default URL |
|---|---|---|---|
| Frontend | apps/frontend |
React + Vite UI | http://localhost:5173 |
| Core API | apps/core-api |
FastAPI auth, jobs, ATS | http://localhost:8000 |
| AI Core | services/ai-core-services |
Parsing, matching, screening AI | http://localhost:8002 |
| PostgreSQL | Docker db |
Primary database | localhost:5434 |
| MinIO | Docker minio |
Resume / JD object storage | API localhost:9002, Console http://localhost:9003 |
Recommended path: install Docker → fill .env files → start Compose → database from scratch (Postgres role/DB via Compose, Alembic migrations, super admin) → verify.
Optional path: run Postgres + MinIO in Docker, run Python/Node apps natively on the host (for faster iteration).
These steps assume Ubuntu / Debian-like Linux. Adjust package names for macOS (Homebrew) or Windows (WSL2 strongly recommended).
Confirm:
git --version
git config --global user.name
# SSH to GitHub should work:
ssh -T git@github.comIf SSH fails, add an SSH key to GitHub or use HTTPS with a personal access token.
# Official convenience script (Linux)
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
# Log out and back in (or reboot) so the docker group applies
docker version
docker compose versionYou need Docker and the Compose V2 plugin (docker compose, not only legacy docker-compose).
sudo apt update
sudo apt install -y \
curl \
openssl \
build-essential \
libpq-dev \
postgresql-client \
python3 \
python3-venv \
python3-pippostgresql-client provides psql for verifying the DB from the host (optional but useful).
Install Node.js 18+ (frontend Dockerfile uses Node 18):
# Example: NodeSource 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v # v18+ or v20+
npm -vOptional but useful for AI-core native work: uv
curl -LsSf https://astral.sh/uv/install.sh | sh- First
docker compose up --builddownloads base images and builds AI deps (Docling / CPU PyTorch). Expect several GB and a long first build. - AI PDF OCR is off by default (
DOCLING_DO_OCR=false) to keep memory reasonable on smaller machines.
git clone git@github.com:joshsoftware/EZScreen.git
cd EZScreenIf you use HTTPS:
git clone https://github.com/joshsoftware/EZScreen.git
cd EZScreenCheckout the branch your team uses for local work (ask if unsure):
git fetch origin
git checkout <branch-name>Never commit .env files. Copy the examples, then edit.
cp apps/core-api/.env.example apps/core-api/.env
cp services/ai-core-services/.env.example services/ai-core-services/.env
cp apps/frontend/.env.example apps/frontend/.envRun these and paste the values into the .env files:
# JWT signing secret
openssl rand -hex 32
# Internal service token (core-api ↔ ai-core-services)
openssl rand -hex 32
# Strong DB / MinIO passwords (pick your own; avoid spaces)
openssl rand -base64 24| Concept | apps/core-api/.env |
services/ai-core-services/.env |
|---|---|---|
| DB user | POSTGRES_USER |
(same user in DATABASE_URL) |
| DB password | POSTGRES_PASSWORD |
password in DATABASE_URL (URL-encoded) |
| DB name | POSTGRES_DB |
same in DATABASE_URL |
| Internal token | INTERNAL_SERVICE_TOKEN |
INTERNAL_SERVICE_TOKEN (identical) |
| MinIO access | MINIO_ACCESS_KEY |
MINIO_ROOT_USER and MINIO_ACCESS_KEY |
| MinIO secret | MINIO_SECRET_KEY |
MINIO_ROOT_PASSWORD and MINIO_SECRET_KEY |
URL-encode special characters in passwords inside DATABASE_URL (e.g. ! → %21, @ → %40, # → %23).
Example: password EZScreen123! → EZScreen123%21 in the URL.
POSTGRES_USER=ezscreen_user
POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD
POSTGRES_DB=ezscreen_db
POSTGRES_HOST_PORT=5434
# Password in URL must be URL-encoded; host "db" is the Compose service name
DATABASE_URL=postgresql+psycopg2://ezscreen_user:CHANGE_ME_URL_ENCODED@db:5432/ezscreen_db
JWT_SECRET=CHANGE_ME_LONG_RANDOM
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7
REFRESH_COOKIE_SECURE=false
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
FRONTEND_BASE_URL=http://localhost:5173
# Browser opens this host — use published host port, NOT Docker DNS "minio"
MINIO_ENDPOINT=127.0.0.1:9002
MINIO_ACCESS_KEY=minio_admin
MINIO_SECRET_KEY=CHANGE_ME_MINIO_SECRET
MINIO_SECURE=false
MINIO_BUCKET_RESUMES=resumes
# Compose overrides AI_SERVICES_HOST to ai-core-services; 127.0.0.1 is fine as fallback
AI_SERVICES_HOST=127.0.0.1
AI_SERVICES_PORT=8002
INTERNAL_SERVICE_TOKEN=CHANGE_ME_IDENTICAL_IN_BOTH_ENVS
EMAIL_MODE=console
EMAIL_FROM=noreply@ezscreen.io
# Local default: placeholder Meet links (no Google credentials required)
GOOGLE_MEET_MODE=mock
GOOGLE_CALENDAR_ID=primary
GOOGLE_CALENDAR_SEND_UPDATES=allSERVICE_NAME=ai-core-services
PORT=8002
LOG_LEVEL=INFO
ENVIRONMENT=development
# LLM — required for parsing / matching / questions (see §7)
OLLAMA_URL=https://ollama.com
OLLAMA_MODEL=gemma4:31b
OLLAMA_API_KEY=your_ollama_cloud_api_key
# Compose sets CORE_API_* via docker-compose.yml; keep a localhost fallback for native runs
CORE_API_URL=http://localhost:8000
CORE_API_BASE_URL=http://127.0.0.1:8000
INTERNAL_SERVICE_TOKEN=CHANGE_ME_IDENTICAL_IN_BOTH_ENVS
DATABASE_URL=postgresql://ezscreen_user:CHANGE_ME_URL_ENCODED@db:5432/ezscreen_db
MINIO_ENDPOINT=minio:9000
MINIO_ROOT_USER=minio_admin
MINIO_ROOT_PASSWORD=CHANGE_ME_MINIO_SECRET
MINIO_ACCESS_KEY=minio_admin
MINIO_SECRET_KEY=CHANGE_ME_MINIO_SECRET
MINIO_SECURE=false
MINIO_BUCKET_NAME=resumes
MINIO_API_HOST_PORT=9002
MINIO_CONSOLE_HOST_PORT=9003
DOCLING_DO_OCR=false
# Live screening / bots — optional until you need them (see §7)
ATTENDEE_API_KEY=
ATTENDEE_API_URL=https://api.attendee.dev/v1
WEBHOOK_URL=https://your-ngrok-url/screening/webhook
WHISPER_API_URL=https://api.groq.com/openai/v1/audio/transcriptions
WHISPER_API_KEY=
KOKORO_API_URL=https://api.replicate.com/v1/predictions
KOKORO_API_KEY=
WEBSOCKET_URL=wss://dummy-ezscreen.ngrok.io/audio# Empty = browser calls /api on same origin (Vite proxy → core-api)
VITE_CORE_API_URL=
# Optional: Google Drive picker for resume upload
# VITE_GOOGLE_CLIENT_ID=
# VITE_GOOGLE_API_KEY=Compose sets DEV_API_PROXY_TARGET=http://core-api:8000 for the frontend container automatically.
POSTGRES_HOST_PORT, MINIO_API_HOST_PORT, and MINIO_CONSOLE_HOST_PORT are substituted by Compose. Either:
- pass both env files when starting Compose (recommended), or
- put those three keys in a project-root
.env(Compose auto-loads it).
From the repo root:
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d --buildFirst build can take a long time. Watch progress:
docker compose ps
docker compose logs -f --tail=100Healthy baseline:
| Container | Expected |
|---|---|
ezscreen-db |
healthy |
ezscreen-minio |
healthy |
ezscreen-minio-init |
exited 0 (creates resumes + jds buckets) |
ezscreen-core-api |
running on :8000 |
ezscreen-ai-core-services |
running on :8002 |
ezscreen-frontend |
running on :5173 |
PostgreSQL is empty on first boot. The Compose db service only creates the role + database; it does not create application tables. Tables come from Alembic migrations in apps/core-api. There is no automatic migrate-on-startup.
Schema design reference: architecture/DB_DESIGN.md.
docker-compose.yml runs postgres:15-alpine as service db (ezscreen-db).
On first container start (empty pgdata volume), Postgres reads these from apps/core-api/.env:
| Env var | Effect |
|---|---|
POSTGRES_USER |
Creates this DB role (e.g. ezscreen_user) |
POSTGRES_PASSWORD |
Password for that role |
POSTGRES_DB |
Creates this database (e.g. ezscreen_db) owned by that role |
Host publish: POSTGRES_HOST_PORT (default 5434) → container 5432.
Data is stored in Docker volume pgdata. Changing POSTGRES_* later does not recreate the user/DB unless you remove the volume (docker compose down -v).
Both services must share the same credentials:
| File | Connection string |
|---|---|
apps/core-api/.env |
DATABASE_URL=postgresql+psycopg2://USER:ENCODED_PASS@db:5432/DB (Compose) |
services/ai-core-services/.env |
DATABASE_URL=postgresql://USER:ENCODED_PASS@db:5432/DB (Compose) |
Same USER / password / DB. Password in the URL must be URL-encoded if it contains ! @ # % etc.
Useful before building the heavy AI image:
# From repo root, after .env files exist
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d dbWait until healthy:
docker compose ps db
# or
docker inspect --format='{{.State.Health.Status}}' ezscreen-db
# expect: healthyFrom the host (install client if needed: sudo apt install -y postgresql-client):
# Replace user/db/password with your POSTGRES_* values
export PGPASSWORD='YourPostgresPassword'
psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db -c '\conninfo'
psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db -c '\dt'
# On a fresh DB, \dt shows "Did not find any relations." until migrations runFrom inside the container:
docker compose exec db \
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c 'SELECT version();'Or hardcode:
docker compose exec db psql -U ezscreen_user -d ezscreen_db -c 'SELECT current_database(), current_user;'| Item | Location / command |
|---|---|
| Alembic config | apps/core-api/alembic.ini |
Env (reads DATABASE_URL from settings / .env) |
apps/core-api/alembic/env.py |
| Migration scripts | apps/core-api/alembic/versions/ |
| Apply all | alembic upgrade head |
| Current revision | alembic current |
| History | alembic history |
Core API does not call create_all on boot. Always run Alembic after a new DB or after pulling new migrations.
Migration chain (apply in order via upgrade head):
c478691b4383— initial schema (orgs, users, jobs, applications, interview tables, enums)d2a8f4c91b07— job skills JSONBe3b9c5d82a14— org settings JSONBf4c1a7e93b20— password reset tokensa1c4e8b27d90— application timelineb7e2d9f41c08— backfill under_hr_reviewc9f3a1e82d04— job screening questions
Initial tables include (among others): organizations, users, job_descriptions, applications, interview_session, interview_analysis, plus Alembic’s alembic_version.
With core-api running (or start it after db is healthy):
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d --build core-api
docker compose exec core-api alembic upgrade head
docker compose exec core-api alembic currentExpected: current revision at head (e.g. c9f3a1e82d04 — confirm with alembic history).
When apps run on the host and Postgres is published on 127.0.0.1:5434:
cd apps/core-api
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# DATABASE_URL in .env must use 127.0.0.1:5434 (not host "db")
alembic upgrade head
alembic currentexport PGPASSWORD='YourPostgresPassword'
psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db -c '\dt'
psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db \
-c "SELECT version_num FROM alembic_version;"You should see application tables and one row in alembic_version.
There is no default admin user. Create one after migrations:
# Docker
docker compose exec core-api python -m scripts.create_super_admin \
--email admin@ezscreen.io \
--password 'YourSecurePassword!'
# Native (venv active, cwd apps/core-api)
python -m scripts.create_super_admin \
--email admin@ezscreen.io \
--password 'YourSecurePassword!'Options: --first-name, --last-name, --update-password (reset if user already exists).
Env overrides: SUPER_ADMIN_EMAIL, SUPER_ADMIN_PASSWORD, SUPER_ADMIN_FIRST_NAME, SUPER_ADMIN_LAST_NAME.
Verify:
psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db -c \
"SELECT email, role, status FROM users WHERE role = 'super_admin';"Login: http://localhost:5173/super-admin/login
Org admin / HR (after you create orgs/users): http://localhost:5173/org-admin/login
Migrations + super admin only. Next steps in the UI (or API):
- Sign in as super admin
- Create an organization
- Invite / create organization_admin or HR users
- As org admin/HR: create jobs, upload resumes, schedule screenings
Invite emails with EMAIL_MODE=console appear in core-api logs, not a real inbox.
A — Schema wipe + remigrate + optional admin (keeps Docker volume; drops public schema):
docker compose exec core-api python -m scripts.reset_db --yes \
--with-super-admin \
--email admin@ezscreen.io \
--password 'YourSecurePassword!'reset_db uses container DATABASE_URL (@db:5432 — correct inside Compose).
B — Destroy Postgres data volume entirely (fresh POSTGRES_* init on next start):
docker compose down
docker volume rm ezscreen_pgdata
# If the volume name differs:
docker volume ls | grep pgdata
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d db
# Wait healthy, then migrate + create admin again (§5.5–5.8)Or wipe all Compose volumes (DB + MinIO + model caches):
docker compose down -vC — Full DROP DATABASE (needs a Postgres superuser URL; uncommon with the stock Compose image, which has no separate postgres superuser password beyond POSTGRES_USER):
# Only if you have an admin URL; see apps/core-api/scripts/reset_db.py --help
python -m scripts.reset_db --yes --drop-database \
--admin-url 'postgresql+psycopg2://ezscreen_user:PASS@127.0.0.1:5434/postgres'Prefer A or B for local Docker.
If you install Postgres on the host instead of Compose db:
sudo apt install -y postgresql postgresql-contrib
sudo service postgresql start
sudo -u postgres psql <<'SQL'
CREATE USER ezscreen_user WITH PASSWORD 'YourPostgresPassword';
CREATE DATABASE ezscreen_db OWNER ezscreen_user;
GRANT ALL PRIVILEGES ON DATABASE ezscreen_db TO ezscreen_user;
SQLThen set both DATABASE_URLs to 127.0.0.1:5432 (or your port), skip starting Compose db, and run Alembic + create_super_admin as in §5.6–5.8. Keep POSTGRES_* in .env only if you still use the Compose db service.
| Symptom | Cause | Fix |
|---|---|---|
password authentication failed |
URL password ≠ POSTGRES_PASSWORD, or not URL-encoded |
Fix both DATABASE_URLs; encode ! as %21, etc. |
Connection refused on 5434 |
DB not up / wrong port | docker compose ps db; check POSTGRES_HOST_PORT |
Connection to host db from laptop fails |
db is Docker DNS only |
From host use 127.0.0.1:5434 |
\dt empty after “setup” |
Migrations never run | alembic upgrade head |
relation already exists |
Partial schema / mixed reset | reset_db --yes or down -v then migrate clean |
Changed POSTGRES_PASSWORD but login fails |
Old credentials baked into pgdata |
docker compose down -v (data loss) or alter role inside Postgres |
| AI service DB errors | ai-core DATABASE_URL wrong |
Match user/pass/db to core-api; use @db:5432 in Compose |
| Enum / column missing after pull | New migration not applied | alembic upgrade head again |
Open or curl:
| Check | URL / command |
|---|---|
| Frontend | http://localhost:5173 |
| Core API docs | http://localhost:8000/docs |
| AI Core docs | http://localhost:8002/docs |
| Core API root | curl -s http://127.0.0.1:8000/ |
| MinIO console | http://localhost:9003 (login = MINIO_ROOT_USER / MINIO_ROOT_PASSWORD) |
| Postgres | psql or any client → 127.0.0.1:5434, user/db from POSTGRES_* |
Invite emails in local mode are printed to core-api logs (EMAIL_MODE=console):
docker compose logs -f core-apiMinimum viable local product loop (create org → job → upload resumes → parse/match) needs a working LLM key (OLLAMA_*). Other keys are feature-specific.
- Create an API key at ollama.com.
- Set in
services/ai-core-services/.env:OLLAMA_URL=https://ollama.com(notapi.ollama.com)OLLAMA_MODEL(e.g.gemma4:31bor the model your team uses)OLLAMA_API_KEY=...
- Restart:
docker compose up -d --force-recreate ai-core-services
Default is GOOGLE_MEET_MODE=mock (placeholder Meet URLs). For live calendar events:
→ Follow docs/integrations/GOOGLE_CALENDAR_SETUP.md
→ Set GOOGLE_MEET_MODE=live and OAuth (or service account) fields in apps/core-api/.env
→ Recreate core-api
- Google Cloud project: enable Google Picker API + Drive API.
- Create a Web OAuth client; authorized JS origin:
http://localhost:5173. - Set in
apps/frontend/.env:VITE_GOOGLE_CLIENT_ID=...VITE_GOOGLE_API_KEY=...
- Rebuild/restart frontend.
Needed for live Meet bot / dual-channel audio.
Option A — Hosted Attendee (app.attendee.dev)
- Attendee API key →
ATTENDEE_API_KEY - Public HTTPS tunnel (ngrok, Cloudflare Tunnel, etc.) pointing at AI core webhook
WEBHOOK_URL=https://<your-tunnel>/screening/webhook
- See docs/integrations/ATTENDEE_INTEGRATION.md
Option B — Self-hosted Attendee + EZScreen MinIO (services/attendee)
Uses the same MinIO as EZScreen (no AWS S3). Bucket: attendee-recordings.
- Start EZScreen infra (creates the Attendee bucket via
minio-init):docker compose \ --env-file apps/core-api/.env \ --env-file services/ai-core-services/.env \ up -d db minio minio-init
- Configure Attendee env (MinIO, not AWS):
cd services/attendee cp .env.example .env # Fill CREDENTIALS_ENCRYPTION_KEY / DJANGO_SECRET_KEY via: # docker compose -f dev.docker-compose.yaml run --rm --no-deps attendee-app-local python init_env.py # Copy AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY from MINIO_* in services/ai-core-services/.env # Prefer AWS_ENDPOINT_URL=http://host.docker.internal:9002 (EZScreen MinIO host port) # Optional if on ezscreen_default with working DNS: http://minio:9000 # Keep AWS_S3_ADDRESSING_STYLE=path
- Confirm Docker network name (
docker network ls→ usuallyezscreen_default). Override withEZSCREEN_NETWORK=...if needed. - Start Attendee (UI on http://localhost:8003):
docker compose -f dev.docker-compose.yaml up -d --build docker compose -f dev.docker-compose.yaml exec attendee-app-local python manage.py migrate - Point
services/ai-core-services/.envat your instance:ATTENDEE_API_URL=http://host.docker.internal:8003ATTENDEE_API_KEY=<key from Attendee dashboard>
- In
services/attendee/.env, allow Docker hostnames (required or ai-core getsDisallowedHost):Then recreate Attendee app:ALLOWED_HOSTS=localhost,127.0.0.1,host.docker.internal,attendee-app-local,* SITE_DOMAIN=localhost:8003docker compose -f dev.docker-compose.yaml up -d attendee-app-local - Restart ai-core after env changes.
- Smoke test (from repo root):
# Connectivity: should return {"results":[]} # (run from a shell that has your ATTENDEE_API_KEY; do not paste keys into chat) curl -s -H "Authorization: Token $ATTENDEE_API_KEY" \ -H "Host: localhost" \ http://127.0.0.1:8003/api/v1/bots # Or via ai-core (needs a real interview_session_id + future Meet link for full join) curl -s -X POST http://127.0.0.1:8002/screening/bot/dispatch \ -H 'Content-Type: application/json' \ -d '{"interview_session_id":"<uuid>","meeting_url":"https://meet.google.com/xxx-yyyy-zzz"}'
Note: live audio/webhooks still need a public tunnel (
WEBHOOK_URL/WEBSOCKET_URL). Without ngrok, bot create/schedule still works; realtime audio callbacks will not.
Set WHISPER_API_KEY / KOKORO_API_KEY (and URLs if different) in services/ai-core-services/.env when exercising live audio pipelines.
Use when you want hot reload without rebuilding images. Keep Postgres + MinIO in Compose; run apps on the host.
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d db minio minio-initIn apps/core-api/.env for native uvicorn:
DATABASE_URL=postgresql+psycopg2://ezscreen_user:ENCODED_PASS@127.0.0.1:5434/ezscreen_db
MINIO_ENDPOINT=127.0.0.1:9002
AI_SERVICES_HOST=127.0.0.1
# Do not rely on Docker-only overridesIn services/ai-core-services/.env for native uvicorn:
DATABASE_URL=postgresql://ezscreen_user:ENCODED_PASS@127.0.0.1:5434/ezscreen_db
MINIO_ENDPOINT=127.0.0.1:9002
CORE_API_URL=http://127.0.0.1:8000
CORE_API_BASE_URL=http://127.0.0.1:8000cd apps/core-api
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
alembic upgrade head
python -m scripts.create_super_admin --email admin@ezscreen.io --password 'YourSecurePassword!'
uvicorn src.main:app --reload --host 0.0.0.0 --port 8000cd services/ai-core-services
# Prefer uv if installed:
uv sync
uv run uvicorn src.main:app --reload --host 0.0.0.0 --port 8002
# Or: pip install with CPU torch index (see Dockerfile), then uvicorncd apps/frontend
cp .env.example .env # if not already
npm install
npm run dev
# Vite proxies /api → http://127.0.0.1:8000 by default# Start (after images built)
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d
# Stop
docker compose down
# Stop and delete volumes (wipes DB + MinIO data)
docker compose down -v
# Rebuild one service after Dockerfile / deps change
docker compose up -d --build core-api
# Logs
docker compose logs -f core-api ai-core-services frontend
# Shell into API
docker compose exec core-api bash| Symptom | Likely cause | Fix |
|---|---|---|
Compose ignores POSTGRES_HOST_PORT / MinIO ports |
Vars not in Compose substitution env | Pass --env-file for both service envs, or put ports in root .env |
| Presigned upload/download fails in browser | MINIO_ENDPOINT is minio:9000 |
Use 127.0.0.1:9002 in core-api .env (browser-reachable) |
password authentication failed |
DATABASE_URL password ≠ POSTGRES_PASSWORD or not URL-encoded |
Align and encode special chars |
| AI → core-api callbacks 401 | Mismatched INTERNAL_SERVICE_TOKEN |
Same value in both .env files; recreate both services |
| Empty schema / missing tables | Migrations not run | docker compose exec core-api alembic upgrade head |
| Port already in use | Another process on 5173/8000/8002/5434/9002 | Change *_HOST_PORT or stop the conflicting process |
| MinIO buckets missing | minio-init failed |
docker compose logs minio-init; re-run compose |
| LLM / parse errors | Missing or wrong OLLAMA_API_KEY |
Set key; confirm OLLAMA_URL=https://ollama.com |
Frontend /api 502 in Docker |
core-api not healthy | Check docker compose ps and core-api logs |
| PEP 668 / system pip blocked | Installing Python pkgs globally | Use python3 -m venv as shown above |
-
.envfiles are gitignored and never committed -
JWT_SECRETandINTERNAL_SERVICE_TOKENare random, not example placeholders - MinIO and Postgres passwords are not defaults you reuse elsewhere
-
GOOGLE_MEET_MODE=mockuntil Calendar OAuth is intentionally configured - Real API keys (Ollama, Groq, Attendee, Google) stay out of chat logs and PRs
| Doc | Topic |
|---|---|
| README.md | Short monorepo overview |
| integrations/GOOGLE_CALENDAR_SETUP.md | Live Meet + Calendar |
| integrations/ATTENDEE_INTEGRATION.md | Meeting bot |
| architecture/SYSTEM_DESIGN.md | System design |
| architecture/DB_DESIGN.md | Database |
services/ai-core-services/README.md |
AI microservice API map |
# 0) Docker + Node + Python toolchain installed; re-login after docker group
# 1) Clone
git clone git@github.com:joshsoftware/EZScreen.git && cd EZScreen
# 2) Env
cp apps/core-api/.env.example apps/core-api/.env
cp services/ai-core-services/.env.example services/ai-core-services/.env
cp apps/frontend/.env.example apps/frontend/.env
# Edit both service .env files: matching passwords, tokens, MINIO_ENDPOINT=127.0.0.1:9002 in core-api
# 3) Up (Postgres creates POSTGRES_USER / POSTGRES_DB on first boot via empty pgdata volume)
docker compose \
--env-file apps/core-api/.env \
--env-file services/ai-core-services/.env \
up -d --build
# 4) Database from scratch — migrate schema, then seed platform admin
docker compose exec core-api alembic upgrade head
docker compose exec core-api alembic current
docker compose exec core-api python -m scripts.create_super_admin \
--email admin@ezscreen.io \
--password 'YourSecurePassword!'
# Optional: confirm tables from host
# PGPASSWORD='...' psql -h 127.0.0.1 -p 5434 -U ezscreen_user -d ezscreen_db -c '\dt'
# 5) Open
xdg-open http://localhost:5173/super-admin/login # or visit in browser