Skip to content

CMS server-only guards

Problem

LMS mechanically guards ~65 DB/auth/rate-limit modules with import "@/lib/server-only". CMS has almost no server-only imports despite holding the same kind of sensitive code (Kysely access, Auth.js config, bcrypt). A future refactor could accidentally pull a CMS server module into a client component and leak AUTH_SECRET or DATABASE_URL into the client bundle.

Proposal (deferred — not started)

Reactivate with T-006 when @open-learning-hub/server extraction is reprioritized — land mechanical guards as part of that consolidation pass rather than ahead of it.

  1. Add import "server-only" (or import "@/lib/server-only" if a thin re-export is preferred for consistency with LMS) to every file under:
    • apps/cms/src/lib/db/**
    • apps/cms/src/lib/auth/**
    • apps/cms/src/lib/rbac/**
    • apps/cms/src/lib/security/**
    • apps/cms/src/lib/api/external-auth.ts and any rate-limit modules
  2. If a CMS module is intentionally shared between server and client, leave it untouched but call it out in the PR description.
  3. Verify by running next build; any accidental client import will fail loudly.
  4. Add a short note to apps/cms/AGENTS.md documenting the convention.

Acceptance criteria

  • All targeted modules begin with import "server-only";.
  • next build succeeds for CMS (no client-bundle leakage).
  • AGENTS.md updated.
  • npm run check passes.

Out of scope

  • Refactoring code organization beyond adding the guard.
  • LMS already has this; no LMS changes.

Notes / decisions log

  • 2026-05-24: Ticket created from monorepo audit.
  • 2026-05-25: Deferred — bundle with T-006; reactivate when @open-learning-hub/server extraction is reprioritized.
  • 2026-05-25: Moved to tickets/deferred/ alongside T-006, T-014, and T-015.