# 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.10, Docker or Podman, Node 22, and the Infisical CLI.

```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:3210`
- Convex dashboard: `http://localhost:6791`
- Payload Postgres: `localhost:5432`

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: Gitea `DOTENV_PROD`, 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. Gitea runs the quality gate first, builds the Next
image from a temporary Gitea-secret env file, then pushes SHA and `latest` tags.
CI never installs or invokes Infisical.
