Local Development in the Pivot Repositories
Clone pivot and pivot-internal
Install system dependencies
- Git
- Docker
- Node and npm
- pnpm
- Go
- Rust/Cargo (for Tauri desktop app builds)
- Terraform CLI (if you will be editing Terraform modules in
pivot-internal) - Atlas CLI (opens in a new tab)
pnpm install
From the root of each repository.
tools/scripts/go-tools-install.sh
From the root of the pivot repo to install Go CLI dependencies, such as for
generating Protobuf code. You likely need to
chmod +x tools/scripts/go-tools-install.sh before running this shell script.
npx buf generate
This is a necessary codegen step whenever cloning the repo or changing .proto
files. It will generate a folder called gen/ that is ignored by Git.
Use docker compose
Running docker compose up from the root of the pivot repository starts all
backing services like Postgres, Cassandra, Valkey, NATS, and AWS service
emulations (S3, SES). Turbopuffer is a managed service and cannot be run
locally; development involving Quest may require mocking or connecting to a
shared dev instance.
Once the necessary backing services are started, all our container-based backend
services (that we deploy to ECS in staging/production) will start as well (and
should automatically apply any Postgres database migrations). Docker will watch
the source directories for those services and will rebuild the image and
redeploy into the docker compose environment when changes are made.
As described here, Docker will
inject configuration values and secrets using an entirely local stack, so no
real secrets are needed unless you need to connect to a dependency that can't be
run or emulated locally. If so, these overwridden values can be set using the
--env-file
CLI argument (opens in a new tab).
Alternatives
AMD64
The following commands have been tested on an AMD64 architecture and serve as
alternatives to running docker compose up directly.
docker compose up database nats nats-init localstack localstack-initwill run create (if not existent) and start containers for Postgres, NATS, and LocalStack.(npx or pnpm) nx serve {projectName}can be used to run individual projects (only one project at a time).(npx or pnpm) nx run-many -t serve -p {projectName1} {projectName2}...can be used to run multiple projects at once.
Seeder
Run the seeder app with pnpm nx execute seeder to add data to the running
Docker services. We also use Seeder in CI to test backend service APIs for
breaking changes.
Use nx
Both pivot and pivot-internal use Nx as a multi-language monorepo framework.
pnpm nx is used to serve, build, test, and lint. Prefix your nx
commands with pnpm rather than installing Nx globablly and rather than using
npx to ensure that all developers use the version of Nx specified in the
package.json.
Run pnpm nx serve {projectName} with the name of the project from the relevant
project.json file to run apps in development mode. For the pivot repo, you
only need to do this after running docker compose up if you want to run
frontend apps. The backend services that run in ECS in production are all
started via Docker (though you can run serve for them as well if you want one
outside of Docker -- hot reload will be faster that way).
As described here, for applications
that require environment variables, Nx will inject them based on the .env file
in each app directory, which is committed to source control. You can create a
.env.local file to override any variable defined in the .env with actual
secrets that will be gitignore'd.
Expo Custom Development Client
For previewing frontend changes on mobile, you will need to install our Expo custom development client -- Expo Go will not work because we have custom native modules beyond the Expo standard runtime.
Using NATS
You can manually explore NATS streams and subjects with the NATS CLI.
nats sub --user pivot_facebox_user --password pivot_facebox_password facebox.change_feed.user.updatedV1Installing Dependencies and Creating New Services Using Make
Check out the MAKEFILE to explore the available commands.
Generating a new Go backend service:
make cookiecutter
make service SERVICE_NAME=<<service_name>>Using Postgres, Ent, Atlas
For backend Go services that use the Ent ORM, Atlas is used for migrations against Postgres.
Ent
Create entities
# from apps/facebox
go run -mod=readonly entgo.io/ent/cmd/ent new EntityNameGenerate code
# from repo root
go generate ./apps/facebox/internal/entAtlas
Note that the Atlas CLI must be installed on your development machine to create (or even apply) migrations. This means the app will fail to start without first installing the Atlas CLI (opens in a new tab).
Create a new migration
cd apps/facebox
atlas migrate diff migration_name \
--dir "file://internal/ent/migrate/migrations" \
--to "ent://internal/ent/schema" \
--dev-url "docker://postgres/16/test?search_path=public"Update your local database to match the Ent schema (good for local dev before you actually create a migration)
atlas schema apply \
-url "postgres://pivot_facebox_user:pivot_facebox_password@localhost:5432/pivot_facebox?sslmode=disable" \
--to "ent://apps/facebox/ent/schema"Wipe your local database (if schema apply is failing)
atlas schema clean \
-url "postgres://pivot_facebox_user:pivot_facebox_password@localhost:5432/pivot_facebox?sslmode=disable" \
--auto-approveLint the migrations directory to run checks (this also runs in CI)
atlas migrate lint \
--latest 100 \
--dir "file://apps/facebox/ent/migrate/migrations" \
--dev-url "docker://postgres/15/test?search_path=public"After customizing a migration, regenerate the hash
atlas migrate hash \
--dir "file://internal/ent/migrate/migrations"Atlas CLI commands (opens in a new tab).
Using Postgres, Drizzle, and Drizzle Kit
We use Drizzle as our TypeScript ORM. It comes with a CLI companion,
drizzle-kit that we can use in local development, but which is not actually
needed to run migrations, just to generate them.
Generate a new migration file
pnpm drizzle-kit generate:pg --config=apps/buzzbuzz/src/drizzle/drizzle.config.tsPrior to generating a migration, it can be helpful to force your local database to match the schema files
pnpm drizzle-kit push:pg --config=apps/buzzbuzz/src/drizzle/drizzle.config.tsUsing Git Hooks
In the root of the pivot repo, you will find a folder called githooks, which
contains commands that will be run whenever some actions are performed.
The purpose of using hooks is to automate some tasks that need to run whenever switching branches or pulling changes, for example (i.e. running buf generate).
To enable all git hooks, run the following command in the project root directory (only once):
git config core.hooksPath './githooks'Emulating AWS Services with LocalStack
LocalStack runs via docker compose in the pivot repo. Be sure to allow the
localstack-init container to run at first launch.
Use the LocalStack dashboard (opens in a new tab) from your browser to connect to the LocalStack docker container from a GUI. This is free of charge.
Services connect to LocalStack via the https://localhost.localstack.cloud
environment veriable, not localhost directly.