Scripts Reference
All deployment and operational scripts included in the repository.
Overview
| Script | Location | Purpose | Run From |
|---|---|---|---|
deploy-prod.sh | scripts/ | Automated production deployment with rollback | Server |
validate-deployment.sh | scripts/ | Pre-deployment validation checks | Server |
push-snomed.sh | scripts/ | Upload SNOMED RF2 to server and run import | Mac (local) |
import_snomed_rf2.py | backend/scripts/ | SNOMED RF2 database import | Server (via Docker) |
verify-port-config.sh | scripts/ | Check port configuration consistency | Local/Server |
validate_and_stamp_department_schedules.py | backend/scripts/ | Post-ingest: validate + stamp department schedules | Server (via Docker) |
seed_ontology_aliases.py | backend/scripts/ | Post-ingest: seed specialty-noun → department aliases | Server (via Docker) |
seed_snomed_domain_mapping.py | backend/scripts/ | Post-ingest: seed SNOMED → clinical-domain map | Server (via Docker) |
Post-Ingest Finalization Scripts
Run once after a full crawl + taxonomy extraction (see
Data Seeding → Step 6).
All three are idempotent and read DATABASE_URL from the zol-app container env.
They are operator steps, not part of the ingest pipeline — skipping them
leaves the doctor-schedule tools, spoken-specialty resolution, and SNOMED domain
guards silently non-functional on a fresh install.
| Script | What breaks if skipped | Re-run when |
|---|---|---|
validate_and_stamp_department_schedules.py | Every "which doctors consult on {day}?" query hedges (no schedule is trusted) | After any re-ingest of … – Raadplegingen pages |
seed_ontology_aliases.py | Spoken specialty nouns ("longarts") don't resolve to a department | After the approved DEPARTMENT_SPECIALTY_NOUNS table changes |
seed_snomed_domain_mapping.py | SNOMED domain plausibility guards have no mapping | After a SNOMED import / when the ~38-row map changes |
docker exec zol-app python -m scripts.validate_and_stamp_department_schedules
docker exec zol-app python -m scripts.seed_ontology_aliases
docker exec zol-app python -m scripts.seed_snomed_domain_mapping
Not these on a fresh install:
backfill_consultation_schedule.pyandbackfill_department_schedule.pyare one-shot historical migrations for pre-existing corpora; new docs get those fields extracted at ingest time.
deploy-prod.sh
Automated production deployment with health checks and rollback.
./scripts/deploy-prod.sh
What It Does
- Pre-deployment checks — Docker, compose, env file, disk space
- Backup — PostgreSQL dump + volume snapshot
- Pull images — Download latest Docker images
- Migrations — Run Alembic database migrations
- Deploy —
docker compose up -dwith--remove-orphans - Health checks — Wait for backend and frontend health endpoints
- Smoke tests — API endpoint, frontend, auth endpoint
- Cleanup — Prune unused images, remove old backups (>30 days)
Failure Handling
If any step fails, the script triggers automatic rollback:
- Stops new containers
- Logs the failure
Configuration
| Variable | Default | Description |
|---|---|---|
COMPOSE_FILE | docker-compose.prod.yml | Compose file to use |
ENV_FILE | .env.prod | Environment file |
BACKUP_DIR | backups/ | Backup destination |
validate-deployment.sh
Pre-deployment validation without actually deploying.
./scripts/validate-deployment.sh
Checks Performed
- Docker Engine installed and running
- Docker Compose installed
docker-compose.prod.ymlYAML syntax valid- Required Dockerfiles exist
- nginx configuration exists
- Deployment script is executable
.env.prod.exampletemplate exists- CI/CD workflow exists
- Backend and frontend directory structure
Exit Codes
| Code | Meaning |
|---|---|
| 0 | All checks passed |
| 1 | One or more checks failed |
push-snomed.sh
Upload SNOMED CT RF2 from Mac to server and run import.
./scripts/push-snomed.sh user@server-ip [OPTIONS]
Arguments
| Argument | Required | Description |
|---|---|---|
user@server-ip | Yes | SSH target (e.g., deploy@10.0.0.5) |
Options
| Flag | Description |
|---|---|
--dry-run | Show what would be done without executing |
--help | Show usage information |
What It Does
- Find — Auto-detects
~/Downloads/SnomedCT_ManagedServiceBE_PRODUCTION_* - Compress —
tar -czf(~2 GB → ~400 MB), reuses existing tarball - Upload —
scpto/opt/zol-rag/snomed/on the server - Import —
docker exec zol-app python -m scripts.import_snomed_rf2inside the container - Verify — Queries row counts from SNOMED tables
Prerequisites
- SNOMED RF2 folder in
~/Downloads/ - SSH key-based access to the server
- The
zol-appcontainer running on the server
Examples
# Full import
./scripts/push-snomed.sh deploy@10.0.0.5
# Preview only
./scripts/push-snomed.sh deploy@10.0.0.5 --dry-run
import_snomed_rf2.py
SNOMED CT RF2 to PostgreSQL import script.
# Run via Docker (on server)
docker exec zol-app python -m scripts.import_snomed_rf2 \
--rf2-dir /path/to/Snapshot [--dry-run] [--db-url URL]
Arguments
| Flag | Required | Default | Description |
|---|---|---|---|
--rf2-dir | Yes | — | Path to RF2 Snapshot directory |
--dry-run | No | false | Parse and show statistics without writing to DB |
--db-url | No | DATABASE_URL env | PostgreSQL connection URL |
Import Phases
- Parse RF2 files — Dutch descriptions, English descriptions (for FSN), relationships, language refset
- Build records — Concept records with FSN, preferred Dutch term, semantic tag
- Compute transitive closure — IS-A hierarchy (topological sort + BFS)
- Insert into PostgreSQL — Bulk COPY into
app.snomed_*tables
Tables Modified
| Table | Content |
|---|---|
app.snomed_concepts | Concept ID, FSN, preferred Dutch term, semantic tag |
app.snomed_descriptions | Dutch descriptions with acceptability |
app.snomed_relationships | All active relationships (IS-A, FINDING_SITE, etc.) |
app.snomed_transitive_closure | Pre-computed IS-A ancestry (ancestor, descendant, depth) |
All tables are truncated before import (fresh load, not incremental).
Expected Output
Phase 1: Parsing RF2 files...
Dutch descriptions: ~150,000
English descriptions: ~350,000
Relationships: ~900,000
Phase 2: Building concept records...
Concepts: ~350,000
Phase 3: Computing transitive closure...
Closure rows: ~5,000,000
Phase 4: Loading into PostgreSQL...
Total time: ~5-15 minutes
verify-port-config.sh
Check port configuration consistency across the project.
./scripts/verify-port-config.sh
Verifies that port numbers in Docker compose files, environment variables, and application configuration are consistent with each other.
Operational Commands Quick Reference
These are not scripts but commonly used Docker commands for operations:
Health Check
curl -s http://localhost:80/health | python3 -m json.tool
View Logs
docker logs zol-app --tail 100 -f
Restart Application
APP_IMAGE=zol-rag-app:${GIT_SHA} \
docker compose -f docker/docker-compose.app.yml --env-file .env.prod up -d
Database Shell
docker exec -it zol-postgres psql -U ${POSTGRES_USER} -d ${POSTGRES_DB}
Container Status
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"