Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI

on:
pull_request:
push:
branches:
- dev
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
ci:
name: Typecheck, lint, test, and build
runs-on: ubuntu-latest
env:
CI: true

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Enable pnpm from packageManager
run: corepack enable && corepack prepare pnpm@10.33.0 --activate

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Check types
run: pnpm check-types

- name: Lint
run: pnpm lint

- name: Unit and component tests
run: pnpm test

- name: Build web
run: pnpm --filter web build

- name: Verify database static checks
run: pnpm --filter @repo/db db:verify:static
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ node_modules/

# Local env files
.env*
!.env.example
!.env.*.example
!**/.env.example
!**/.env.*.example


# Testing
Expand Down
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ pnpm install
Start local development:

```bash
pnpm run doctor
pnpm dev
pnpm dev:web:tunnel
pnpm dev:web:scan
```

Expand All @@ -36,9 +38,12 @@ pnpm --filter mobile dev
pnpm self-host:up
```

Run the main validation commands before opening a PR:
Run the main validation commands before handoff or review:

```bash
pnpm verify:static
pnpm verify
pnpm verify:full
pnpm knip
pnpm knip:full
pnpm check-types
Expand All @@ -48,15 +53,15 @@ pnpm test

## Development workflow

1. Create a focused branch for one change.
1. Work from the shared `dev` checkout for normal focused changes.
2. Make the smallest change that solves the problem.
3. Run the relevant checks locally.
4. Open a PR with a short summary of the user-facing outcome.
4. Commit to `dev` after checks pass; open a PR only for explicit review, release, or hotfix flows.

## Multi-Agent Workflow

- Keep orchestration and review in the root checkout.
- For medium and large efforts, use one Worktrunk worktree per bounded lane under `~/GradientPeak/.worktrees/<branch>`.
- For medium and large efforts, use one worktree per bounded lane under `~/GradientPeak/.worktrees/<branch>`.
- Keep all GradientPeak worktrees inside the repo-local `.worktrees/` directory.
- Use branch names shaped like `spec/<spec-slug>/<lane>` for multi-lane efforts.
- Require merge packets and a fan-in owner before integrating parallel lane outputs.
Expand All @@ -66,9 +71,8 @@ pnpm test
- `apps/web/README.md` covers web-specific setup and commands.
- `apps/mobile/README.md` covers mobile-specific setup, testing, and E2E entrypoints.
- `packages/db/README.md` covers database ownership and local DB tooling.
- `provider-onboarding.md` documents the recommended flow for onboarding a new third-party provider starting from the current Wahoo-first setup.

Environment files should live with the owning app or package, not at the repo root.
Environment files should live with the owning app or package, not at the repo root. Start from the checked-in `.env.example` files and keep secret-bearing `.env` files untracked.

Git hooks are managed with `lefthook` and install automatically from `pnpm install`.

Expand Down
21 changes: 21 additions & 0 deletions apps/mobile/.env.e2e.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# GradientPeak mobile Maestro/E2E template.
# Copy to apps/mobile/.env.e2e for local Maestro runs.

APP_ENV=development
EXPO_PUBLIC_MAESTRO_E2E=1
EXPO_PUBLIC_API_URL=http://127.0.0.1:3000
EXPO_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
EXPO_PUBLIC_MAESTRO_E2E_API_URL=http://10.0.2.2:3000
EXPO_PUBLIC_MAESTRO_E2E_SUPABASE_URL=http://10.0.2.2:54321
EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
EXPO_PUBLIC_REDIRECT_URI=gradientpeak-dev://integrations
EXPO_PUBLIC_GOOGLE_API_KEY=
MAESTRO_APP_ID=com.deancochran.gradientpeak.dev
MAESTRO_SIGNUP_EMAIL_PREFIX=gradientpeak.maestro
MAESTRO_SIGNUP_EMAIL_DOMAIN=example.com

# Sentry and PostHog are normally disabled for E2E unless these are filled.
EXPO_PUBLIC_SENTRY_DSN=
EXPO_PUBLIC_ENABLE_SENTRY_IN_DEV=0
EXPO_PUBLIC_POSTHOG_KEY=
EXPO_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
25 changes: 25 additions & 0 deletions apps/mobile/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# GradientPeak mobile local development template.
# Copy to apps/mobile/.env and fill in real local or hosted values.

APP_ENV=development
EXPO_PUBLIC_APP_SCHEME=gradientpeak-dev
EXPO_PUBLIC_API_URL=http://localhost:3000
EXPO_PUBLIC_SUPABASE_URL=http://localhost:54321
EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
EXPO_PUBLIC_REDIRECT_URI=gradientpeak-dev://integrations
EXPO_PUBLIC_GOOGLE_API_KEY=
EXPO_PUBLIC_ENABLE_SERVER_OVERRIDE=1
EXPO_PUBLIC_ENABLE_MOBILE_LOGS=0

