Shop It Docs
Developer Resourcescontent

Content Module Backend Documentation

Newsletter schema, entitlement model, runtime behavior, and release checklist for content series/items/featured flows.

Content Module - Backend Documentation

1. Scope

Content module manages newsletter publishing, featuring, and subscription-tier entitlement checks.

content_type is intentionally constrained to newsletter in the current contract. The enum stays explicit to preserve extension points for future content families without changing column shape.

2. Newsletter Tables

Primary tables:

  • content_series
  • content_item
  • newsletter_content_tier
  • content_series_slug_history
  • content_item_slug_history
  • featured_content
  • content_series_tag

Tier-mapping table (newsletter_content_tier):

  • content_item_id FK to content_item.id (ON DELETE CASCADE)
  • series_id FK to content_series.id (ON DELETE CASCADE)
  • required_tier enum (basic | premium)
  • exactly one target set per row (content_item_id xor series_id)

3. Entitlement Model

Newsletter full-content access depends on:

  • tier mapping via newsletter_content_tier at item or series level
  • active user_feature_access_window rows for newsletter feature keys
  • feature keys: newsletter.basic, newsletter.premium
  • validity check: started_at <= now and ended_at IS NULL

Tier resolution behavior:

  • no tier mapping means preview/free-access content
  • basic requirement is satisfied by basic or premium
  • premium requirement is satisfied only by premium

4. Runtime Behavior

API surfaces are split by responsibility:

  • admin leaf modules: series, items, featured
  • customer leaf modules: series, items, featured
  • mobile prefix is applied by MobileModule composition

Runtime mode:

  • public preview/list endpoints for published content
  • JWT-protected full-content and library endpoints
  • cache-aside reads with deterministic keys
  • prefix invalidation on admin writes

5. Schema Hardening

  • featured_content has featured_content_date_window_check
    • allows NULL start/end
    • blocks invalid windows where start_date > end_date
  • content_series_tag has content_series_tag_tag_id_idx
    • optimizes tag-to-series lookups for tag-filtered browse flows
  • newsletter_content_tier_exactly_one_target
    • enforces one target (content_item_id xor series_id)
  • full-text + trigram indexes support title/body and slug search paths in customer lookups

6. Integration Dependencies

  • subscription module (subscription_module, user_feature_access_window) for entitlement
  • notification flows for newsletter email and push delivery
  • Redis for cache and rate-limiting counters

7. Runtime Configuration

Rate limits:

  • CONTENT_ADMIN_RATE_LIMIT (default 100)
  • CONTENT_ADMIN_RATE_WINDOW_SECONDS (default 60)
  • CONTENT_CUSTOMER_ITEM_RATE_LIMIT (default 30)
  • CONTENT_CUSTOMER_ITEM_RATE_WINDOW_SECONDS (default 60)
  • CONTENT_CUSTOMER_SERIES_RATE_LIMIT (default 100)
  • CONTENT_CUSTOMER_SERIES_SEARCH_RATE_LIMIT (default 50)
  • CONTENT_CUSTOMER_SERIES_RATE_WINDOW_SECONDS (default 60)

Cache TTL:

  • CONTENT_CUSTOMER_SERIES_CACHE_TTL_SECONDS (default 1800)
  • CONTENT_CUSTOMER_ITEM_CACHE_TTL_SECONDS (default 900)
  • CONTENT_CUSTOMER_MY_LIBRARY_CACHE_TTL_SECONDS (default 60)
  • CONTENT_CUSTOMER_PURCHASES_CACHE_TTL_SECONDS (default 60)
  • CONTENT_CACHE_TTL_SECONDS (optional override for featured runtime)
  • REDIS_CACHE_TTL_SECONDS (global fallback)

8. Error Handling

