X
Github
Discord
basecoat
Privacy Policy•Terms of Service•Cookie Policy•Help
Introduction
Highlights
wwwwwwwwwwwwwwwwwww
PreviousHighlights

Edit this page on GitHub.

Deployment Overview

Deploy Basecoat with SST and Cloudflare

Basecoat deploys with SST targeting Cloudflare. The web app, LiveStore sync worker, Durable Object backend, and media storage should all be configured around that platform.

Local development

Run the app and sync backend in separate terminals:

bun run livestore:sync
bun run dev

The LiveStore sync worker uses apps/livestore-sync/wrangler.jsonc locally and the app reads VITE_LIVESTORE_SYNC_URL.

Production environment

Required production values include:

BETTER_AUTH_SECRET=your-production-secret
BETTER_AUTH_URL=https://basecoat.app
ONE_SERVER_URL=https://basecoat.app
CLOUDFLARE_API_TOKEN=your-cloudflare-api-token
CLOUDFLARE_R2_ENDPOINT=...
CLOUDFLARE_R2_ACCESS_KEY=...
CLOUDFLARE_R2_SECRET_KEY=...
CLOUDFLARE_R2_PUBLIC_URL=...
LIVESTORE_SYNC_URL=wss://livestore.basecoat.app
VITE_LIVESTORE_SYNC_URL=wss://livestore.basecoat.app
WEB_DOMAIN=basecoat.app

Sync backend

The LiveStore sync backend runs as a Cloudflare Worker backed by a Durable Object. SST owns the production deployment, while Wrangler supports local development.

Media

Uploaded images and videos are stored in R2 or another S3-compatible object store. LiveStore events carry metadata and storage references, not media binaries.

Versioning model

Product semver is tracked in two deployable workspaces, kept in sync by Release Please:

PackagePathBumped by
App (web + mobile)apps/basecoat/package.json versionRelease Please
LiveStore sync workerapps/livestore-sync/package.json versionRelease Please (linked to app)

Both share CHANGELOG.md at the repo root. The linked-versions plugin ensures a single Release PR bumps both to the same semver.

Native store / OTA targeting uses a separate field on the app package only:

FieldBumped byUsed for
nativeVersion in apps/basecoat/package.jsonYou, when native fingerprint changesruntimeVersion, OTA targeting, store binary compatibility

Release Please only bumps version on the app and sync worker. OTA bundles target nativeVersion via Hot Updater’s appVersion strategy (runtimeVersion in app.config.ts).

When adding native modules, plugins, or native config, bump native version:

bun tko release/bump-native-version

CI fails on main if the Expo fingerprint changed but nativeVersion did not.

CI/CD

CI (ci.yml) runs on every push/PR: check, lint, format, unit tests.

Product versioning (release-please.yml) runs on every push to main. It opens or updates a Release Please PR that bumps version in apps/basecoat/package.json and apps/livestore-sync/package.json, updates CHANGELOG.md, and updates .release-please-manifest.json from Conventional Commits (feat: → minor, fix: → patch, feat!: / BREAKING CHANGE: → major).

Merge that Release PR when you want a product version cut. This pipeline does not create GitHub Releases — changelog and semver live in the repo only.

Deploy pipelines (separate lifecycles, triggered manually or after CI on main):

WorkflowPurposeSkip when
release-please.ymlProduct semver + CHANGELOG.md—
release-web.ymlOne web + API production buildVersion/changelog-only merge
release-livestore-sync.ymlLiveStore sync Worker (path-filtered push)No sync paths changed
release-mobile.ymlOTA or store builds (fingerprint classify)Version/changelog-only merge

Commit scopes (feat(paint), fix(livestore-sync)) are for CHANGELOG readability only. They do not drive semver bumps or deploy routing. Deploy routing uses changed paths and Expo fingerprint diff.

Mobile release router

release-mobile.yml compares @expo/fingerprint at the merge commit vs its parent.

  • Fingerprint unchanged → OTA hot update to the production channel (matches APP_VARIANT=production in store builds).
  • Fingerprint changed → ios-cd and/or android-cd store builds (requires nativeVersion bump in the same merge).

Manual overrides: dispatch release-mobile with force_strategy (ota / native), channel, rollout percentage, or force-update flag.

Preview store builds on PRs still use the native: commit/title gate.

Conventional commit scopes (optional)

Use scopes for humans and CHANGELOG grouping — not for automation.

Deployable: web, livestore-sync, mobile, hot-update, ci, release-please, deps

Domain: collection, model, paint, paint-scheme, mixes, session, dashboard, auth, profile, settings, notifications, interface, livestore

Cross-platform features: scope by primary intent (feat(paint): …). Put platform-specific work in separate commits when deploy paths differ (feat(mobile): add expo-camera). Mention Requires-Native-Build: yes in the commit body when relevant.