# Sentry and PostHog telemetry. Leave blank to disable local telemetry.
EXPO_PUBLIC_SENTRY_DSN=
EXPO_PUBLIC_ENABLE_SENTRY_IN_DEV=0
EXPO_PUBLIC_SENTRY_TRACES_SAMPLE_RATE=1
EXPO_PUBLIC_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=1
EXPO_PUBLIC_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=0
SENTRY_ORG=
SENTRY_PROJECT=
SENTRY_AUTH_TOKEN=
EXPO_PUBLIC_POSTHOG_KEY=
EXPO_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
EXPO_PUBLIC_POSTHOG_DEBUG=0
10 changes: 5 additions & 5 deletions apps/mobile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Run these from the repo root:

```bash
pnpm --filter mobile dev
pnpm --filter mobile storybook
pnpm --filter mobile storybook:start
pnpm --filter mobile check-types
pnpm --filter mobile lint
pnpm --filter mobile test
Expand All @@ -40,13 +40,13 @@ pnpm --filter mobile test:e2e

```bash
pnpm --filter mobile android:dev
pnpm --filter mobile android:e2e:build
pnpm --filter mobile generate:maestro
pnpm --filter mobile maestro:lane -- smoke
pnpm --filter mobile maestro:prepare
pnpm --filter mobile test:e2e
pnpm --filter mobile test:e2e:flow -- .maestro/flows/main
```

## Related docs

- `apps/mobile/.maestro/README.md` for Maestro flow execution.
- `apps/mobile/scripts/maestro.mjs` wraps Maestro setup, launch, cleanup, and flow execution.
- `README.md` for repo-level workflow and validation commands.
- `packages/db/README.md` for local DB tooling used by app-backed workflows.
61 changes: 61 additions & 0 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# GradientPeak web local development template.
# Copy to apps/web/.env.local and fill in provider/client secrets as needed.

APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3000
BETTER_AUTH_SECRET=local-development-secret-change-me

DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PRIVATE_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
NEXT_PRIVATE_SUPABASE_SECRET_KEY=
SUPABASE_SERVICE_ROLE_KEY=

SUPABASE_AUTH_SITE_URL=http://localhost:3000
SUPABASE_AUTH_WEB_REDIRECT_URL=http://localhost:3000/auth/confirm
SUPABASE_AUTH_WEB_REDIRECT_URL_SECURE=http://localhost:3000/auth/confirm

OAUTH_CALLBACK_BASE_URL=http://localhost:3000
WAHOO_WEBHOOK_TOKEN=
STRAVA_CLIENT_ID=
STRAVA_CLIENT_SECRET=
WAHOO_CLIENT_ID=
WAHOO_CLIENT_SECRET=
TRAININGPEAKS_CLIENT_ID=
TRAININGPEAKS_CLIENT_SECRET=
GARMIN_CLIENT_ID=
GARMIN_CLIENT_SECRET=
ZWIFT_CLIENT_ID=
ZWIFT_CLIENT_SECRET=

NEXT_PUBLIC_MOBILE_AUTH_REDIRECT_URI=gradientpeak-dev://auth/confirm
NEXT_PUBLIC_MOBILE_REDIRECT_URI=gradientpeak-dev://integrations
NEXT_PUBLIC_MOBILE_REDIRECT_FALLBACK=gradientpeak-dev://integrations
AUTH_ALLOWED_DEEP_LINK_PREFIXES=gradientpeak-dev://,gradientpeak://
EXPO_PUBLIC_APP_SCHEME=gradientpeak-dev

AUTH_EMAIL_MODE=smtp
AUTH_EMAIL_FROM=GradientPeak Local <noreply@localhost>
AUTH_EMAIL_REPLY_TO=noreply@localhost
AUTH_SMTP_HOST=127.0.0.1
AUTH_SMTP_PORT=54324

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point local SMTP at Inbucket's SMTP port

With this template, any developer who copies apps/web/.env.example and uses AUTH_EMAIL_MODE=smtp will send Nodemailer to port 54324. In our Supabase config that port is the Inbucket web UI (packages/db/supabase/config.toml:92-95); the SMTP listener is 54325, so verification/reset emails fail to send instead of appearing in Inbucket. Set this to 54325 or change the Supabase SMTP port to match.

Useful? React with 👍 / 👎.

AUTH_SMTP_USER=
AUTH_SMTP_PASS=
AUTH_SMTP_SECURE=false

# Sentry and PostHog telemetry. These are safe to leave blank for local work.
# Fill them when you want the local dev server/browser to send events upstream.
APP_ENV=development
SENTRY_DSN=
SENTRY_TRACES_SAMPLE_RATE=1
VITE_SENTRY_DSN=
VITE_SENTRY_TRACES_SAMPLE_RATE=1
POSTHOG_KEY=
POSTHOG_HOST=https://us.i.posthog.com
POSTHOG_SECRET_KEY=
POSTHOG_PERSONAL_API_KEY=
VITE_POSTHOG_KEY=
VITE_POSTHOG_HOST=https://us.i.posthog.com
VITE_POSTHOG_DEBUG=0
7 changes: 4 additions & 3 deletions apps/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ pnpm install
Run the web app:

```bash
pnpm --filter web dev
pnpm --filter web dev:local
pnpm --filter web dev:tunnel
```

Run the main checks:
Expand Down Expand Up @@ -103,10 +104,10 @@ SMTP sinks.

## Container Publishing

The production container workflow is defined in:
Production container publishing should be defined in:

- `.github/workflows/publish-container.yml`

It now builds:
When restored/enabled, it should build:

- `apps/web/Dockerfile`
7 changes: 5 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
"private": true,
"type": "module",
"scripts": {
"dev": "concurrently \"pnpm run dev:app\" \"pnpm run dev:ngrok\"",
"dev": "pnpm run dev:local",
"dev:local": "pnpm run dev:app",
"dev:tunnel": "concurrently \"pnpm run dev:app\" \"pnpm run dev:ngrok\"",
"dev:app": "pnpm exec dotenv -e .env.local -- vite dev --host 0.0.0.0 --port 3000",
"dev:wahoo-drain": "pnpm exec dotenv -e .env.local -- node scripts/drain-wahoo-provider-sync.mjs",
"dev:wahoo-drain:direct": "pnpm exec dotenv -e .env.local -- vite-node scripts/drain-wahoo-provider-sync-direct.ts",
"dev:wahoo-drain:once": "pnpm exec dotenv -e .env.local -- node scripts/drain-wahoo-provider-sync.mjs --once",
"dev:ngrok": "ngrok http --domain=outgoing-ape-repeatedly.ngrok-free.app 3000",
"dev:scan": "concurrently \"VITE_ENABLE_REACT_SCAN=1 pnpm run dev:app\" \"pnpm run dev:ngrok\"",
"dev:scan": "VITE_ENABLE_REACT_SCAN=1 pnpm run dev:app",
"dev:scan:tunnel": "concurrently \"VITE_ENABLE_REACT_SCAN=1 pnpm run dev:app\" \"pnpm run dev:ngrok\"",
"build": "vite build",
"check-types": "tsc --noEmit",
"preview": "vite preview",
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
"audit:forms": "node tooling/forms/audit-forms.mjs",
"check": "biome check apps packages tooling .github README.md package.json pnpm-workspace.yaml turbo.json biome.json",
"check:ci": "biome ci apps packages tooling .github README.md package.json pnpm-workspace.yaml turbo.json biome.json",
"dev": "pnpm --filter web dev",
"doctor": "node tooling/doctor.mjs",
"dev": "pnpm --filter web dev:local",
"dev:all": "turbo run dev",
"dev:clean": "pnpm exec k 3000 3100 8081 8082 || true && pnpm run self-host:down >/dev/null 2>&1 || true && printf '[dev-clean] local web/mobile dev servers and Supabase stopped\n'",
"dev:e2e": "turbo run dev:e2e --parallel --ui tui",
"dev:web": "pnpm --filter web dev",
"dev:web:local": "pnpm --filter web dev:local",
"dev:web:tunnel": "pnpm --filter web dev:tunnel",
"dev:wahoo-drain": "pnpm --filter web dev:wahoo-drain",
"dev:wahoo-drain:direct": "pnpm --filter web dev:wahoo-drain:direct",
"dev:wahoo-drain:once": "pnpm --filter web dev:wahoo-drain:once",
Expand Down Expand Up @@ -57,6 +60,9 @@
"test": "turbo run test",
"test:parity": "pnpm exec vitest run --config vitest.parity.config.ts",
"test:e2e:web": "pnpm --filter web test:e2e",
"verify:static": "pnpm check && pnpm check-types",
"verify": "pnpm verify:static && pnpm test",
"verify:full": "pnpm verify && pnpm knip",
"quality:agent": "pnpm check && pnpm check-types && pnpm test && pnpm knip",
"self-host:up": "pnpm --filter @repo/db self-host:up",
"self-host:down": "pnpm --filter @repo/db self-host:down"
Expand Down
6 changes: 6 additions & 0 deletions packages/db/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# GradientPeak local database template.
# Copy to packages/db/.env when DB package commands need explicit connection values.

DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
SUPABASE_DB_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
Loading
Loading