Template
CI reads Infisical staging as the read-only convexmonorepo-ci machine identity, deploys the Convex functions, builds and pushes the image, and asks the VPS to redeploy. Payload schema changes now ship as migrations that production runs on startup; the baseline matches the production schema and is recorded as applied there. The local stack moves to its own ports and syncs the Convex runtime env, and the scripts pick up Infisical account switching, dev-kill and a cache-safe CI install.
103 lines
3.8 KiB
Markdown
103 lines
3.8 KiB
Markdown
# Convex Turbo Monorepo
|
|
|
|
A reusable Bun/Turborepo template with Next.js 16, Expo, self-hosted Convex,
|
|
Payload CMS, shared UI/config packages, Vitest, and Docker deployment.
|
|
|
|
## Local setup
|
|
|
|
Requirements: Bun 1.3.14, Docker or Podman, Node 22, the Infisical CLI, `jq`, and
|
|
`flock`.
|
|
|
|
```sh
|
|
bun install --frozen-lockfile
|
|
infisical login
|
|
infisical init
|
|
bun db:up
|
|
bun dev:next
|
|
```
|
|
|
|
The committed `.infisical.json` links this repository to its own Infisical
|
|
project. Local commands read `dev` by default and never fall back to `.env`
|
|
files. Select staging with `INFISICAL_ENV=staging bun dev:next`.
|
|
|
|
Local services:
|
|
|
|
- Next.js: `http://localhost:3000`
|
|
- Convex API: `http://localhost:3240`
|
|
- Convex dashboard: `http://localhost:6794`
|
|
- Payload Postgres: `localhost:5436`
|
|
|
|
Next and Expo run on the host. Payload uses the local Postgres database. Convex
|
|
uses a separate self-hosted data volume and does not use Postgres by default.
|
|
The commented `POSTGRES_URL` in Compose is an opt-in example for cloned projects.
|
|
|
|
```sh
|
|
bun db:down # stop; preserve Payload and Convex data
|
|
bun db:down:wipe # remove both volumes, generated admin key, and seed marker
|
|
bun db:sync:payload # refresh/apply the local Payload seed snapshot from staging
|
|
```
|
|
|
|
`db:sync:payload` reads the staging `PAYLOAD_DB_URL`, saves a private PostgreSQL
|
|
snapshot under `.local/`, and replaces only the localhost Payload database. It
|
|
never writes to staging or Convex. Normal `bun db:up` never contacts staging;
|
|
it only restores `.local/payload-staging.dump` when the local database marker is
|
|
missing or stale. The marker is `.local/payload-seed-state.env`, not a database
|
|
table, so Payload schema push will not try to drop it. Stop the Next development
|
|
server first so it does not reconnect while the database is being replaced. The
|
|
snapshot includes Payload users and password hashes, allowing the same admin
|
|
credentials locally; protect it as production-derived data and delete it when no
|
|
longer needed.
|
|
|
|
Physical devices cannot resolve their own `localhost`; override the public
|
|
Convex URL with the development host's LAN address when testing Expo on-device.
|
|
|
|
## Environment model
|
|
|
|
- Local `dev` and `staging`: Infisical.
|
|
- Generated local state: `.local/<environment>.generated.env`.
|
|
- CI/CD: Infisical `staging`, read by the read-only `convexmonorepo-ci` machine
|
|
identity and materialized only as a temporary runner file.
|
|
- Docker compilation: explicit Compose build args; `.env*` stays outside the
|
|
image context.
|
|
|
|
Run `sh scripts/with-env dev -- <command>` for an environment-aware command or
|
|
`sh scripts/export-env dev` to materialize a temporary merged dotenv stream.
|
|
Do not commit or maintain root `.env` files.
|
|
|
|
## Development and quality
|
|
|
|
```sh
|
|
bun dev:next
|
|
bun dev:expo
|
|
bun lint:ws
|
|
bun format
|
|
bun lint
|
|
bun typecheck
|
|
bun test:unit
|
|
bun test:integration
|
|
bun test:component
|
|
SKIP_E2E=1 bun run ci:check
|
|
```
|
|
|
|
`bun test:e2e` starts the isolated local stack and currently performs generic
|
|
stack smoke checks. It skips in CI and when `SKIP_E2E=1` is set.
|
|
|
|
Shared dependency versions belong in root catalogs. Edit the root catalog, run
|
|
`bun install`, then `bun lint:ws`; do not run `bun update` inside a workspace.
|
|
|
|
## Deployment
|
|
|
|
Production Compose retains the self-hosted Convex backend/dashboard and accepts
|
|
an external Payload `PAYLOAD_DB_URL`. Its commented Postgres service remains an
|
|
optional Payload database.
|
|
|
|
A push to `main` runs the quality gate, deploys the Convex functions, builds the
|
|
Next image, pushes SHA and `latest` tags, and asks the VPS to redeploy
|
|
`podman-convexmonorepo.service` over the forced-command deploy key. If that last
|
|
step fails, the nightly update timer deploys the image instead. Each job reads
|
|
Infisical `staging` through `scripts/ci-export-env.mjs` as the `convexmonorepo-ci`
|
|
machine identity (Gitea secrets `INFISICAL_CLIENT_ID` and
|
|
`INFISICAL_CLIENT_SECRET`).
|
|
|
|
Payload schema changes ship as migrations; see `AGENTS.md`.
|