feat(web): scaffold apps/web — SolidJS live sheet on Convex#31
Merged
Conversation
M2 kickoff, per #8. SolidJS + Vite+ + Tailwind app wired to the local Convex deployment, with the marketing/app layout split so the landing page and future VTT (/table/:id) can grow their own chrome. - apps/web: routes / (placeholder landing), /characters (roster + "Create Vesper" dev seed), /characters/:id (full derived sheet: identity, attributes + bonuses, combat, vitals, saves, skills, spells, with a Roll Vitals button pinning concrete rolls live) - lib/convex.ts: hand-rolled Solid bindings over ConvexClient — createQuery maps a live-query subscription onto a signal (reactive args resubscribe; onError surfaces subscription failures instead of hanging on "Loading"), createMutation/createAction helpers; 6 unit tests against a fake client - backend: characters.list roster query (newest first, bounded at 50) + test; package exports for the generated api (and dataModel types) so the app imports typed function refs - CI now checks/tests backend and web alongside rules (backend was never wired in); README updated to the three-package layout - convex/_generated committed as `convex dev` regenerates it, ending the fmt flip-flop noise 105/105 tests, vp check clean, prod build clean. Verified in a real browser against the anonymous local deployment: seed -> live sheet -> roll vitals streaming in, plus the invalid-id error path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Rv4wV7c73SkfkHbFcGygu
There was a problem hiding this comment.
4 issues found across 27 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- root vite.config fmt.ignorePatterns excludes convex/_generated: the files are committed as `convex dev` regenerates them (prettier style), so oxfmt checking them just fights the code generator. This was the CI failure — the root `vp check` I validated with resolves ignores differently than the per-package `vp run backend#check` CI runs. (Formatting is root-configured in Vite+ monorepos; a package- level fmt block doesn't apply.) - /characters: wire onError into the roster query so a failed subscription surfaces instead of hanging on "Loading…" (same fix the sheet page already had), and catch create-seed rejections into a visible error instead of an unhandled rejection - /characters/:id: catch rollVitals rejections into a visible error - README: `rules#check` comment no longer implies it checks the whole workspace Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Rv4wV7c73SkfkHbFcGygu
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Cubic follow-up: a stale query error could mask recovered data because
nothing cleared the page-level error signal when the subscription
pushed a good value again (and the sheet page had the same latent bug).
Instead of patching each page, the bindings now own both signals:
createQuery returns { data, error }, clears the error on every
successful update and on resubscription, and the pages drop their
hand-rolled error wiring. New test pins error -> recovery clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Rv4wV7c73SkfkHbFcGygu
There was a problem hiding this comment.
0 issues found across 4 files (changes from recent commits).
Requires human review: This PR introduces substantial new code and infrastructure with a large blast radius, so it should be reviewed by a human.
Re-trigger cubic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #8. M2 kickoff: the SolidJS web app, wired end to end to the Convex backend, with
/characters/:idrendering the full derived sheet live.What's here
apps/web(SolidJS + Vite+ + Tailwind v4, in the pnpm workspace withvp run web#dev/#check/#test/#build):/(placeholder landing) and app shell for/characters..., split from day one so the landing page and future VTT (/table/:id) each grow their own chrome.src/lib/convex.ts, ~50 lines + tests):createQuerymaps aConvexClient.onUpdatesubscription onto a Solid signal — reactive args (e.g. route params) resubscribe and reset to loading;onErroris threaded through because an errored subscription otherwise never resolves and the page would hang on "Loading…" silently (caught during browser verification). PluscreateMutation/createActionhelpers. 6 unit tests against a fake client (subscribe/update/null/error/resubscribe/dispose)./characters— live roster + "Create Vesper" dev seed button (same fixture the rules/backend tests pin) hittingcharacters.create./characters/:id— the proof of life: identity, attributes + derived attribute bonuses, combat profile, vitals (ranges until rolled), saves, skills, spells, and a Roll vitals button hittingcharacters.rollVitalswith results streaming back over the subscription.VITE_CONVEX_URLcommitted inapps/web/.envpointing at the anonymous local deployment (not a secret; dev works out of the box).Backend:
characters.listroster query (identity fields only, newest first, bounded with.take(50)) + test.package.jsonexports for./api(generated function refs) and./dataModel(types) so the app gets typed end to end.Housekeeping:
convex/_generatedcommitted asconvex devregenerates it (prettier-style), which ends the recurring dirty-tree noise onmain.Verification
Verified in a real browser against the local anonymous deployment: landing →
/characters→ seed Vesper → sheet renders every section with the expected fixture numbers (Native Tongue 98%, Wilderness Survival 44%, P.P.E. 64–214, spell strength 12) → Roll vitals pins concrete values live (no reload) → invalid-id route shows the error instead of hanging. Zero console errors on the happy path.105/105 tests across the workspace;
vp checkand the production build are clean.Out of scope (per the issue): builder wizard (#9), sheet visual design (#10), landing content, VTT.
Summary by cubic
Scaffolded a SolidJS web app on
convexwith a live character sheet and simple roster, delivering the end-to-end flow in #8. Also adds Solid–Convex bindings, a backend roster query, CI for web/backend, and moves query error state into the bindings for reliable recovery.New Features
apps/web(SolidJS + Vite + Tailwind): routes for/(placeholder),/characters(roster + “Create Vesper” seed), and/characters/:id(derived sheet with live updates and “Roll vitals”)./table/:idcan evolve independently.convex(createQuery,createMutation,createAction): reactive args resubscribe; errors surface instead of hanging; covered by unit tests.characters.listroster query (identity only, newest first, capped at 50); package exports./apiand./dataModelfor typed imports in@riftforge/backend.VITE_CONVEX_URLfor the anonymous local backend sovp run web#devworks out of the box; committedconvex/_generatedto stop churn.Bug Fixes
createQuerynow returns{ data, error }and clears stale errors on resubscription and on successful updates; pages drop manual onError wiring.rollVitalsrejections) instead of silent hangs.packages/backend/convex/_generated/**from formatter to stop generator vs. fmt conflicts.rules#checkonly checks the rules package.Written for commit 6b7efec. Summary will update on new commits.