Install
$ agentstack add skill-wtsi-hgi-agentskills-nextjs-fastapi-conventions ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Next.js + FastAPI Conventions
Single source of truth for architecture, code quality, and testing in Next.js + FastAPI full-stack projects.
Project Stack
- Frontend: Next.js 16 (App Router) + React 19 + shadcn/ui + Tailwind CSS
v4 (TypeScript, in frontend/)
- Backend: FastAPI + Uvicorn + Pydantic (Python 3.11+, in
backend/)
Architecture
BFF Pattern
The browser NEVER calls FastAPI directly. All backend communication flows through the Next.js server layer:
- Server Actions (
app/actions.ts) handle mutations. Client components call
these; they run on the Next.js server and proxy to FastAPI.
- API Routes (
app/api/*/route.ts) exist ONLY for external consumers
(health checks, webhooks), NOT for frontend use.
Type Safety (Zod Contracts)
Every FastAPI response is validated on the frontend with Zod:
lib/contracts.ts: Zod schemas mirroring Pydantic models.lib/backend-client.ts:backendJson()fetches + validates against Zod.- Contract breaks fail fast with
BackendRequestError.
New endpoint checklist:
- Pydantic response model in
backend/api/schemas.py. - Matching Zod schema in
frontend/lib/contracts.ts. - Contract test in
frontend/tests/contracts.test.ts. backendJson()with schema in Server Action.
Components
- Server Components (default): fetch data, pass as props.
- Client Components (
'use client'): interactivity, browser APIs, hooks.
React 19
useActionState(NOT deprecateduseFormState).- Explicit state types (e.g.
GreetingStateinlib/greeting-state.ts).
Backend Structure
- Lifespan via
@asynccontextmanager(NOT@app.on_event). pydantic-settingsfor typed config from env vars.- Versioned routers under
api/v1/. - Every endpoint declares
response_modeland returns a Pydantic model.
Code Quality
Python
- Async endpoints,
httpx.AsyncClient(notrequests). - Type hints everywhere.
Annotatedfor FastAPI params. - Docstrings on modules, classes, public functions.
HTTPExceptionfor API errors. No swallowed exceptions.- Import grouping: stdlib | third-party | local.
TypeScript
strict: true. Neverany(preferunknown+ narrowing).- Zod for all external data; derive types with
z.infer<>. - Server Actions:
'use server', return typed state objects. - shadcn/ui components from
components/ui/. - Import grouping: React/Next.js | third-party | local
@/(components > lib >
types).
- Tailwind v4 semantic tokens (
text-foreground,bg-muted), not raw colours.
Styling
- Tailwind utility classes in JSX.
cn()fromlib/utils.tsfor conditional
classes.
- Semantic tokens from
@theme, not raw colour values. - Mobile-first responsive (
sm:,md:,lg:). - CVA for component variants. Sonner for toasts. next-themes for theme switching.
Tailwind v4 Runtime Theming
- Treat Tailwind v4 theme variables as part of the runtime contract, not as
ordinary CSS constants. Read the project's actual globals.css/theme setup before changing visual states.
- If dark mode is driven by
next-themeswithattribute="class", ensure
Tailwind's dark: variant is also class-driven (for example with @custom-variant dark (&:where(.dark, .dark *));). Do not assume .dark affects Tailwind utilities when the compiled CSS still uses prefers-color-scheme.
- Use
@theme inlineonly when utilities should inline a referenced value.
Do not use it for semantic colours that must change at runtime between light and dark themes; compiled utilities may freeze light-mode literals such as #ffffff or #e2e8f0.
- For semantic colours that must respond to theme changes, prefer utilities
that compile to runtime CSS variables, explicit arbitrary values such as bg-[var(--color-card)], or small custom CSS rules that use var(...).
- When debugging Tailwind v4 styling, inspect the generated CSS or browser
computed styles before changing specificity. Cascade layers, !important, and @theme inline can make source CSS misleading.
File Organisation
- Pages in
app/(App Router). Reusable components incomponents/. - shadcn/ui in
components/ui/(don't edit directly). - Shared utils/types in
lib/. Import via@/.
Testing
- Follow testing-principles for test intent; this section covers stack
mechanics.
Backend (pytest)
pytest+pytest-asyncio(auto mode).httpx.AsyncClient+ASGITransportagainst FastAPIapp.- Assert status codes AND JSON payloads.
@pytest.mark.anyiofor async tests.
Frontend (Vitest)
environment: 'node'. Tests infrontend/tests/*.test.ts.- Contract tests:
.parse()and.safeParse()against schemas. describe/itblocks,expect()matchers.
Visual and Perceptual UI Tests
- For styling bugs that users perceive visually (contrast, borders, selection,
focus rings, dark mode, animations), prefer real-browser tests with Playwright over jsdom-only tests.
- A test that reads source CSS text, checks for a class name, or asserts only a
computed property is not sufficient for a visual regression. It can be useful as a guard, but it does not prove the rendered UI is visible.
- Assert the user-visible result: compare screenshots or sample rendered pixels
from the affected element and its surroundings. For borders and rings, check frame pixels against the element fill and neighbouring cells/surfaces, not just borderTopColor against another element's border.
- Test every relevant theme/mode through the same mechanism the app uses in
production. If dark mode is class-driven, set the class and verify compiled CSS responds to it; if it is media-driven, use page.emulateMedia().
- Avoid injecting fake probe styles into tests for the feature under test. Load
the real app stylesheet and fail against the actual cascade.
- If a visual assertion is hard to express, include a focused screenshot
assertion or a small canvas/pixel sampler plus clear thresholds derived from visible contrast, not from the implementation details of a chosen token.
Commands
Backend
cd backend && python -m pytest tests/ -v # all tests
cd backend && python -m pytest tests/ -v -k # specific test
cd backend && ruff check --fix . && ruff format . # lint+fix
cd backend && ruff check . && ruff format --check . # lint check only
Frontend
cd frontend && pnpm test # all tests
cd frontend && pnpm test:watch # watch mode
cd frontend && pnpm lint # lint
cd frontend && pnpm format # format
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wtsi-hgi
- Source: wtsi-hgi/agentskills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.