Merge pull request #330 from trails-cool/document-https-dev-special-cases
Document why HTTPS=1 dev exists, and the one case that still needs it
This commit is contained in:
commit
ba3a619160
3 changed files with 111 additions and 2 deletions
34
CLAUDE.md
34
CLAUDE.md
|
|
@ -68,6 +68,40 @@ pnpm db:push # Push Drizzle schema to local PostgreSQL
|
|||
pnpm db:studio # Open Drizzle Studio (DB browser)
|
||||
```
|
||||
|
||||
### Local HTTPS dev (rare — most contributors never need this)
|
||||
|
||||
The default dev loop runs the journal on plain HTTP at
|
||||
`http://localhost:3000`. WebAuthn passkeys, magic links, sessions, the
|
||||
Terms gate, SSE — everything works over HTTP because the WebAuthn spec
|
||||
treats `localhost` as a secure context regardless of scheme. CI's e2e
|
||||
suite runs over plain HTTP too.
|
||||
|
||||
There is exactly one feature that requires local HTTPS: **Wahoo OAuth**.
|
||||
Wahoo (and most OAuth providers) reject `http://` redirect URIs, so the
|
||||
`/api/sync/connect/wahoo` callback flow can only complete against an
|
||||
HTTPS dev server. To run that flow:
|
||||
|
||||
```bash
|
||||
HTTPS=1 ORIGIN=https://localhost:3000 pnpm --filter @trails-cool/journal dev
|
||||
```
|
||||
|
||||
`HTTPS=1` enables the `@vitejs/plugin-basic-ssl` cert + the ALPN
|
||||
HTTP/1.1 workaround in `apps/journal/vite.config.ts`. `ORIGIN` makes the
|
||||
WebAuthn server expect the HTTPS origin (set this together with HTTPS=1
|
||||
or you'll get origin-mismatch errors). Use `pnpm --filter` (not
|
||||
`pnpm dev`) because turbo doesn't pass `HTTPS` through unless added to
|
||||
its `globalPassThroughEnv` — `pnpm --filter` bypasses turbo entirely.
|
||||
|
||||
**Don't set `ORIGIN=https://localhost:3000` in your `apps/journal/.env`
|
||||
unless you intend to always run with `HTTPS=1`.** Mismatched values
|
||||
break the e2e suite and generic dev. See
|
||||
`apps/journal/.env.example` for what each var means.
|
||||
|
||||
If you find yourself wanting `HTTPS=1` for any reason other than Wahoo
|
||||
testing, write it down here so the assumption stays auditable —
|
||||
"everything but Wahoo works over HTTP locally" is what keeps CI and
|
||||
local config symmetric.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
- **Unit tests** (Vitest + jsdom): For packages, components, utilities, and app logic.
|
||||
|
|
|
|||
55
apps/journal/.env.example
Normal file
55
apps/journal/.env.example
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Journal local-dev environment.
|
||||
# Copy to `.env` (gitignored) and edit. Most contributors don't need
|
||||
# anything in this file — the journal app boots on plain HTTP at
|
||||
# http://localhost:3000 with sensible defaults.
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
# DO NOT SET unless you know you need it
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
#
|
||||
# `ORIGIN` is what the WebAuthn ceremony uses as `expectedOrigin`.
|
||||
# When unset it defaults to `http://localhost:3000`, which is what
|
||||
# Playwright sends and what the browser sees in plain-HTTP dev.
|
||||
#
|
||||
# The ONLY reason to set this is if you're running the dev server
|
||||
# over HTTPS (see HTTPS=1 below) and want passkey registration to
|
||||
# succeed against the HTTPS origin. If you set it to `https://...`
|
||||
# without also running the server over HTTPS, you'll get
|
||||
# "Unexpected registration response origin" errors in dev and the
|
||||
# local e2e suite (which always hits HTTP) will fail registration.
|
||||
#
|
||||
# ORIGIN=https://localhost:3000
|
||||
|
||||
# Flagship marker. Renders the project marketing block on the
|
||||
# anonymous home and gates a few "this is the canonical instance"
|
||||
# behaviors. Self-hosted instances leave this unset; flagship CI
|
||||
# sets it to `true`. Either is fine for local dev — set it if you
|
||||
# want to see the full marketing layout, leave it unset if you
|
||||
# want the self-host home view.
|
||||
# IS_FLAGSHIP=true
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
# Wahoo OAuth (only needed when actively testing the Wahoo import)
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Wahoo's OAuth flow is the one feature that genuinely needs HTTPS
|
||||
# locally: the provider rejects `http://` redirect URIs. To exercise
|
||||
# the connect/disconnect/import flow end-to-end, you need:
|
||||
#
|
||||
# 1. Local HTTPS dev server: run `HTTPS=1 pnpm --filter
|
||||
# @trails-cool/journal dev` (the basic-ssl plugin in
|
||||
# vite.config.ts wires up the cert; see the comment there for
|
||||
# the ALPN workaround).
|
||||
# 2. ORIGIN=https://localhost:3000 (uncomment above).
|
||||
# 3. Wahoo client credentials below, and a redirect URI of
|
||||
# `https://localhost:3000/api/sync/callback/wahoo` registered
|
||||
# in your Wahoo developer dashboard.
|
||||
#
|
||||
# WAHOO_CLIENT_ID=
|
||||
# WAHOO_CLIENT_SECRET=
|
||||
# WAHOO_WEBHOOK_TOKEN=
|
||||
|
||||
# Integration test secret (only needed if running the integration
|
||||
# test suite that drives the API directly). Generate with
|
||||
# `openssl rand -hex 32`.
|
||||
# INTEGRATION_SECRET=
|
||||
|
|
@ -11,6 +11,26 @@ export default defineConfig({
|
|||
plugins: [
|
||||
tailwindcss(),
|
||||
reactRouter(),
|
||||
// Local HTTPS dev is OPT-IN via `HTTPS=1`. Plain HTTP is the default
|
||||
// and the right choice for ~everything: WebAuthn (passkeys) treats
|
||||
// `localhost` as a secure context regardless of scheme, magic links
|
||||
// work over HTTP, sessions / Terms gate / SSE all work over HTTP.
|
||||
// CI doesn't set HTTPS=1 either — the e2e suite runs against the
|
||||
// production `react-router-serve` build over plain HTTP and passes
|
||||
// cleanly. So most contributors should never touch this flag.
|
||||
//
|
||||
// The one case where you DO need HTTPS=1 locally:
|
||||
// - Wahoo OAuth callback testing — Wahoo (and most OAuth
|
||||
// providers) reject `http://` redirect URIs, so the
|
||||
// /api/sync/connect/wahoo flow can only complete against an
|
||||
// HTTPS dev server. See docs/tooling.md for the full
|
||||
// command (`HTTPS=1 ORIGIN=https://localhost:3000 pnpm
|
||||
// --filter @trails-cool/journal dev`) and gotchas.
|
||||
//
|
||||
// If you find yourself wanting HTTPS=1 for any other reason, write
|
||||
// it down in docs/tooling.md — the assumption that "everything but
|
||||
// Wahoo works over HTTP locally" is what keeps the CI/local
|
||||
// configurations symmetric.
|
||||
...(process.env.HTTPS === "1" ? [import("@vitejs/plugin-basic-ssl").then((m) => m.default())] : []),
|
||||
sentryVitePlugin({
|
||||
org: "trails-qq",
|
||||
|
|
@ -36,8 +56,8 @@ export default defineConfig({
|
|||
// `singleFetchAction` compares `Origin` against the `Host` header,
|
||||
// which HTTP/2 replaces with `:authority` and Node doesn't
|
||||
// synthesize back. Restricting ALPN to `http/1.1` keeps the Host
|
||||
// header intact and lets fetcher form submissions through.
|
||||
// Plain HTTP dev (the default) is unaffected.
|
||||
// header intact and lets fetcher form submissions through. Only
|
||||
// matters when `HTTPS=1` is set — see the plugins comment above.
|
||||
https: process.env.HTTPS === "1" ? { ALPNProtocols: ["http/1.1"] } : undefined,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue