Skip to main content

Client

packages/client is the end-user app at greengoods.app: one codebase, two presentations. Visitors get an editorial public website; gardeners get an installed PWA that captures work offline in the field. Most business logic comes from shared; this package owns route composition and presentation.

The two shells​

  • Public browser routes render through PublicShell with the site header, editorial navigation, and public-safe data access.
  • Installed and authenticated PWA routes render through AppShell with the bottom navigation bar, offline capture, and the app experience.

Never mix the two. If a route or shell change blurs the paths, check router.tsx, the shell component, and the matching Storybook story in the same pass. To tour the PWA without a wallet, use the mock-auth URL from Getting Started.

Follow one work submission to see the app’s capture, queue and review path.

Inside src​

A request enters through main.tsx, which picks the public or PWA bootstrap by presentation. router.tsx composes the route table in config/routes.tsx into the matching shell from routes/; each view then renders client components over shared hooks, and the service worker in sw/ keeps the installed app working without signal.

DirectoryWhat lives there
src/main.tsx, src/PublicApp.tsx, src/PwaApp.tsx, src/bootstrapPublic.tsx, src/bootstrapPwa.tsxEntry points and bootstraps for the public site and the installed app
src/routes/The shells themselves: PublicShell, AppShell, the root route, the session gate, and the PWA runtime
src/router.tsx and src/config/routes.tsxHow routes are composed for both presentations
src/views/Screens by area: Home, Garden, Profile, Login, and the public pages
src/components/Client-owned building blocks by role: Actions, Cards, Communication, Display, Errors, Features, Inputs, Layout, Navigation, Public, Pwa, and Sheets
src/sw/The service worker: the offline shell, media caching, the share target, and background work
src/config/The PWA manifest, routing rules, IPFS settings, and app bootstrap
src/styles/Client stylesheets layered on the shared tokens
src/content/Curated public content and social previews
src/webmcp.tsWebMCP tools for public-safe browser routes
src/__tests__/Vitest suites for views, shells, and the service worker

Run and test​

bun run --cwd packages/client test
bun run --cwd packages/client build

Run the build whenever route wiring, render output, or PWA packaging moves; tests alone don't prove those.

How it connects​

The client reads garden and membership state through the indexer's read models and reads work through shared's EAS data layer, which only queries. Writing takes a different path: captured work goes into the shared job queue, and its executors encode and send the attestations. The Anatomy of a Work Submission traces that whole path.

Conventions that will bite you​

  • Work submission must preserve the offline-first queue flow. Bypassing the queue for passkey users breaks recovery.
  • Blob URLs go through shared's mediaResourceManager; a stray URL.createObjectURL leaks memory on capture-heavy flows.
  • Authentication branches through shared auth APIs, and wallet chain state is never the source of truth for app defaults.
  • No local hooks or providers for logic that belongs in shared.
  • New user-facing strings ship in en, es, and pt together.

Go deeper​

  • packages/client/AGENTS.md is the full package contract, including the design-surface rules.
  • Personas and Surfaces defines the five personas and the surfaces that may name each one; the route table itself lives in src/config/routes.tsx and src/config/pwaRouting.ts.