Think Throo is in BetaSome features are still evolving. Expect improvements and the occasional rough edge.

Canopy Codebase Architecture

1 chapter

Canopy Codebase Architecture

Stop explaining your architecture to your AI agent on every task. This collection, inspired by LobeChat's OSS codebase, gives it the full picture — project structure, API layer, state management, components structure, error handling, and performance patterns — once, permanently.

TypeScriptNext.jscli

Install

$npx skills add thinkthroo/skills --skill canopy-codebase-architecture

SKILL.md

/--- name: canopy-codebase-architecture description: > Full-stack Next.js codebase architecture guide. Use when scaffolding a new feature, placing files, wiring up an API endpoint, adding a Zustand store, protecting a route, handling errors, or optimising performance. Covers the complete vertical slice from database to UI using a Todo app as the canonical example. Triggers on any task involving project structure, API design, state management, security, components, error handling, or performance in a Next.js App Router codebase. license: MIT metadata: author: thinkthroo version: "1.0.0" series: amazon-rainforest /---

Canopy — Codebase Architecture

A comprehensive architecture guide for production-grade Next.js applications, demonstrated through a Todo app. Contains rules across 7 categories, prioritised by impact.

All code examples use TodoItem, createTodo, store/todo/, etc. so the patterns transfer cleanly to any domain — swap the entity name for your own.


When to Apply

Reference these guidelines when:

  • Scaffolding a new feature end-to-end (DB → API → store → UI)
  • Deciding where a new file belongs
  • Writing or reviewing tRPC routers and client services
  • Creating or refactoring Zustand stores
  • Protecting routes or procedures
  • Adding error handling and observability
  • Optimising re-renders or bundle size

Rule Categories by Priority

| Priority | Category | Impact | Prefix | Rule file | |----------|----------|--------|--------|-----------| | 1 | Project Structure | CRITICAL | struct- | rules/project-structure.md | | 2 | API Layer | CRITICAL | api- | rules/api-layer.md | | 3 | Security | HIGH | sec- | rules/security.md | | 4 | State Management | MEDIUM-HIGH | state- | rules/state-management.md | | 5 | Component Structure | MEDIUM | comp- | rules/component-structure.md | | 6 | Error Handling | MEDIUM | err- | rules/error-handling.md | | 7 | Performance | LOW-MEDIUM | perf- | rules/performance.md |


Quick Reference

1. Project Structure (CRITICAL)

  • struct-directory-layout — One folder per concern at the top level; never mix concerns
  • struct-data-flow — Unidirectional: UI → Store → Service → tRPC → Server Service → DB
  • struct-feature-colocation — Components used by one page live next to that page
  • struct-naming-conventions — PascalCase components, camelCase hooks/utils, UPPER_SNAKE_CASE constants
  • struct-env-imports — Always import env vars through a validated utils/env.ts, never process.env directly

2. API Layer (CRITICAL)

  • api-single-client — One pre-configured tRPC client instance; never create duplicates
  • api-router-per-entity — One tRPC router file per entity, all registered in a root index
  • api-service-abstraction — Client service wraps tRPC client calls; exported as a singleton
  • api-typed-input — All procedure inputs validated with Zod schemas
  • api-authed-procedure — All user-data endpoints use authedProcedure, never publicProcedure

3. Security (HIGH)

  • sec-auth-middleware — Route protection lives in middleware.ts, not in page components
  • sec-authed-procedure — Read userId only from ctx, never from request body or params
  • sec-no-token-state — Tokens are never stored in localStorage or Zustand
  • sec-input-validation — Validate at the API boundary; never trust client-supplied data
  • sec-database-rls — Every user-owned table has RLS enabled with all CRUD policies
  • sec-service-role-server-only — Admin/service-role DB client used only in server-side code

4. State Management (MEDIUM-HIGH)

  • state-store-per-entity — One Zustand store per entity with a standard five-file structure
  • state-initial-shape — Explicit TypeScript interface + zero-value default object
  • state-selectors — All selectors live in selectors.ts; never write inline selectors in components
  • state-actions-call-services — Actions are the only place that call client services
  • state-devtools-naming — Pass false, 'actionName' to every set() call for DevTools tracing

5. Component Structure (MEDIUM)

  • comp-server-first — Default to Server Components; add "use client" only when the component needs interactivity
  • comp-ui-library — Use the shared UI package; never install shadcn components individually per app
  • comp-feature-colocation — One page → co-locate; two or more pages → promote to components/
  • comp-modal-pattern — All modals accept open and onOpenChange props; use Dialog from the UI library
  • comp-typed-props — Every component has explicit prop types; no implicit any

6. Error Handling (MEDIUM)

  • err-catch-and-capture — Every catch block calls Sentry.captureException with tags.hook and tags.action
  • err-user-toast — Show toast.error() for every user-visible failure; never alert() or log-only
  • err-boundaries — Add route-level error.tsx next to every page that fetches data
  • err-structured-loggingSentry.logger on the client; pino on the server
  • err-no-swallow — Never swallow errors silently; every catch must capture or re-throw

7. Performance (LOW-MEDIUM)

  • perf-dynamic-import — Lazy-load heavy components with next/dynamic; always provide a loading fallback
  • perf-memo — Wrap expensive components with React.memo when the parent re-renders frequently
  • perf-use-memo — Memoize expensive derived values; keep dependency arrays exhaustive
  • perf-debounce — Debounce side-effects triggered by fast user input; use use-debounce
  • perf-fine-grained-selectors — Subscribe to specific state slices, never the whole store object

How to Use

Read a rule file for the detailed explanation and code examples:

rules/project-structure.md    — struct-* rules
rules/api-layer.md            — api-* rules
rules/security.md             — sec-* rules
rules/state-management.md     — state-* rules
rules/component-structure.md  — comp-* rules
rules/error-handling.md       — err-* rules
rules/performance.md          — perf-* rules

Each rule contains:

  • Why it matters — the problem it prevents
  • Bad example — what not to do, with explanation
  • Good example — the correct pattern, with explanation

Full Compiled Document

For all rules expanded in one flat document: AGENTS.md