Tracking the post-merge review findings from PR #41. Triage below; we'll cherry-pick and ship in batches.
P0 — broken by the waveflow-web archive
These reference URLs that will 404 once InstaZDLL/waveflow-web is archived + replaced by a README pointer. Ship them in the same PR as the archive.
P1 — security / correctness
P2 — UX / a11y / quality
P3 — tooling / tests
P4 — labeler accuracy
How we'll ship this
- P0 ships with the archive PR — fixes URLs that are about to 404 anyway, no point splitting.
- P1-P3 batched per area — security in one PR, UX in another, tooling in a third. Each ≤ 200 LOC so review stays bounded.
- P4 rides P0 (single-line labeler tweak, no point standalone).
Closes #(this issue) after the last batch lands.
Provenance
CodeRabbit + automated review on PR #41, captured 2026-06-12.
Tracking the post-merge review findings from PR #41. Triage below; we'll cherry-pick and ship in batches.
P0 — broken by the
waveflow-webarchiveThese reference URLs that will 404 once
InstaZDLL/waveflow-webis archived + replaced by a README pointer. Ship them in the same PR as the archive.web/package.json—repository.url+bugsstill point atwaveflow-web. Change both tohttps://github.com/InstaZDLL/waveflow-server(or the/websubpath forbugsif GitHub honours it — verify)..github/ISSUE_TEMPLATE/config.yml— contact_links still targetwaveflow-web/.... Update Security + Q&A + Ideas + Show-and-tell to the monorepo URLs.web/public/manifest.json—"short_name": "TanStack App","name": "Create TanStack App Sample". Replace with real WaveFlow branding.web/README.mdline 46 — references the obsoletesrc/routes/profiles.tsx(file no longer exists; the actual route is_authed.profiles.tsx).P1 — security / correctness
.github/workflows/ci-web.yml— addpersist-credentials: falseto theactions/checkoutstep (matches the rest of the repo's checkout posture)..github/workflows/label-pr.yml— add a top-levelconcurrencyblock (key on PR number) and drop the workflow-levelpermissions: write; grantpull-requests: writeonly to the jobs that need it.web/src/server-fns/session.ts— wrapauth.api.getSessionin try/catch, returnnullonUNAUTHORIZED, rethrow others. Preserves the existing early-return shape.web/src/routes/_authed.profiles.$profileId.libraries.$libraryId.artists.tsx— loader's catch returnserr.messageto the UI. Replace with a generic message; log the rawerrserver-side. Same fix on the playlists loader if shaped identically.web/src/lib/db.ts—Number.parseInt(BETTER_AUTH_DB_MAX)accepts"10foo". Tighten to/^\d+$/orNumber.isInteger + > 0.web/src/components/ThemeToggle.tsx— barelocalStorage.getItem/setItem('theme')will throw in private browsing / quota-exhausted contexts. Wrap reads + writes in try/catch.web/.gitignore— broaden the env exclusion (.env.production/.env.stagingslip through today). Add*.env*with an explicit!.env.examplenegation.P2 — UX / a11y / quality
web/src/components/PlayerBar.tsx—onPointerCancelclearsseekScrubwithout committing. MirroronPointerUp: ifseekScrub !== null, callplayer.seek(seekScrub)before clearing.web/src/lib/use-focus-trap.ts— whenitems.length === 0,container.focus()silently fails on a container withouttabindex. Add a temporarytabindex="-1", focus, then remove.web/src/routes/_authed.profiles.tsx—new Date(p.last_used_at).toLocaleDateString()is non-deterministic SSR ↔ client. Pre-format in the loader with an explicitIntl.DateTimeFormat(locale, { timeZone }).web/src/components/Footer.tsx— display string says "AGPL-3.0", licence file is "AGPL-3.0-only". Update string.web/src/styles.css—@themeblock redefines surfaces locally in rgba; consume the OKLCH tokens from@waveflow/design-tokensinstead so a preset swap re-tints both halves identically.P3 — tooling / tests
web/scripts/db-migrate.ts—MIGRATIONS_DIR = join(process.cwd(), 'db', 'migrations')breaks when invoked from the repo root after the monorepo merge. Resolve viaimport.meta.urlso the path is module-relative.web/vitest.config.ts—passWithNoTests: truehides discovery failures. Set tofalse(CI will fail loud if globs drift).web/src/routes/sign-up.test.tsx— add coverage for empty display-name rejection + max-password-length boundary + name/email trim on success.web/src/routes/_authed.profiles.$profileId.playlists.test.tsx—React.PropsWithChildrenreferenced without animport * as React/import { PropsWithChildren }. Fix import.web/src/routes/sign-in.test.ts— rename to-sign-in.test.tsxso the TanStack Router plugin's-prefix convention excludes it from the route tree (analogous fix already applied to other route-adjacent test files)..github/pull_request_template.md— MD041: first heading should be H1, not H2. Replace## Summarywith# Summary.P4 — labeler accuracy
.github/labeler.yml—web/src/routes/sign-in/**/web/src/routes/sign-up/**only match dir paths, but the actual routes aresign-in.tsx/sign-up.tsx(files at root ofroutes/). Switch toweb/src/routes/sign-in{,/**}/web/src/routes/sign-up{,/**}.How we'll ship this
Closes #(this issue) after the last batch lands.
Provenance
CodeRabbit + automated review on PR #41, captured 2026-06-12.