@open-learning-hub/server shared package
Problem¶
Several server primitives are duplicated or only present in one app:
- bcrypt password hashing (helper in CMS, inline calls in LMS — see T-012).
- Security headers (only CMS — see T-001).
- Structured redacting logger (only LMS, sparsely used; CMS has none).
- API error helper /
ApiError(CMS only — converged in T-003 for LMS). - Rate-limit driver interface (now shared; see notes).
Consolidating these into a workspace package keeps the apps thin without forcing schema or mutation-transport convergence (which is a standing decision to leave alone).
Proposal (partially implemented)¶
- Add/expand
packages/server/workspace package withname: "@open-learning-hub/server"and per-feature subpath exports (no barrel):./password → bcrypt cost 12 helpers ./errors → ApiError + handleApiError + ErrorCode union ./headers → getSecurityHeaders() ./log → structured redacting logger (port from either app's src/lib/log.ts per .cursor/rules/091-structured-logging.mdc parity contract) ./rate-limit → driver interface + memory + upstash drivers - Configure as source-only (no
dist/), consumed viatranspilePackagesin both apps'next.config.ts(matcheswidget-wire-schemaspattern). - Strict TS,
noUncheckedIndexedAccess: true(matches other packages). - Migrate consumers:
- CMS: replace
apps/cms/src/lib/security/headers.ts,apps/cms/src/lib/api/errors.ts,apps/cms/src/lib/auth/password.tsimports with@open-learning-hub/server/*re-exports (keep thin compatibility shims for one release if helpful). - LMS: replace the modules landed by T-001, T-003, T-012 with
@open-learning-hub/server/*imports.
- CMS: replace
- Add unit tests in
packages/server/src/**/__tests__/mirroring the original locations.
Acceptance criteria¶
- New
packages/server/rate-limit surface transpiles and is consumed by both apps. - CMS and LMS import remaining primitives from
@open-learning-hub/server/*instead of app-local modules (legacy paths either deleted or shimmed to the package). - All pre-existing tests still pass; new package-level tests added.
-
npm run checkpasses.
Out of scope¶
- Converging the rate-limit concrete driver implementations (memory is shared; upstash stays deferred per T-014).
- Sharing Auth.js config (auth models intentionally diverge).
- Sharing DB / Kysely schemas.
Notes / decisions log¶
- 2026-05-24: Ticket created from monorepo audit. Scheduled to land after T-001, T-003, T-012 so the API shapes are stable before extraction.
- 2026-05-25: Deferred for a later effort. App-local primitives (T-001, T-003, T-012) can land without extraction; reactivate when monorepo consolidation is reprioritized.
- 2026-05-25: Moved to
tickets/deferred/alongside T-014 and T-015. - 2026-05-25: T-009 (CMS
server-onlyguards) deferred as companion work when this package effort resumes. - 2026-07-07: Implemented
@open-learning-hub/server/rate-limitsubpath and migrated LMS/CMS rate-limit drivers to it. Remaining shared-package work (./errors,./log, and consolidation of existing standalone packages) stays deferred.