Skip to content

Define and enforce project publication semantics for v1 course APIs

Problem

The LMS currently calls GET /api/v1/projects with status=published and locale=<locale> when resolving published courses. That route accepts those query params, but does not enforce them:

  • status is ignored by the handler.
  • locale is ignored for filtering semantics.
  • The projects table has no canonical publication-status column, so "published courses only" is not enforceable at the data layer.

This also affects OG/public metadata safety assumptions:

  • LMS route behavior and social metadata generation rely on "published" course expectations.
  • Without explicit publication semantics, unpublished content can be accidentally exposed through listing and downstream metadata paths.

Why this matters

  • Security/content governance: Draft or internal projects can leak to learner-facing routes and social crawlers.
  • Contract drift: LMS consumer code assumes status=published is authoritative while the CMS producer does not enforce it.
  • Operational ambiguity: Product and engineering currently lack one source of truth for "project is publishable/public."

Implemented direction

  1. Defined canonical project visibility states as draft | published in CMS validation and authoring UI.
  2. Added explicit publication state to CMS project persistence (projects.status) with migration and index support.
  3. Updated CMS v1 list/detail APIs to enforce publication filtering (status) for project discovery routes.
  4. Documented and enforced locale filtering as an exact match against projects.language for cross-tenant list semantics.
  5. Aligned LMS fetchers and adapters to consume real status values and filter non-published projects at the contract boundary.

Acceptance criteria

  • A canonical publication field exists for projects and is documented.
  • /api/v1/projects enforces publication filtering for published-only requests.
  • Public LMS course discovery paths only return published projects.
  • Locale semantics for project listing are documented and enforced.
  • Contract tests cover status and locale behavior end-to-end.

Out of scope

  • Reworking page-level publication semantics.
  • Redesigning non-v1 internal CMS admin endpoints unrelated to public listing.