Generates the Content context for serving published content (blog posts, pages, landing pages, and documentation) to public and authenticated viewers.
$ mix cms_gen.content
This is the single-tenant, production-facing content system. Access control is
based on authentication (any non-nil scope vs nil) rather than multi-tenancy —
there is no account_id/project_id filtering, and the scope value is never
inspected beyond nil-vs-not-nil. phx.gen.auth is not required: pass whatever
your app already uses to represent an authenticated viewer, or nil for
anonymous-only content. It is distinct from the multi-tenant ContentAdmin
layer and is the target of the publishing/sync flow.
Generated files
Schemas
lib/app/content/content.ex— Content schema (slug, content_type, processed HTML, SEO/OG metadata)lib/app/content/tag.ex— Tag schema (global, single-tenant)lib/app/content/content_tag.ex— Join schema for content/tags
Repositories
lib/app/content/content_repository.ex— Published content queries (scope-aware)lib/app/content/tag_repository.ex— Tag upsert/lookup
Context
lib/app/content.ex— Content context with sync_content/1 publishing flow
Pull flow
lib/app/content/pull.ex— manifest fetch, hash verification, atomic replacelib/app/content/pull_client.ex— Req client for manifest/blob GETslib/app/content/s3_client.ex— ExAws S3 put/get (needs :ex_aws + :ex_aws_s3)lib/app/content/ex_aws_req_client.ex— Req-backed ExAws HTTP client
Web
lib/app_web/controllers/content_sync_controller.ex— POST /sync (push) and POST /pull (trigger), both deploy-key authenticated
Migrations
priv/repo/migrations/*_create_content_tables.exs— contents + tags + content_tags
The /api/content router scope is injected automatically, and injection is
idempotent — re-running the generator will not duplicate it.