diff --git a/README.md b/README.md
index 79f156d..02b0adf 100644
--- a/README.md
+++ b/README.md
@@ -21,17 +21,19 @@
- bootstrap an anonymous local Convex deployment and run the backend health query: `pnpm bootstrap:backend:local`
- keep the local Convex backend watcher running: `pnpm dev:backend:local`
- run the one-shot local Convex health check alias: `pnpm run:backend:health:local`
+- run the web app with the local Convex URL bridged into `NEXT_PUBLIC_CONVEX_URL`: `pnpm dev:web`
+- typecheck the web app with the same Convex URL bridge when available: `pnpm typecheck:web`
+- build the web app with the same Convex URL bridge when available: `pnpm build:web`
- typecheck Convex backend files: `pnpm typecheck:backend`
- re-run the local backend verification pass: `pnpm verify:backend:local`
- confirm committed Convex codegen is current: `pnpm check:backend:generated`
-- run the web app: `pnpm dev:web`
- lint the web app: `pnpm lint:web`
-- typecheck the web app: `pnpm typecheck:web`
-- build the web app: `pnpm build:web`
- run the baseline local verification pass: `pnpm verify`
Convex writes repo-root deployment configuration to `.env.local` during local setup and keeps anonymous local state under `.convex-home/` plus `.convex-tmp/`. Keep all of those uncommitted. The committed `convex/_generated/` files are expected to stay clean after `pnpm check:backend:generated`.
+The repo-root web commands bridge `CONVEX_URL` from `.env.local` into `NEXT_PUBLIC_CONVEX_URL` automatically when the file exists, so the first `apps/web -> convex/` runtime path works without a second hand-maintained env file.
+
`pnpm verify` is the full repo verification pass and now includes the local Convex bootstrap checks. If you are iterating on the web app only, use `pnpm verify:web` for the lighter web-only path.
## Start here
diff --git a/apps/web/README.md b/apps/web/README.md
index 5c47989..42196b2 100644
--- a/apps/web/README.md
+++ b/apps/web/README.md
@@ -8,12 +8,14 @@ From the repo root:
```bash
pnpm install
+pnpm dev:backend:local
pnpm dev:web
```
Useful follow-up commands:
```bash
+pnpm bootstrap:backend:local
pnpm lint:web
pnpm typecheck:web
pnpm build:web
@@ -25,4 +27,6 @@ pnpm build:web
- framework baseline: `Next.js` App Router
- language baseline: `TypeScript`
- styling baseline: `Tailwind CSS`
-- this scaffold intentionally stops before `Convex`, auth, billing, or deployment wiring
+- repo-root web commands bridge `CONVEX_URL` from `.env.local` into `NEXT_PUBLIC_CONVEX_URL` when local Convex bootstrap has run
+- the homepage now renders the placeholder public query `health:status` from `convex/`
+- auth, billing, deployment hardening, and server-side Convex patterns still belong to follow-on issues
diff --git a/apps/web/package.json b/apps/web/package.json
index 3cbba71..e37940d 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -10,6 +10,7 @@
"typecheck": "next typegen && tsc --noEmit --incremental false"
},
"dependencies": {
+ "convex": "^1.32.0",
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"
diff --git a/apps/web/src/app/convex-client-provider.tsx b/apps/web/src/app/convex-client-provider.tsx
new file mode 100644
index 0000000..950976a
--- /dev/null
+++ b/apps/web/src/app/convex-client-provider.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import { ConvexProvider, ConvexReactClient } from "convex/react";
+import type { ReactNode } from "react";
+
+let convexClient: ConvexReactClient | null = null;
+let convexClientUrl: string | null = null;
+
+function getConvexClient(convexUrl: string | undefined) {
+ if (!convexUrl || typeof window === "undefined") {
+ return null;
+ }
+
+ if (!convexClient || convexClientUrl !== convexUrl) {
+ convexClient?.close();
+ convexClient = new ConvexReactClient(convexUrl);
+ convexClientUrl = convexUrl;
+ }
+
+ return convexClient;
+}
+
+export function resetConvexClientForTests() {
+ convexClient?.close();
+ convexClient = null;
+ convexClientUrl = null;
+}
+
+export function ConvexClientProvider({ children }: { children: ReactNode }) {
+ const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL;
+ const client = getConvexClient(convexUrl);
+
+ if (!client) {
+ return <>{children}>;
+ }
+
+ return
+ Live Convex status +
+pnpm dev:backend:local and refresh once the local
+ backend is healthy again.
+ + Live Convex status +
+
+ This panel reads the placeholder health:status{" "}
+ query from the real backend bootstrap under convex/.
+
+ Backend endpoint +
+{convexUrl}
++ Query state +
++ Connecting to Convex and waiting for the first placeholder payload. +
++ Query result +
++ Convex returned an empty placeholder payload. Refresh after restarting the local + backend if this sticks around. +
++ Convex runtime path +
+
+ The app can render without a backend URL, but the live Convex read path only
+ turns on when the repo-root .env.local{" "}
+ file exists.
+
pnpm bootstrap:backend:local once, keep{" "}
+ pnpm dev:backend:local running, and start the web
+ app with pnpm dev:web from the repo root.
+ + Live Convex status +
+