Development documentation
Purpose
This guide contains the minimum local context needed for contributors. It keeps the branch changes small and aligned with the project reset scope.
Local runbook
Start the project with either:
-
Docker Compose:
docker compose -f docker-compose.dev.yml up --build(the development stack; the rootdocker-compose.ymlis the production release)docker compose -f docker-compose.dev.yml down -vto reset local data
-
Phoenix from source:
mix deps.getmix ecto.setupmix phx.server
Required local checks
Run before opening a PR:
mix formatmix testmix coverallspre-commit run --all-filesnpm test --prefix mcp-servernpm run build --prefix mcp-server
The two npm checks need Node 24 (the Active LTS line). That version is
pinned in three places that must agree: actions/setup-node in CI,
engines.node in mcp-server/package.json, and the node:24-alpine image in
mcp-server/Dockerfile โ test/portfolixir/ci_test.exs asserts that they do,
and that @types/node describes the same major. Running the checks on another
major produces an EBADENGINE warning rather than an error; CI is the
authority.
If pre-commit is not installed:
pre-commit install --install-hooks
Measuring before activating a derived value
Which analytics run the :durable lifetime is a configuration decision
informed by measurement, never an architectural one
(ADR-0039 ยง2). The command
that produces the measurement seeds a deterministic synthetic ledger and times
every figure a surface waits on, twice, with the derived layer off:
DATABASE_NAME=portfolixir_bench mix ecto.create
DATABASE_NAME=portfolixir_bench mix ecto.migrate
DATABASE_NAME=portfolixir_bench mix portfolixir.derived.measure
It writes synthetic transactions, so point it at a throwaway database as
above โ the same convention priv/demo uses โ and it refuses to run in :prod.
--securities, --bookings and --years size the ledger; --skip-seed
measures whatever is already there.
An analytic that turns out cheap enough not to need a lifetime is a finding and is printed as one. Record the run in ADR-0039 next to the existing measurement rather than in a commit message, so the next activation decision has something to be compared against.
Scope guardrails
- Use synthetic fixture data only.
- Keep tests free from external network calls.
- Keep financial values in Decimal-backed fields.
- Keep architecture decisions local and explicit to the three domain modules plus web.