Commit Graph
5 Commits
Author SHA1 Message Date
BBergleandClaude Sonnet 5 7bef79fae5 feat(web): SvelteKit PWA shell with login
CI / Repo hygiene (pull_request) Successful in 2s
CI / API (lint, types, tests) (pull_request) Successful in 2s
CI / Migrations reversible (pull_request) Successful in 3s
CI / Web (lint, typecheck, build) (pull_request) Failing after 8s
Phase 0 scaffolding for the frontend: SvelteKit + adapter-static in SPA mode
(fallback index.html, ssr disabled in the root layout — no Node process in
production, Caddy serves build/ directly per docs/PLAN.md), a login page and
auth store backed by /api/v1/auth/{login,me,logout}, an installable-PWA shell
(hand-written manifest, iOS meta/safe-area handling, an install-onboarding
banner), and a Dockerfile whose only job is to produce a buildable /app/build
artifact for deploy/ to consume.

Service worker notes, since the wiring isn't obvious from the diff:

- injectManifest, not generateSW: the caching policy needs to say "never
  cache /api/*", which generateSW's declarative config can't express as
  precisely as hand-written Workbox routes can.
- Uses the base `vite-plugin-pwa` plugin, not `@vite-pwa/sveltekit`'s
  SvelteKit-specific wrapper. That wrapper's injectManifest build expects
  SvelteKit's own built-in src/service-worker.{js,ts} convention to have
  already transpiled the file — but that native build only permits importing
  SvelteKit's own three virtual modules and hard-rejects `workbox-*` imports,
  which our SW needs. The base plugin bundles src/service-worker.ts directly
  instead, which works. SvelteKit's native service-worker convention is
  explicitly disabled (`kit.files.serviceWorker` pointed at a path that
  doesn't exist) so the two builds can't collide and silently clobber each
  other's output — they do, if both are left enabled, and the failure mode is
  silent (the SW builds fine, just precaches nothing).
- workbox-core/precaching/routing/strategies had to be added as direct
  devDependencies even though workbox-build depends on them — pnpm doesn't
  hoist transitive deps into the top-level node_modules, so the SW bundle
  step couldn't resolve them otherwise.
- The SPA fallback index.html doesn't exist yet at service-worker-build time
  (adapter-static writes it after all Vite plugins finish), so it can't be
  glob-hashed into the precache manifest normally. It gets a synthetic
  manifest entry instead, revisioned by a per-build-invocation timestamp
  (see the swIndexRevision comment in vite.config.ts) so the cached shell
  still invalidates correctly on every deploy.

Full rationale for each choice is inline as comments in vite.config.ts and
apps/web/README.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 08:18:36 -04:00
BBergle e7cb06a6bc Merge pull request 'chore: set up branching, CI, and PR workflow' (#1) from chore/repo-scaffolding into main
CI / Repo hygiene (push) Successful in 2s
CI / Web (lint, typecheck, build) (push) Successful in 2s
CI / Migrations reversible (push) Successful in 2s
CI / API (lint, types, tests) (push) Successful in 45s
Reviewed-on: #1
2026-09-20 21:21:50 -04:00
BBergleandClaude Opus 5 e34c1d92ad chore(scripts): resolve Gitea token from keychain or config file
CI / Repo hygiene (pull_request) Successful in 1s
CI / API (lint, types, tests) (pull_request) Successful in 3s
CI / Web (lint, typecheck, build) (pull_request) Successful in 2s
CI / Migrations reversible (pull_request) Successful in 2s
An exported GITEA_TOKEN only exists in the shell that exported it, so
tooling invoked from elsewhere could not find it. Resolve in order:
$GITEA_TOKEN, ~/.config/gitea/token, then the macOS Keychain — so the
token can live somewhere durable and non-world-readable instead of a
plaintext dotfile.

Also factors the API call and repo coordinates into scripts/lib/gitea.sh
so pr.sh and review.sh stop duplicating them, and adds
`review.sh --list` for enumerating open PRs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 21:18:18 -04:00
BBergleandClaude Opus 5 d5e473959c chore: set up branching, CI, and PR workflow
CI / Repo hygiene (pull_request) Successful in 24s
CI / API (lint, types, tests) (pull_request) Successful in 55s
CI / Web (lint, typecheck, build) (pull_request) Successful in 25s
CI / Migrations reversible (pull_request) Successful in 3s
Prepares the repo for parallel agent work. No application code.

- CLAUDE.md: conventions, branch naming, and the six non-negotiable
  invariants from the design (immutable raw bytes, no stored odometers,
  SI integers, dual-layer user isolation, secret containment, single
  ingestion path). Also records a model-allocation policy: the
  orchestrator runs Opus 5, workers default to Sonnet, and Opus is
  reserved for review plus the areas where a mistake is silent and
  expensive (ingest, wear SQL, auth/RLS, the Bryton protocol client).
  And the Gitea Actions gotchas, so nobody rediscovers them:
  GITEA_TOKEN cannot push to the container registry, jobs.*.environment
  is ignored, and cron needs a workflow_dispatch pair.
- CONTRIBUTING.md: day-to-day flow, worktrees for parallel branches,
  review expectations.
- .gitea/workflows/ci.yml: repo hygiene (branch naming, secret scan,
  no ride data in git), plus API/web/migration jobs that guard on whether
  the code exists yet, so CI is meaningful now and grows into the real
  thing rather than being rewritten.
- .gitea/PULL_REQUEST_TEMPLATE.md: forces an honest "how this was
  verified" and an invariant checklist.
- scripts/pr.sh, scripts/review.sh: open and inspect PRs via the Gitea API.
- Directory scaffold with placeholder READMEs.

Agents open PRs; humans merge them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 21:12:22 -04:00
BBergleandClaude Opus 5 d3f5ed7e7b Add planning docs for self-hosted cycling app
Planning output only; no application code yet.

Key findings driving the design:

- The Bryton Rider 650 has on-device Wi-Fi (Main Menu -> Data Sync) and
  uploads to Bryton's cloud with no phone and no Bryton Active app. Paired
  with the reverse-engineered Bryton cloud API — which returns the original
  unmodified FIT bytes — this makes ride sync fully hands-off, and higher
  fidelity than the current Strava route (Strava's API cannot return the
  original file, only smoothed streams).
- Build fresh rather than forking Endurain or FitTrackee; borrow Endurain's
  gear/component structure and strava-gear's retroactive time-ranged wear
  computation.
- PWA rather than a native iOS app: iOS 16.4+ gives home-screen PWAs real
  push notifications, which was the only thing that used to force native.

Docs:
  docs/PLAN.md       stack, schema, ingestion, auth, notifications, roadmap,
                     CI/CD, risks, verification
  docs/RESEARCH.md   Bryton cloud protocol, FIT library comparison,
                     maintenance intervals, geo services, Gitea gotchas
  docs/DECISIONS.md  decisions taken, alternatives rejected, rationale

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 20:55:30 -04:00