diff --git a/README.md b/README.md index b2f6716..0b6a57e 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ Convex writes repo-root deployment configuration to `.env.local` during local se The local Convex bootstrap now mirrors `CONVEX_URL` into `apps/web/.env.local` as `NEXT_PUBLIC_CONVEX_URL` so the web app can read the placeholder `health:status` query through the Convex client runtime. If you want the homepage to show live backend data instead of the local configuration fallback, run `pnpm bootstrap:backend:local` first and keep `pnpm dev:backend:local` running while you use `pnpm dev:web`. +The first server-side `Next.js -> Convex` baseline now lives at `/server-status`. It uses `fetchQuery` from `convex/nextjs` on a dedicated route rendered dynamically, while the homepage keeps the reactive client-side `useQuery` path. + `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 3e1b552..3a9d475 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -28,4 +28,5 @@ pnpm build:web - language baseline: `TypeScript` - styling baseline: `Tailwind CSS` - the app mounts a Convex provider baseline and the homepage performs a live `health:status` query when `apps/web/.env.local` contains `NEXT_PUBLIC_CONVEX_URL`; the local Convex bootstrap now mirrors that value automatically from the repo-root Convex bootstrap output +- the server-side Convex baseline lives at `/server-status` and uses `fetchQuery` from a server component without replacing the reactive client pattern on `/` - auth, billing, and deployment wiring still belong to follow-on issues diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index cde069e..30d92a1 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,3 +1,4 @@ +import Link from "next/link"; import { BackendStatusCard } from "./backend-status-card"; export default function Home() { @@ -34,6 +35,12 @@ export default function Home() { > Next.js docs + + Server-side baseline +
Next issues
-
#64, #56, #59
+
#9, #56, #59
@@ -85,13 +92,12 @@ export default function Home() { Now in place

- A clean frontend baseline + Client and server baselines

- The repo now has a real web surface under{" "} - apps/web, ready for - local development, Convex integration, linting, and production - builds. + The repo now has one reactive client read and one explicit server-side + read pattern under apps/web, + ready to support later profile and auth work without mixing patterns.

@@ -114,12 +120,12 @@ export default function Home() { Immediate follow-on

- Add the first server-side data baseline + Define the profile data foundation

- The next meaningful milestone is documenting the first server-side - Convex read path so App Router usage stays clean as real features - land. + The next meaningful milestone is establishing the first durable + profile schema so public pages and claim flows can build on typed + domain records instead of the bootstrap health placeholder.

diff --git a/apps/web/src/app/server-status/page.tsx b/apps/web/src/app/server-status/page.tsx new file mode 100644 index 0000000..7145c38 --- /dev/null +++ b/apps/web/src/app/server-status/page.tsx @@ -0,0 +1,148 @@ +import Link from "next/link"; +import { fetchBackendStatus } from "@/convex/server"; + +export const dynamic = "force-dynamic"; + +export default async function ServerStatusPage() { + const status = await fetchBackendStatus(); + + return ( +
+
+
+
+
+ VRDex + Server-side Convex baseline +
+ +
+

+ First server-side App Router read path. +

+

+ This route demonstrates the baseline Next.js{" "} + server-component pattern for Convex in VRDex: use fetchQuery{" "} + for a server-only read, and keep useQuery for + reactive client surfaces. +

+
+ +
+ + Back to homepage + + + Convex server docs + +
+
+
+ +
+
+

+ Live result +

+ + {status.kind === "live" ? ( + <> +

+ Server read reached Convex +

+

+ This page rendered on the server using fetchQuery(api.health.status){" "} + before the response reached the browser. +

+ +
+
+
+ Status +
+
{status.data.status}
+
+
+
+ Scope +
+
{status.data.scope}
+
+
+
+ Backend +
+
{status.data.backend}
+
+
+
+ Note +
+
{status.data.note}
+
+
+ + ) : status.kind === "missing-url" ? ( + <> +

+ Convex URL not configured +

+

+ Run pnpm bootstrap:backend:local so the local + bootstrap writes NEXT_PUBLIC_CONVEX_URL into + apps/web/.env.local before using this + server-side route. +

+ + ) : ( + <> +

+ Convex server read failed +

+

+ Start pnpm dev:backend:local, confirm + NEXT_PUBLIC_CONVEX_URL is available to the web app, + and reload this page. +

+ + )} +
+ + +
+
+
+ ); +} diff --git a/apps/web/src/convex/server.ts b/apps/web/src/convex/server.ts new file mode 100644 index 0000000..7dc740e --- /dev/null +++ b/apps/web/src/convex/server.ts @@ -0,0 +1,25 @@ +import { fetchQuery } from "convex/nextjs"; +import { api } from "@convex-generated-api"; + +export async function fetchBackendStatus() { + if (!process.env.NEXT_PUBLIC_CONVEX_URL) { + return { kind: "missing-url" as const }; + } + + try { + const data = await fetchQuery(api.health.status, {}); + + return { + kind: "live" as const, + data, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + + console.error(`Server-side Convex fetchQuery failed: ${message}`); + + return { + kind: "error" as const, + }; + } +} diff --git a/docs/backend/convex-bootstrap.md b/docs/backend/convex-bootstrap.md index b79f096..4e67fb8 100644 --- a/docs/backend/convex-bootstrap.md +++ b/docs/backend/convex-bootstrap.md @@ -19,6 +19,7 @@ It is intentionally narrow: enough structure to run Convex locally, generate typ - `convex.json` pins Convex to Node `22` so local backend runtime expectations stay aligned with the repo's current Node baseline - `convex/tsconfig.json` provides the TypeScript settings Convex uses to typecheck backend source files - the web app consumes `health:status` as the first real `Next.js -> Convex` runtime path, mounting a client-side provider baseline and surfacing the result in the homepage without inventing early product schema +- the web app also exposes `/server-status`, where a server component uses `fetchQuery` against the same `health:status` function as the initial server-side baseline ## Local workflow @@ -36,6 +37,7 @@ Notes: - Convex writes deployment configuration to the repo-root `.env.local` file. - The local Convex wrapper mirrors the repo-root `CONVEX_URL` into `apps/web/.env.local` as `NEXT_PUBLIC_CONVEX_URL` so the web app can follow the normal client-side Convex + Next.js convention without leaking a non-public variable through server props. +- That same `NEXT_PUBLIC_CONVEX_URL` value is also what `fetchQuery` uses for the current server-side baseline route, so local client and server reads share one deployment setting. - Anonymous local backend state for this repo is kept under `.convex-home/` and `.convex-tmp/` so the bootstrap does not collide with other Convex projects on the same machine. - The current bootstrap is local-development focused. Production deploy keys, preview deployments, and frontend environment wiring belong to follow-on issues. - Committed files in `convex/_generated/` are treated as checked-in build artifacts and should remain diff-free after `pnpm check:backend:generated`. @@ -51,5 +53,15 @@ Keep the initial backend slice simple: ## Follow-on issues - `#55` wires the web app to the first Convex client/runtime path using `health:status` -- `#64` should add the first server-side `Next.js -> Convex` data path once the client runtime baseline is stable +- `#64` adds the first server-side `Next.js -> Convex` data path with `fetchQuery` on `/server-status` - schema, auth, billing, and production deployment posture should land in their own issues instead of bloating the bootstrap + +## App Router baseline + +The current rule is intentionally narrow: + +- use `useQuery` inside client components when the UI should stay reactive after first render +- use `fetchQuery` inside server components when the page only needs a server-side read +- defer `preloadQuery` until a real feature needs server-rendered first paint plus a hydrated reactive handoff + +This keeps the first App Router pattern copyable without introducing multiple competing baselines before auth and domain work arrive. diff --git a/docs/planning/engineering-strategy.md b/docs/planning/engineering-strategy.md index 6637471..6f2d16e 100644 --- a/docs/planning/engineering-strategy.md +++ b/docs/planning/engineering-strategy.md @@ -51,6 +51,7 @@ Current recommendation: - keep the first backend slice schema-light with an explicit health query instead of guessing at product tables too early - use local-development-friendly Convex setup first, then layer in frontend wiring, auth, billing, and production deployment posture through follow-on issues - once the local backend bootstrap is deterministic, include it in the baseline PR verification pass alongside the web checks +- use one explicit server-side App Router baseline once client wiring is stable: `fetchQuery` for server-only reads, with `preloadQuery` deferred until a feature truly needs hydrated reactivity after server render ## Monetization direction