HTTPerrorCodeMessage
400CONTENT_STATUS_INVALIDCannot set status=published when scheduledAt is in the future.
400CONTENT_ARCHIVED_NOT_PUBLISHABLEArchived content cannot be published.
400CONTENT_SCHEDULED_AT_INVALIDInvalid scheduledAt value.
400CONTENT_SERIES_CREATE_FAILEDFailed to create content series.
400CONTENT_NOT_PUBLISHEDCannot send unpublished newsletter.
403CONTENT_ACCESS_DENIEDYou do not have access to this content.
404CONTENT_NOT_FOUNDContent item not found.
404CONTENT_SERIES_NOT_FOUNDContent series not found.
404CONTENT_CATEGORY_NOT_FOUNDCategory with ID <id> not found.
404TAG_NOT_FOUNDTag not found for id(s): <ids>.
404FEATURED_CONTENT_NOT_FOUNDFeatured content not found.
400FEATURED_CONTENT_INVALID_DATE_RANGEFeatured startDate must be before or equal to endDate.
503ERR_CONFIG_INVALIDConfiguration validation failed.
429RATE_LIMIT_EXCEEDEDToo many requests. Please try again later.

9. Backend Diagram

10. Module Composition

  • ContentModule - shared module
    • imports: ConfigModule, DatabaseModule, RedisModule, TrainingModule
  • ContentAdminAggregateModule - admin aggregate
    • ContentAdminModule: series CRUD
    • ContentItemAdminModule: item CRUD
    • ContentFeaturedAdminModule: featured management
  • ContentCustomerAggregateModule - customer aggregate
    • ContentCustomerModule: series + items + library
    • ContentFeaturedCustomerModule: featured listing

11. File Map

ConcernFile PathPurpose
Admin seriesapps/api/src/modules/content/admin/series/*Series CRUD
Admin contentapps/api/src/modules/content/admin/content/*Content item CRUD
Admin featuredapps/api/src/modules/content/admin/content-featured/*Featured management
Customer seriesapps/api/src/modules/content/customer/series/*Series discovery
Customer contentapps/api/src/modules/content/customer/content/*Content item access
Customer featuredapps/api/src/modules/content/customer/content-featured/*Featured listing
DB schemapackages/db/src/schema/content/*Table definitions

12. Release/QA Checklist

  • Series, item, and featured admin/customer routes resolve from leaf modules.
  • Entitlement checks enforce tier gating on full-content endpoints.
  • Newsletter tier mapping enforces exactly-one-target invariant.
  • Featured date-window check rejects invalid start/end ranges.
  • Cache key prefixes are deterministic and invalidated on content mutations.
  • Rate-limit envs are present and pass startup validation.
  • Structured errors return stable errorCode values for all major failure paths.

13. Environment Variables

VariableDefaultDescription
CONTENT_ADMIN_RATE_LIMIT100Rate limit for admin content operations
CONTENT_ADMIN_RATE_WINDOW_SECONDS60Rate limit window for admin operations
CONTENT_CUSTOMER_ITEM_RATE_LIMIT30Rate limit for customer content item requests
CONTENT_CUSTOMER_ITEM_RATE_WINDOW_SECONDS60Rate limit window for customer item requests
CONTENT_CUSTOMER_SERIES_RATE_LIMIT100Rate limit for customer series requests
CONTENT_CUSTOMER_SERIES_SEARCH_RATE_LIMIT50Rate limit for series search requests
CONTENT_CUSTOMER_SERIES_RATE_WINDOW_SECONDS60Rate limit window for customer series
CONTENT_CUSTOMER_SERIES_CACHE_TTL_SECONDS1800Cache TTL for customer series list
CONTENT_CUSTOMER_ITEM_CACHE_TTL_SECONDS900Cache TTL for customer item detail
CONTENT_CUSTOMER_MY_LIBRARY_CACHE_TTL_SECONDS60Cache TTL for customer library
CONTENT_CUSTOMER_PURCHASES_CACHE_TTL_SECONDS60Cache TTL for customer purchases
CONTENT_CACHE_TTL_SECONDS-Optional override for featured runtime
REDIS_CACHE_TTL_SECONDS-Global fallback cache TTL

Time fields in this module are stored as timezone-aware values and should be handled as ISO-8601 instants by API consumers.


See Also