Prescriptoo CLI
Development and test environments also expose database operations through the development HTTP service, documented in services/development/README.md. The CLI and HTTP service share their SQL routines and seed catalogs in pkg/development/database.
pcli is the root program for repository operational commands. Build it from the repository root:
make build-cli
./bin/pcli
./bin/pcli --helpYou can also run any command without building the binary by replacing ./bin/pcli with go run ./tools/cli, for example:
go run ./tools/cli database migrate
go run ./tools/cli database --helpCommands are grouped under database, generate, clean, and build. db remains an alias of database. The previous db create, proto, gen-openapi, and gen-sqlc paths remain supported for scripts, while help and the console use the grouped paths. The root Makefile delegates build-api, build-docs, and build-cli to the matching CLI commands.
Interactive console
Run ./bin/pcli in a terminal to open the Bubble Tea developer console, or use ./bin/pcli tui explicitly. go run ./tools/cli opens the same interface. The first menu contains Database, Generate, Clean, and Build. Choose a group to browse its tasks; Esc returns to the group menu. Tasks cover migration status/application, migration creation, fixtures, database cleanup/reset, source generation, repository cleanup, Docker image builds, and CLI self-builds. Opening the console does not run a task or connect to the database.
Search with /, choose a task, fill in its options, and review before running. Database tasks show the resolved host, database, environment, and service; database URL overrides and fixture passwords are hidden. Blank overrides use the existing .env / process-environment defaults. Blank fixture passwords use the existing development default. A reviewed database target is passed explicitly to the command so later configuration changes cannot redirect it.
| Screen | Controls |
|---|---|
| Task menu | ↑/↓ or j/k to move, / to search, Enter to accept a search and then select, q to quit |
| Options | Tab / Shift+Tab or ↑/↓ to move fields, ←/→ to choose a service, Enter to continue, Esc to return, q to quit outside text fields |
| Review | Enter to run, Esc to edit, q to quit; destructive tasks and remote/non-development seeds require typing the displayed confirmation and use Ctrl+C to quit |
| Command output | ↑/↓ or Page Up/Down to scroll; Ctrl+C cancels and shows the result; q cancels and quits after the task stops |
| Result | Enter or Esc to return to the menu, q to quit |
Output streams into a scrollable view with a running indicator and a final success/error result. The console retains the latest 64 KiB of output and hides database credentials and fixture passwords. Cancellation can leave earlier migrations applied; inspect migration status before retrying.
The console calls the same Cobra handlers as direct commands, retaining the existing service validation, local database restrictions, and confirmation requirements. Every direct command and flag below remains available for scripts. Without terminal input and output, plain pcli prints help; pcli tui reports that an interactive terminal is required. --help always prints command help.
Generation commands
./bin/pcli generate migration --service identity --name add_account_status
./bin/pcli generate protobuf
./bin/pcli generate openapi
./bin/pcli generate sqlc --service identity
# Or without building the CLI:
go run ./tools/cli generate protobuf
go run ./tools/cli generate openapi
go run ./tools/cli generate sqlc --service identity| Command | Purpose | Requirements |
|---|---|---|
generate migration --service identity --name add_account_status | Create a timestamped Goose SQL migration | Repository checkout; explicit service and migration name |
generate protobuf | Run scripts/proto-gen.sh: lint protobuf definitions with buf lint, then regenerate stubs with buf generate in proto/ | Bash, Buf on PATH, and Buf configuration in proto/ |
generate openapi | Run the offline Huma route generator and overwrite the checked-in api/openapi.yaml used by Scalar and Swagger | Go on PATH and the repository source checkout |
generate sqlc --service identity | Regenerate Go query accessors using the selected service's sqlc.yaml | sqlc on PATH; currently only Identity has a configuration |
These commands find the repository root from the current directory, so the built CLI works from any repository subdirectory. They stream tool output and return errors if a tool fails. These commands do not load database configuration or start the API. OpenAPI generation does not connect to PostgreSQL or RabbitMQ; review the generated specification, then run ./bin/pcli build docs to update the docs image. Use ./bin/pcli <command> --help for details. generate sqlc requires an explicit --service and reports an error if that service has no sqlc.yaml.
The current protobuf directory contains a health schema but no Buf configuration; add the configuration before running protobuf generation.
Creating migration source files
Never edit, delete, rename, or reorder an existing migration file unless the user explicitly requests that specific change. Use a new migration for schema or data changes by default. This rule applies even when a migration appears unused or incorrect: changing migration history is not authorized by a general request to change the database schema.
./bin/pcli generate migration --service identity --name add_account_status
# Or without building the CLI:
go run ./tools/cli generate migration --service organization --name add_team_indexgenerate migration requires --service (identity, doctor, admin, organization, authorization, audit, medicine, or prescription) and --name (lowercase letters, digits, and underscores, starting with a letter). It creates a timestamped Goose SQL migration with Up and Down sections in services/<service>/internal/postgres/migrations. Run from the repository root or a subdirectory. Goose is built into the CLI; a separate executable is not needed. This command does not read database configuration, connect to PostgreSQL, or apply the migration. Rebuild the CLI after editing migrations so that database commands include the updated embedded files.
Database commands
Applying migrations and managing data
./bin/pcli database migrate
./bin/pcli database migrate --service identity
./bin/pcli database migrate --service prescription
./bin/pcli database status
./bin/pcli database seed
./bin/pcli database seed-medicine
./bin/pcli database seed-suggestions
./bin/pcli database clean --yes
./bin/pcli database reset --yes| Command | Behavior | Command flags |
|---|---|---|
database migrate | Apply pending embedded migrations | --service (default all) |
database status | Show embedded migration status | --service (default all) |
database seed | Ask which development datasets to seed | --items (comma-separated), --all, optional --password override |
database seed-medicine | Load 600 Bangladesh drug variants with related catalog entries | No command-specific flags |
database seed-suggestions | Load 100 diagnoses, advice phrases, and investigations each | No command-specific flags |
database clean | Truncate managed application data and reset identities | --yes (required) |
database reset | Roll back and reapply all service migrations without seeding | --yes (required) |
Commands that connect to PostgreSQL use --database-url and --environment. Use ./bin/pcli database <command> --help for the current command help. The --password override must contain at least eight characters. Without an override, each development account's password is its email address.
migrate applies all services in dependency order by default. The supported service names are identity, doctor, admin, organization, authorization, audit, medicine, and prescription. Each service owns an embedded migration set and an independent Goose history table; identity keeps the legacy goose_db_version table for compatibility.
Admin owns admin_users; Organization owns organizations, memberships, and teams. Roles, permission catalogs, assignments, and overrides are stored only in the Authorization service's authz_* tables. The legacy Admin/Organization role and permission tables and their seeds/imports were removed from the existing baseline at the user's explicit request. This baseline edit does not alter databases that already applied those migrations; it takes effect when creating a fresh database.
migrate, status, seed, seed-medicine, and seed-suggestions accept remote development, staging, and production PostgreSQL URLs. All three seed commands show the target and require typing seed before connecting to a remote database or using a non-development environment. The interactive console collects this confirmation on its review screen. Incorrect or missing input cancels the command. Local or Docker Compose targets in development/local/test environments need no typed seed confirmation. System and missing database names are always rejected. clean and reset only accept development/local/test environments and local or Docker Compose PostgreSQL hosts, and require --yes.
Configuration defaults to ENV and DATABASE_URL loaded by the repository's normal configuration loader. Flags override those values:
./bin/pcli database migrate --database-url "$DATABASE_URL"
./bin/pcli database seed --environment development --items admin,organization
./bin/pcli database seed --items doctors,medicines,suggestions
./bin/pcli database seed --allWithout selection flags, seed asks for comma-separated item names or numbers, or all. An empty/invalid selection cancels before connecting. Available items are admin, organization, doctors, medicines, and suggestions (also accepted as prescription-suggestions). Use --items or --all in scripts; these flags are mutually exclusive. The TUI's Seed development data checklist uses space to toggle items and a to select/clear all. Its review shows selected datasets and account emails. The Database menu also includes Seed all development data, which runs database seed --all after options and review. Existing seed-medicine and seed-suggestions commands remain available.
| Item | Accounts | Assigned roles |
|---|---|---|
admin | admin@admin.com, staff@admin.com | Super Admin; Read-only Admin |
organization | admin@acme.com, staff@acme.com, admin@nova.com, staff@nova.com | Organization Admin and Read-only Member in Acme/Nova |
doctors | doctor@doctor.com | Deferred; doctor authorization is not configured |
Each account's default password equals its email address. Super Admin has every admin permission; Organization Admin has every organization permission in its organization. Read-only roles grant read/list permissions. Roles, catalogs, subjects, and assignments are seeded in authz_* tables; organization admins also retain the existing owner membership behavior. Staff memberships do not gain owner privileges. Admin and organization seeds require their service, Identity, and Authorization migrations; doctor seeds require Identity and Doctor only.
Repeated seeds reuse existing account IDs and organization slugs, restore fixture credentials and memberships, replace fixture role assignments/permission overrides, and restore the default role permission bundles. Unrelated accounts and roles are preserved. Original admin/doctor fixture IDs are reused when upgrading old development data. Each selected dataset commits independently; successful earlier datasets remain if a later one fails. Results report progress and only the selected accounts. reset rolls back all service migrations in reverse dependency order, and reapplies them without seeding fixtures. The TUI's Reset local database does the same and has no account/password options. Use a seed action separately after reset to populate development data.
The doctor migrations create doctor_profiles and track versions in goose_doctor_version. After applying them, seed --items doctors creates the development doctor's professional profile with license DEV-DOCTOR-001 and speciality General Medicine, an empty specialization array, qualification summary MBBS, FCPS and two example chambers, enabling /api/v1/doctors/auth/login and populated /api/v1/doctors/profile responses. Repeated seeds preserve existing professional details. Apply the second doctor migration before using the extended profile response or seed. It adds expertise, qualification and chamber columns; rollback removes those new values while retaining the original profile fields. Doctor tables are included in development clean/reset.
Cleanup commands
./bin/pcli clean all --dry-run
./bin/pcli clean cache --yes
./bin/pcli clean node-modules --yes
./bin/pcli clean binaries --yes
./bin/pcli clean docs --yes
./bin/pcli clean all --yes| Target | Files removed |
|---|---|
cache | Repository .cache and VitePress caches in docs/ and api-docs/ |
node-modules | node_modules directories throughout the checkout, excluding Git and agent/configuration directories |
binaries | bin/, services/api/bin/, services/api/server, and services/api/tmp/ |
docs | Generated VitePress site output, docs/reference/go/, and docs/public/examples/ |
all | All of the targets above |
Cleanup requires --yes unless --dry-run is set; dry runs only list existing targets. These commands find the repository root from the current directory. Shared Go build/module caches are outside their scope. Symbolic links are not followed into external directories. Repository cleanup is separate from database clean, which truncates local database data.
Build commands
# Bootstrap the CLI, then rebuild it from its own executable:
go run ./tools/cli build cli
./bin/pcli build cli
./bin/pcli build api
./bin/pcli build docsbuild api builds prescriptoo-api:latest using services/api/Dockerfile. build docs builds prescriptoo-api-docs:latest using api-docs/Dockerfile. Both require Docker and access to a running Docker daemon. They use the same builds as make build-api and make build-docs.
build cli requires Go on PATH and produces bin/pcli, like make build-cli. It compiles to a temporary file in bin/ and replaces the executable only after a successful build. On Linux, the running executable continues using its original file, so the CLI can rebuild itself, including from the Build menu. Restart the console to load the new version; subsequent direct invocations use the new executable immediately. An unsuccessful build preserves the old binary. These commands work from any repository subdirectory and stream build output.
Implementation and code reference
The tools/cli module uses Bubble Tea v2 with Bubbles and Lip Gloss for the interactive console, Cobra for command execution, and shared configuration. Shared database helpers handle target validation, embedded migration selection, and development fixtures. Migration order follows ownership dependencies; reset reverses it for rollback. These commands are separate from production HTTP routes.
See command reference, database helpers, and CLI entry point. Tests cover target restrictions, migration registration/order, fixture behavior, and command validation.
Audit history
Audit migrations are registered as audit with goose_audit_version. Apply them before deploying audited writers, along with Authorization's new read-permission migration. History is append-only and retained indefinitely; normal API clients cannot modify or purge it. Guarded development clean/reset includes audit tables and restores their immutable trigger within the cleanup transaction. See the Audit service guide for coverage and testing.
Medicine migrations use the medicine service and goose_medicine_version. Apply them with go run ./tools/cli database migrate --service medicine. Development clean/reset includes the medicine_ tables.
Medicine catalog fixtures
Run go run ./tools/cli database seed-medicine after applying the medicine migrations. The bundled CC BY 4.0 dataset subset contains 600 drug variants, 310 brands, 62 generics, and 26 manufacturers from a published Bangladesh catalog snapshot. The interactive console exposes the same command as Seed medicine catalog.
The command runs atomically and can be repeated without duplicate entries. Matching live catalog records retain their IDs and status; deleted entries owned by the seed can be restored. This command does not require identity/admin tables and does not change development accounts. Attribution and snapshot details are in pkg/development/database/seeds/README.md; the dataset source is licensed under CC BY 4.0.
Prescription suggestion fixtures
Apply the prescription migrations, then load the bundled suggestion catalogs:
go run ./tools/cli database migrate --service prescription
go run ./tools/cli database seed-suggestionsThe catalog contains 100 entries for each suggestion entity: diagnosis, advice, and investigation (300 total). The interactive console exposes the same command as Seed prescription suggestions. It supports the standard database flags and requires a local development/test target.
All three label catalogs load atomically. Repeated runs reuse matching labels ignoring case and preserve existing IDs, label casing, and edits to seeded records. The summary reports bundled catalog sizes, not the number of newly inserted rows. Only prescription tables are needed. Data and format details are in pkg/development/database/seeds/README.md.
Admin doctor management storage
Apply Organization migration 00004 for org_doctor_affiliations, Admin migration 00006 for admin_doctor_verifications, and Authorization migration 00003 for the new admin.doctor.* permission keys. Affiliations have a unique organization/doctor pair; verification submissions have a partial unique index allowing one pending submission per doctor. Account suspension uses the existing Identity account and session tables. Business mutations and their audit records commit together. Existing platform admins must receive explicit grants for the new permissions. See Doctor administration.
Doctor migrations 00005–00006 introduce one required speciality and ordered child specializations. Populated databases can stop at the reconciliation preflight; see the Doctor upgrade procedure for inspection, explicit mapping, retry, and rollback. Original expertise text remains in private recovery columns during rollout. Rebuild the CLI before migration.
Patient profile migration 00002_simplify_patient_profiles.sql requires an empty patient table. It adds required string age and sex, an optional address, and removes birth date and alert arrays. Upgrade and downgrade stop if profiles exist, without deleting them automatically.
Patient profiles use goose_patient_version and migrate after Organization, before Prescription. --service patient selects only Patient migrations. Patient tables are included in development clean/reset. Migrate all services before testing Doctor patient writes.
Clinical input catalogs
Apply Prescription migration 00002 and Authorization migration 00006, then run go run ./tools/cli database seed --items clinical-suggestions to load 301 chief complaints and 800 history suggestions. Both catalogs load atomically with stable IDs; reruns preserve administrator edits and deletions. seed --all includes them. See clinical queries and Admin CRUD.