Keel

Docs / AI-native / Conventions

Conventions

memory/conventions.md is where the small, repeated decisions live, the ones that are easy to get wrong differently in every file if nobody writes them down. This page covers the same ground that file does, so you can see the format before you start extending it.

Naming

  • Files: kebab-case (team-switcher.tsx), not camelCase or PascalCase.
  • Components: PascalCase exports, named, not default, so renames show up in every import.
  • Route handlers: always route.ts under app/api/**, never a server action, see "No Server Actions" below.

Folder shape

Feature-first, not type-first. components/app/settings/ holds everything the settings pages need, rather than scattering settings-related pieces across a global components/forms/, components/cards/ split.

No Server Actions

Every mutation goes through a traditional /api route handler, called from a client component via fetch. This holds even though Next's own docs default to Server Actions for forms.

Why this is a hard rule, not a preference

Mixing Server Actions and route handlers in the same codebase means two different mental models for "how does a mutation get to the database," and two different places to check for auth/permission gating. Picking one and sticking to it removes an entire category of "wait, which pattern does this use" questions six months in.

Data access

Server-side session and permission logic for API routes lives in lib/dal/*.ts, each file starting with import "server-only". Route handlers call into the DAL instead of re-deriving the session inline, so the "is this user allowed to see this" logic exists in exactly one place per resource.

Edit this page on GitHub →Last updated Jul 19, 2026