Imported from MichaelOlave/ClubCRM (
apps/web/AGENTS.md). Install upstream withnpx skills add MichaelOlave/ClubCRM --skill web. Copyright stays with the author.
This is NOT the Next.js you know
This app uses Next.js 16.2.1 and React 19.2.4. APIs, conventions, and defaults may differ from older training data.
Before making framework-level changes, read the relevant guide in node_modules/next/dist/docs/ and heed deprecation notices.
Web App Agent Guide
This file applies to work inside apps/web.
Read This First
- Review the monorepo before editing code, even for web-only tasks.
- This is a dual-language project: TypeScript in
apps/weband Python inapps/api. - Do not assume a frontend change is isolated until you have checked the root scripts, shared docs, and API contract.
- Read the relevant repo-level docs in
README.md,docs/contributing.md, anddocs/architecture.mdbefore making workflow or architecture changes.
Environment
- Use the repository devcontainer workflow as the default development environment.
- The repository is mounted at
/workspaceinside the devcontainer. - Work from
/workspace/apps/webwhen running app-local commands. - Dependencies are installed during the devcontainer
postCreateCommand(python3 ./scripts/bootstrap.py), which runspnpm bootstrap. - Prefer the containerized workflow instead of setting up a separate host-machine Node environment.
The default local stack includes:
webon port3000apion port8000postgreson port5432mongodbon port27017redison port6379kafkaon port9092
The devcontainer Compose stack already starts web and api, so root scripts such as pnpm dev:web, pnpm dev:api, and pnpm dev are for manual restart, debugging, or validation rather than first-run setup.
Workspace Context
- This package is the ClubCRM Next.js frontend.
- The backend lives in
apps/apiand is a FastAPI service. - The repo is a
pnpmworkspace with apps underapps/*. - Root scripts are the source of truth for shared checks and common workflows across both stacks.
- The web package currently uses the App Router under
src/appwith(app)and(public)route groups.
Important files:
package.jsonpyproject.tomlapps/web/package.jsonapps/web/src/app/layout.tsxapps/web/src/app/page.tsxapps/web/src/app/globals.cssapps/web/src/app/system/health/page.tsxapps/web/src/app/system/audit/page.tsxapps/api/src/main.pyapps/api/src/presentation/http/router.pyapps/api/src/modules/system/presentation/http/routes.pyapps/web/README.mdapps/api/README.mddocs/contributing.mddocs/architecture.md
Commands
From the repository root:
pnpm bootstrapinstalls Node dependencies and provisions the API virtualenv/toolingpnpm dev:webrestarts or runs the web app on0.0.0.0pnpm dev:apirestarts or runs the FastAPI app from the Python virtualenvpnpm devrestarts or runs both app entrypoints togetherpnpm build:webruns the production web buildpnpm lint:webruns the web ESLint checkspnpm lintruns the repo lint pipeline across both stackspnpm lint:apiruns Ruff against the backendpnpm check:apibytecode-compilesapps/api/srcfor a quick sanity checkpnpm verifyruns the repo verification pipeline
From apps/web:
pnpm devpnpm buildpnpm startpnpm lint
Prefer root-level scripts when the task affects shared workflow, CI parity, or multiple apps. Treat the root scripts as the CI-facing contract unless there is a strong reason to use something narrower.
Implementation Notes
- Keep changes aligned with existing Next.js App Router patterns in
src/app. - Check whether the change depends on backend routes, payloads, or environment variables before editing.
- Preserve TypeScript, ESLint, and Prettier compatibility.
- Respect the backend Python toolchain: Ruff, the in-repo
apps/api/.venv, and the rootpnpmplus Python/Node helper scripts are part of the standard workflow. - Preserve Python-side expectations when the web app reads API responses.
- Do not "fix" backend, infra, port, or container assumptions from the web side without checking the repo workflow first.
- Avoid editing generated or environment-specific artifacts such as
apps/api/.venvunless the task explicitly requires it. - Favor small, focused changes over broad refactors.
- Update repo docs, not just web docs, when behavior, setup, ports, API assumptions, or team workflow changes.
Current app behavior to keep in mind:
src/app/page.tsxcurrently redirects authorized users to/dashboard, authenticated-but-unprovisioned users to/not-provisioned, and everyone else to/login.- Admin routes live under
src/app/(app), public entry points live undersrc/app/(public), and the auth proxy handlers live at/api/auth/loginand/auth/callback. - The current admin MVP includes dashboard, profile, clubs, members, club-level join-request review,
/system/audit, and/system/health; public routes currently cover/login,/not-provisioned,/docs,/testing,/join/[clubId], and the networking-demo/demo/failoverroute. - The admin shell is role-aware: org admins see the full workspace, while club managers get a reduced shell for assigned clubs.
- Most feature data currently flows through server-side modules in
src/features/*/server; many of those modules now call live backend endpoints while a smaller amount of route composition still stays web-side. src/app/system/health/page.tsxpreserves the admin diagnostics flow,src/app/system/audit/page.tsxpreserves the admin audit flow, andsrc/app/demo/failover/page.tsxprovides the public failover-monitor route for the networking demo.- The diagnostics flow probes the API using
API_BASE_URL, thenWEB_API_PUBLIC_BASE_URL, thenhttp://api:8000, thenhttp://localhost:8000. - The expected backend response comes from
apps/api/src/modules/system/presentation/http/routes.pyand returns top-levelstatus: "ok"plus nested health-check details such aschecks.redis. - The diagnostics page exports
dynamic = "force-dynamic"and usesfetch(..., { cache: "no-store" }).
Do not remove or change this behavior casually unless the task explicitly calls for it.
Frontend Structure
The web app uses a feature-first layout under src/:
src/
app/ # Routes, layouts, and metadata — composition only
(app)/ # Admin shell route group
dashboard/
profile/
clubs/
[clubId]/
join-requests/
members/
[memberId]/
system/ # Protected diagnostics and audit pages using their own layout
audit/
health/
live-routing/
(public)/ # Public entry points
docs/
login/
not-provisioned/
testing/
join/[clubId]/
api/auth/login/ # Same-origin auth handoff proxy
auth/callback/ # Same-origin auth callback proxy
demo/failover/ # Public networking-demo failover monitor and recycle action
features/ # Default home for business-facing feature code
audit/
auth/
clubs/
dashboard/
docs/
forms/join-request/
health/
landing/
members/
memberships/
profile/
testing/
<feature>/
components/ # Feature-specific presentational components
server/ # Server-only loaders/actions for App Router server components
types/ # Feature-owned input/output/view types
index.ts # Public surface — routes import only this, not deep internals
components/
ui/ # Generic, business-agnostic UI primitives
layout/ # App shell, sidebar, header, page container wrappers
hooks/ # Cross-feature React hooks
lib/
api/ # Shared fetch base and request helpers
env/ # Environment variable parsing and config access
utils/ # Pure utility helpers with no feature ownership
types/ # Truly app-wide types only; prefer feature-local types first
proxy.ts # Future auth redirects and route guards if the app needs them
Placement rules
- Code that mentions one business concept belongs in that feature folder.
- Two features sharing the same visual primitive but not the same business meaning →
components/ui. - Two features sharing the same business workflow → extract a shared feature submodule only after the second real use.
- Something used by only one route → keep it inside that route segment or feature, not in global shared folders.
- Do not create catch-all folders (
helpers,common,shared) without a narrow subcategory.
Import direction (enforced by ESLint)
app → features → components → lib
lib/andcomponents/must not import fromfeatures/orapp/.- Run
pnpm lint:webto check. Violations are errors, not warnings.
proxy.ts (auth/redirects)
In Next.js 16+, the route guard file is src/proxy.ts (not middleware.ts — that convention is deprecated). Do not create this file with an empty stub; it requires a real function export. Add it only when auth redirect logic exists.
Hooks placement
- Cross-feature hooks →
src/hooks/ - Feature-local hooks →
features/<feature>/hooks/
Test placement
Tests are co-located, not in a top-level __tests__ folder:
features/<feature>/**/__tests__/*.test.tsxapp/**/__tests__/*.test.tsx
Adding a new feature
- Create
src/features/<feature>/with the sub-folders you need. - Add a route in
src/app/.../page.tsxthat imports only from@/features/<feature>. - Touch
src/components/uiorsrc/components/layoutonly for genuinely generic UI. - Run
pnpm lint:webandpnpm build:webbefore finishing.
Note on features/health
The health feature is both a useful reference and a real diagnostics slice. It demonstrates the folder layout while preserving the current API connectivity check on /system/health. Do not model domain features directly on it, but it is a real runtime path rather than a dead scaffold.
Quality Bar
Before finishing substantial web changes, run the most relevant checks:
pnpm lint:webfor frontend lintingpnpm build:webwhen routing, rendering, config, or build behavior changespnpm verifywhen the change affects shared tooling or cross-app behavior
If you cannot run a recommended check, say so clearly in your handoff.