Local development stack
Ce contenu n’est pas encore disponible dans votre langue.
This guide gets a complete SpeculaPro environment running on one computer: the database, the event log, the cache and the application. It runs SpeculaPro from its source repository, which is private, so it is for SpeculaPro’s own engineers and partners with access to the code.
Before you start
Section titled “Before you start”Install:
- Docker (Docker Desktop, OrbStack or Docker Engine with the Compose plugin)
- Go 1.26 or newer. The build uses Go 1.27.2, named in
backend/go.mod; with an older Go thegocommand downloads 1.27.2 by itself, unless you have setGOTOOLCHAIN=local - Node.js 22 or later and npm
- make (preinstalled on macOS and most Linux distributions)
Check that ports 5432 (Postgres), 6379 (Valkey), 19092 (Redpanda), 8081 (Redpanda Console) and 8080 (SpeculaPro) are free. If you already run Postgres or Redis locally, stop them first or the containers will fail to start.
What is in the repository
Section titled “What is in the repository”Répertoirebackend/ the Go service and its database migrations
Répertoirecmd/speculapro/ the
speculaprocommand- …
Répertoiremigrations/ database schema, built into the binary
- …
Répertoirefrontend/ the web app; compiled into the binary
- …
Répertoiredeploy/
- compose/docker-compose.yml local Postgres, Redpanda, Valkey
- sql/roles.sql database roles for production
Répertoiredocs/ this documentation site
- …
- .env.example sample settings for local development
- Makefile shortcuts for every step below
How to run SpeculaPro locally
Section titled “How to run SpeculaPro locally”Every step below is a make target. To see all of them, with one line on what each does:
make help-
Create your settings file. From the repository root:
Terminal window cp .env.example .envThe
Makefilereads.envautomatically. The defaults point at the local containers, so you do not need to change anything yet. Every setting is explained in the configuration reference. -
Start the supporting services.
Terminal window make upThis starts four containers in the background: Postgres 18, Redpanda (Kafka-compatible), Redpanda Console (a web page for looking inside Redpanda, at http://localhost:8081) and Valkey (Redis-compatible). The first run downloads the images and can take a few minutes.
Check that they are running:
Terminal window make psAll four should show
running, andpostgresshould showhealthyafter a few seconds. -
Create the database tables.
Terminal window make migrateThis applies every migration in
backend/migrations/in order. You should see one line per migration file, each marked as applied. Running it again is safe: migrations that are already applied are skipped.make migrate-statuslists every migration and whether it is applied.If you have set up the separate database roles locally, put the owner’s connection string in
SP_DB_OWNER_URL(in.envor the environment):make migrateandmake migrate-statusthen connect as the owner instead ofSP_DB_URL. With the default local settings there is one superuser and nothing to set. -
Create the Kafka topics.
First open
.envand set a small partition count for a laptop:Terminal window SP_KAFKA_PARTITIONS=6SpeculaPro creates 16 topics, and each gets this many partitions. The default of 64 makes 1,024, which is more than the local single-core Redpanda container accepts (see Partitions). The number is fixed when a topic is created, so set it before this step. Then:
Terminal window make topicsExpected output (topic names start with the
sp.prefix):created sp.alert.createdcreated sp.alert.created.dlqcreated sp.case.events...Each topic gets a
.dlqtwin (a dead-letter queue, where messages that cannot be processed are parked instead of lost). Running the command again prints nothing: existing topics are left alone. -
Build the web app.
Terminal window make webThis installs the frontend’s packages and compiles the web app into
backend/internal/web/dist, where the Go binary picks it up. You only need to repeat this when the frontend changes. -
Start SpeculaPro.
Terminal window make runYou should see log lines similar to:
level=WARN msg="using the built-in DEVELOPMENT encryption keys; never use this environment for real data"level=INFO msg="persister started" persist_worker=0 topic=sp.txn.ingestedlevel=INFO msg="stream evaluator started" stream_worker=0 topic=sp.txn.ingestedlevel=INFO msg="worker started" interval=6h0m0slevel=INFO msg="metrics listening" addr=:9090level=INFO msg="webhook dispatcher started"level=INFO msg="speculapro started" roles="[api decision ingest persist stream worker]" version=dev env=developmentlevel=INFO msg="http listening" addr=:8080The order of the lines can vary, and you will see one
persister startedline per persist worker and onestream evaluator startedline per stream evaluator (four of each by default). The warning is expected in development. It is your reminder that this environment’s encryption keys are public.make runstarts every role in one process: the web app and API, the real-time decision API, the ingest API, the persister, the stream evaluator and the worker.No alerts until you enable rules. A new workspace has no rules. Transactions you send are stored, but nothing is evaluated (and no running totals are kept) until you install a rule pack and enable at least one rule. See Managing rules.
-
Open the app. Go to http://localhost:8080. The interactive API documentation is at http://localhost:8080/api/docs.
How to create your first workspace
Section titled “How to create your first workspace”A workspace is one institution’s private area in SpeculaPro: its users, rules, alerts and data. Nobody can sign in until a workspace and its first administrator exist. Create one from the command line:
cd backendgo run ./cmd/speculapro tenant create \ --slug acme \ --name "Acme Pay" \ --kind psp \ --country GH \ --currency GHS \ --timezone Africa/Accra \ --admin-name "Ada Mensah"From the repository root, make tenant runs the same command, with the options in ARGS:
make tenant ARGS="--slug acme --name 'Acme Pay' --kind psp --country GH --currency GHS --admin-email [email protected] --admin-name 'Ada Mensah'"Any other command works the same way through make sp, for example make sp ARGS="tenant reset-password --slug acme --email [email protected]".
The output looks like this:
workspace "acme" created (0199c3a2-…)admin: [email protected]temporary password (shown once, valid for 72h0m0s, must be changed at first sign-in): 4kQ…| Option | Required | Meaning | Default |
|---|---|---|---|
--slug |
Yes | Short workspace name typed at sign-in. Lowercase letters, digits and hyphens, 2–63 characters, starting with a letter or digit | |
--name |
Yes | The institution’s display name | |
--admin-email |
Yes | Email address of the first administrator | |
--admin-name |
No | Display name of the first administrator | Administrator |
--kind |
No | psp, fintech, bank, mobile_money, microfinance or other |
psp |
--country |
No | Two-letter ISO country code | GH |
--currency |
No | Base currency (three-letter ISO code). Thresholds and reports are expressed in it | GHS |
--timezone |
No | IANA timezone. Rules such as “per calendar day” use it | Africa/Accra |
Then sign in at http://localhost:8080 with the workspace slug, the admin email and the temporary password. You will be asked to choose a new password, set up an authenticator app and save your recovery codes. Until the administrator has chosen their own password, their account’s status is invited.
If the first administrator’s password expires
Section titled “If the first administrator’s password expires”Inside the app, only an administrator can issue a temporary password. If the only administrator can’t sign in (their first temporary password expired, was lost, or they forgot their password), issue a new one from the command line. This is the operator’s break-glass:
cd backendtemporary password for [email protected] (shown once, valid for 72h0m0s, must be changed at sign-in): Zt8…| Option | Required | Meaning |
|---|---|---|
--slug |
Yes | The workspace’s slug |
--email |
Yes | The person’s sign-in email |
The command works for anyone in the workspace, not only administrators. It:
- replaces their password with the new temporary one, valid for 72 hours;
- signs them out everywhere and unlocks the account;
- keeps their roles and their authenticator app. It doesn’t reset two-factor; once they can sign in, another administrator can do that from Settings › People;
- leaves a disabled account disabled. Re-enable it in the app first if that person should get back in;
- is recorded in the audit log as
user.reset_passwordwith the actor system andvia: cli.
It connects to the database with SP_DB_URL, like tenant create. If the workspace or email doesn’t exist, it fails with find user … in … and changes nothing.
Next: send some data
Section titled “Next: send some data”With a workspace in place you can send transactions, customers and accounts through the ingest API, using an API key with the ingest:write scope. Follow Sending data for the steps. To fill the local stack with realistic mobile money traffic in one go, use the load generator.
How to work on the web app with live reload
Section titled “How to work on the web app with live reload”If you are changing the frontend, run the Vite development server alongside the backend:
make run # in one terminal: API on :8080make dev-web # in another terminal: UI on :5173Open http://localhost:5173. Changes to the frontend appear instantly, and API calls are forwarded to port 8080.
How to stop and reset
Section titled “How to stop and reset”make downstops the containers but keeps your data (it lives in Docker volumes). To start completely fresh, delete the volumes too:
docker compose -f deploy/compose/docker-compose.yml down -vIf something goes wrong
Section titled “If something goes wrong”| Symptom | Likely cause and fix |
|---|---|
make up fails with “port is already allocated” |
Another program is using 5432, 6379, 19092, 8081 or 8080. Stop it, or change the port mapping in docker-compose.yml and the matching setting in .env |
make migrate fails with “connection refused” |
Postgres is still starting. Wait a few seconds and run it again, or check make ps |
The browser shows UI not built: run make web |
The web app has not been compiled into the binary. Run make web, then restart make run |
make topics creates some topics, then fails on one |
The broker has run out of partitions: 16 topics × SP_KAFKA_PARTITIONS is more than it accepts. Set SP_KAFKA_PARTITIONS=6 in .env. Topics already created keep their size; to start over locally, see How to stop and reset. See Partitions |
make topics hangs or fails to connect |
Redpanda is not running, or SP_KAFKA_BROKERS does not point at localhost:19092. See Kafka troubleshooting |
unknown role "…" |
SP_ROLES or --role has a typo. Use all, or any of api, decision, ingest, persist, stream, worker |
More in Troubleshooting.