File Naming (Canonical)¶
This is the single normative rule for source filenames in the monorepo. Other docs link here instead of restating policy.
Exports vs files: React components, types, and interfaces use PascalCase symbols. Filenames use kebab-case (or the exceptions below). The filename does not have to mirror the export name character-for-character.
Example: theme-provider.tsx exports ThemeProvider; sign-in.ts exports signInAction.
Default (apps and packages)¶
| Artifact | Filename | Primary export |
|---|---|---|
| React component | kebab-case.tsx |
PascalCase FooBar |
| Hook | use-kebab-case.ts |
camelCase useFooBar |
| Pure util / lib module | kebab-case.ts |
camelCase functions |
| Co-located test | kebab-case.test.ts(x) next to the source file |
— |
| Multi-segment folder | kebab-case/ per path segment |
— |
Remote unit tests (tests/unit/**): kebab-case.test.ts, or parent-segment.module-name.test.ts when mirroring query modules (e.g. enrollments.by-user.test.ts).
Exceptions (do not “normalize” away)¶
| Location | Pattern | Rationale |
|---|---|---|
packages/ui/src/components/ui/* |
shadcn lowercase single-word (button.tsx) or kebab-case multi-word (confirm-dialog.tsx) |
shadcn CLI regeneration |
packages/widget-renderers/** |
kebab-case aligned with widget type slugs (word-search-widget.tsx) |
Wire format + CMS widget files |
| Barrels and shared type files | index.ts, types.ts, domain.ts |
Conventional module entrypoints |
| Next.js App Router | page.tsx, layout.tsx, route.ts, [param]/, (group)/ |
Framework conventions |
Per-app status¶
| App / area | Status |
|---|---|
apps/cms components |
Compliant — kebab-case under src/components/; tests often in __tests__/ with matching kebab names |
apps/cms modules |
Compliant — kebab-case under src/lib/** (minor outlier: tokenVersion.ts in src/lib/auth/) |
apps/lms components |
Compliant — kebab-case under src/components/ and src/app/**/_components/; co-located kebab-case.test.tsx |
apps/lms modules |
Compliant — kebab-case under src/lib/**, src/auth/**, src/db/**, src/types/**, and route-colocated action modules |
apps/lms test harness |
Compliant — tests/utils/render-with-theme.tsx (export renderWithTheme stays camelCase) |
packages/* |
Compliant — follow table above; no PascalCase component filenames |
Cross-app ticket: T-027 CMS vs LMS Drift.
Enforcement¶
- Report-only audit:
npm run audit:filenames(future CI gate support via--strict). - Component/module migration scripts are historical and should not be re-run unless restoring from a bad state.
- Canonical script details (scope, flags, and usage) live in Root Scripts Reference.
- Git blame: root
.git-blame-ignore-revslists the migration commit so blame skips renames. GitHub uses it automatically; locally rungit config blame.ignoreRevsFile .git-blame-ignore-revsonce per clone.
New files under apps/lms/src/** and apps/lms/tests/utils/** must use kebab-case filenames and folders. Component tests: co-located kebab-case.test.tsx (see apps/lms/.cursor/rules/030-testing.mdc).
Related rules¶
- Export naming (PascalCase components, types): 030-coding-best-practices.mdc
- LMS co-located component tests: apps/lms/.cursor/rules/030-testing.mdc
data-testidvalues (kebab-case, not filenames): 059-data-testid-policy.mdc