Skip to the lesson
CivOps AI Academy · M17Website and Content: A Headless CMS for the Site, the Catalogue and the Knowledge Base
0%

Chapter 1 · The content model

Content stored once, shown anywhere

A website built page by page has its words tangled into its layout. A headless content model stores the content once, as typed entries with versions, and lets any front end ask for it. This chapter says what the module does, what it leaves to others, and how its tables hold content safely.

25 min12 tables, prefix cms_5 spaces6 statuses

By the end of this chapter you can

  • Say what a headless content model is and which tools the module replaces.
  • Place a piece of content in one of the five spaces and say which neighbouring module owns what this one leaves out.
  • Explain why versions are never edited and what the two version pointers on an entry mean.

What the module does

The module runs the public website, the product catalogue, the careers pages and an internal knowledge base from one content model. Content has drafts, versions, an editorial workflow, scheduled publishing, preview, languages, search engine data, and forms that feed the CRM and the help desk. It replaces content tools such as WordPress (hosted), Webflow, Contentful, Sanity, Storyblok, Strapi Cloud, Payload and HubSpot CMS, and internal page tools such as Confluence, Notion and SharePoint pages. Independent write-ups compare the headless systems among them [1][2][4]. Treat them as opinion and read every price on the vendor's own page.

Headless means the place where content is written (the back end) is separate from the place where it is shown (the front end). The back end stores content and serves it through a read API (a web address that returns content as data). The front end, which may be a website, a phone app or a kiosk, asks for what it needs and decides how it looks.

Headless content modelA content type defines fields; entries hold the content per locale; each edit is an immutable version; the delivery API serves only published versions to the public website, careers pages, product catalogue and knowledge base. AUTHORINGDELIVERYContent typefields as schemaEntryone per localeVersionimmutable dataDelivery APIpublished onlyPublic websiteCareers pagesProduct catalogueKnowledge baseThe same entry feeds every front end. Layout lives in the front end, not in the content.
One model, many front ends. A content type defines the fields. An entry holds the content for one locale. Each edit is an immutable version. The delivery API serves only published versions to the website, the careers pages, the catalogue and the knowledge base.

What is in, and what is not

  • In: content types defined as schema; entries with versions; editorial workflow, scheduling and preview; a media library with transforms and alt text; localisation with fallbacks; SEO (metadata, JSON-LD, sitemap, redirects); navigation, web forms and search; internal knowledge-base spaces with permissions.
  • Out: controlled documents such as SOPs (M06 Document Control); email campaigns (M16); e-commerce checkout (the catalogue, in a later wave).

Every content type belongs to one of five spaces: public_site, catalog, careers, knowledge_base or internal. The space decides who may read the content, so a knowledge-base article about an internal procedure never shows on the public site.

Content types are schema, not pages

A content type (table cms_content_type) is a named list of fields with rules: a unique key, a name, a schema written as JSON, whether it is a singleton (is_singleton: one entry only, such as site settings), whether it is translated (localized) and its space. The fields are text, rich text, number, date, media, reference to another entry, and component blocks (small reusable groups of fields), each with validation such as required, maximum length or allowed values.

Entries and versions

An entry (cms_entry) is the content of one type, in one locale, at one address (slug). Its words are not stored on the entry itself but in versions (cms_entry_version), each holding the field data as JSON, a version_no and a change_note. A version is immutable: editing creates version number plus one, so history cannot be rewritten, and rollback means copying an old version into a new one.

Versions and the two pointersAn entry has four immutable versions. The published pointer names version 2 and the current pointer names version 4. Rollback creates a new version that copies an old one. Version 1first draftVersion 2approved textVersion 3wording changedVersion 4newest draftpublished_version_idcurrent_version_idReaders see version 2. Editors work on version 4. Rollback copies version 2 into a new version 5.
Two pointers on every entry. published_version_id names the version readers see; current_version_id names the newest version editors work on. They are often different.

Entries that point to other entries (an article that features three products) are recorded in cms_entry_reference. This reference graph is how the module knows which pages to refresh when a product changes.

The twelve cms_ tablesThree columns: content (content type, entry, entry version, entry reference), media and navigation (media asset, locale, nav menu, nav item) and traffic and people (redirect, web form, web form submission, knowledge-base feedback). Contentcms_content_typecms_entrycms_entry_versioncms_entry_referenceMedia and navigationcms_media_assetcms_localecms_nav_menucms_nav_itemTraffic and peoplecms_redirectcms_web_formcms_web_form_submissioncms_kb_feedbackTwelve tables. People and files come from the spine: core_person and core_attachment.
The twelve tables. Each has the standard spine columns (id, tenant_id, created_at, created_by, updated_at, updated_by, row_version, archived_at and ext). People come from core_person and files from core_attachment, so the module has neither a people table nor a file store of its own.

The twelve tables, column by column

The table below is the full definition from the module specification: every column the module adds to the standard ones, with its type and whether it is required (marked req). Types are written as in the specification: text, int, bool, ts (a timestamp with time zone), uuid and json (jsonb in Postgres); an arrow means a foreign key to that table. It is what your agent builds from in Session 2.

TableHoldsColumns: type, req = required
cms_content_typeA content type's schemakey text req, unique; name text req; schema json req; is_singleton bool req; localized bool req; space text req: public_site, catalog, careers, knowledge_base or internal
cms_entryOne entry in one localecontent_type_id → cms_content_type req; slug text req; locale text req; translation_group_id uuid; parent_entry_id → cms_entry; status text req: draft, in_review, approved, scheduled, published or archived; current_version_id uuid; published_version_id uuid; publish_at ts; unpublish_at ts; author_id → core_person; seo json
cms_entry_versionAn immutable version of an entry's dataentry_id → cms_entry req; version_no int req; data json req; change_note text; created_by_person → core_person
cms_entry_referenceThe reference graph, for dependencies and refreshing pagesfrom_entry_id → cms_entry req; to_entry_id → cms_entry req; field_key text req
cms_media_assetAn image, video or document with its metadataattachment_id → core_attachment req; title text; alt_text text req; focal_point json; width int; height int; variants json; license text; credit text
cms_localeA locale with its fallbackcode text req, unique; name text req; fallback_code text; is_default bool req
cms_nav_menuA navigation menu per localekey text req; locale text req
cms_nav_itemA menu itemnav_menu_id → cms_nav_menu req; parent_id → cms_nav_item; label text req; entry_id → cms_entry; url text; seq int req
cms_redirectA redirect rulefrom_path text req, unique; to_path text req; status_code req: 301, 302, 307 or 308; hits int; active bool req
cms_web_formA form definition and its routingkey text req, unique; fields json req; target text req: crm_lead, helpdesk_ticket, email or webhook; consent_text text; success_message text; spam_protection text req: none, honeypot, turnstile or recaptcha
cms_web_form_submissionA submitted form with its routing resultweb_form_id → cms_web_form req; payload json req; utm json; ip_hash text; submitted_at ts req; routed_type text; routed_id uuid; status text req: received, routed, spam or failed
cms_kb_feedbackHelpfulness feedback on an articleentry_id → cms_entry req; helpful bool req; comment text; person_id → core_person; at ts req

The standards the module is built against

StandardUsed in this module for
W3C WCAG 2.2 AA [3]Accessibility of published pages and of the editor
schema.org and JSON-LD; sitemaps.org protocolStructured data and the sitemap for search engines (chapter 3)
RFC 9110 (HTTP semantics)The right redirect codes: 301, 302, 307, 308 (chapter 3)
BCP 47Language tags for locales (chapter 3)
Google Core Web VitalsPerformance targets: LCP, INP, CLS (chapter 3)
Exercise · Model one real content type15 minutes

You need: Your inventory from Session 1 (docs/cms-inventory.md), one real page of your site and your AI coding agent

Choose a kind of content from your own site that appears in more than one place, for example a service, a product or a job posting. Work on paper or in a text file first.

Outcome: A one-page content type design for a real kind of content: space, fields with types and required flags, no layout fields, singleton and localisation decided, plus the JSON your agent produced and you checked.

Knowledge check

An editor changes a published page. What happens to the version that readers see?

Knowledge check

Which field name is a sign the content is coupled to a page layout?

References

  1. Cosmic: Sanity vs Contentful 2026. https://www.cosmicjs.com/blog/sanity-vs-contentful
  2. CoderCops: Sanity, Contentful, Strapi and Payload compared (2026). https://blog.codercops.com/blog/headless-cms-comparison-sanity-contentful-strapi-payload-2026
  3. W3C: Web Content Accessibility Guidelines (WCAG) 2.2. https://www.w3.org/TR/WCAG22/
  4. Techsy: Contentful CMS guide 2026. https://techsy.io/en/blog/contentful-guide

Chapter 2 · From draft to live

Workflow, preview and delivery

Nothing should reach the public by accident. This chapter walks one entry through review, approval, scheduling and publication, shows how editors preview a draft on the real front end, and how the delivery API makes sure readers never see one.

30 min6 statuses2 read pathsAlt text required

By the end of this chapter you can

  • Name the six statuses of an entry and who moves it between them.
  • Explain how preview differs from the delivery API and why the delivery API must never return draft content.
  • Say what a revalidation webhook does and what alt text is required for.

The editorial workflow

An entry's status is one of six values: draft, in_review, approved, scheduled, published, archived. People move it along with rights that follow their job. In this course the roles are author (writes), editor (reviews and approves), publisher (schedules, publishes and unpublishes) and site administrator (content types, locales, forms and menu structure). Reviewers leave comments (core_comment) and each approval step is a row in core_approval, so who approved what, and when, is recorded.

The editorial workflowSix statuses left to right: draft, in review, approved, scheduled, published and archived. An arrow returns from in review to draft when changes are requested, and an arrow skips from approved to published for publish now. draftauthor writesin_revieweditor reviewsapprovededitor approvesscheduledset by publisherpublishedlive to readersarchivedoff the sitechanges requestedpublish nowOnly a published version is ever served to readers. Archived entries are kept, not deleted.
Six statuses. An editor or publisher can send an entry back to draft with a comment. A publisher may publish at once or set a time. Archiving keeps the entry; it is never deleted.
StatusWho moves it hereWhat readers see
draftAuthor, or an editor or publisher sending it backNothing new
in_reviewAuthor, when readyNothing new
approvedEditor, after reviewNothing new
scheduledPublisher, with a time in publish_atNothing until that time
publishedPublisher, or the scheduler at publish_atThe published version
archivedPublisher (or the scheduler at unpublish_at)Nothing: the entry is off the site

Scheduling

An entry has two timestamps, publish_at and unpublish_at. A scheduled run publishes at the first and takes the entry down at the second, for example a seasonal offer or a closing date on a job posting. The run acts as its own named login with rights only to do that. The specification has each change publish an event, cms.entry.published or cms.entry.unpublished, so other modules and the front end can react; the course builds these as an optional extension in Session 4, as rows in an event outbox.

Preview and delivery are different paths

Editors need to see a draft inside the real page, with the real design. The Next.js feature for this is draft mode [1]: a route checks that the person may read the entry and then sets a cookie that makes the page show the current version instead of the published one. Readers never get that cookie. They go through the delivery API, which filters on the published version pointer and returns the published version only.

Reader, preview and revalidation pathsReaders go through the delivery API to the published version. Editors preview through draft mode, which reads the current version. When an entry is published, a webhook asks the front end to revalidate the pages that use it. READERBrowserasks for a pageFront endcached pageDelivery APIpublished pointerPublished versionpublished_version_idEDITOR PREVIEWEditorclicks Preview/api/previewchecks the signed-inperson's rightDraft modecookie setCurrent versioncurrent_version_idON PUBLISHEntry publishedcms.entry.publishedWebhookcalls the front endRevalidatepages that use the entry
Three paths. Readers get the published version. Editors preview the current version in draft mode, with the right checked first. When an entry is published, a webhook calls the front end so the pages that use it are refreshed.

Keeping pages fresh

Pages are built ahead of time and kept in a cache so they load fast. When content changes, the front end must be told. A webhook (a web address the module calls when something happens) tells the front end which pages changed, and the front end revalidates them: it rebuilds just those pages, not the whole site [2][3]. This is what the specification calls ISR (incremental static regeneration). The reference graph from chapter 1 supplies the list: when a product changes, every entry that references it is revalidated too.

The media library

Images, video and documents sit in cms_media_asset, which points to a file in core_attachment and adds a title, a focal point (the part of the image that must stay in frame when it is cropped), width and height, responsive variants (the same image at several sizes; the column exists, but the course does not build image transforms), a licence and a credit. Alt text is required at upload, and a blank value is refused by the database. Alt text is the short written description a screen reader speaks in place of an image; WCAG success criterion 1.1.1 asks for a text alternative for non-text content [4]. Accessibility is a legal exposure in many places, and the module's rule is that an image cannot enter the library without it.

Exercise · Walk one entry through the workflow20 minutes

You need: A development copy of your platform with the seed from Session 2, two test users with different roles, and your AI coding agent

Do not use live data. The aim is to see each status change and prove readers never see a draft.

Outcome: A written trace of one entry through draft, review, approval and publication, a proof that a private window sees only the published text, and a passing test that the delivery API never returns draft content.

Knowledge check

A visitor opens an entry that has a newer, unapproved version. Which text do they see?

Knowledge check

A media asset is uploaded with blank alt text. What should happen?

References

  1. Next.js: How to preview content with Draft Mode. https://nextjs.org/docs/app/guides/draft-mode
  2. Next.js: Revalidating. https://nextjs.org/docs/app/getting-started/revalidating
  3. Next.js: revalidateTag. https://nextjs.org/docs/app/api-reference/functions/revalidateTag
  4. W3C: Understanding Success Criterion 1.1.1, Non-text Content (WCAG 2.2). https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html

Chapter 3 · Being found and loading fast

Languages, search and speed

A page nobody can find, or that loads too slowly, might as well not exist. This chapter covers language fallback, the data search engines read, the right redirect code for each case and the three speed measures Google calls Core Web Vitals.

25 min4 redirect codes3 Web VitalsLighthouse accessibility 95+

By the end of this chapter you can

  • Explain how a locale falls back to another and why a locale can never fall back to itself.
  • Name what a page's seo data produces and choose the right redirect code for a given case.
  • State the three Core Web Vitals and their good thresholds.

Localisation with fallbacks

Each locale (table cms_locale) has a code written as a BCP 47 language tag [1], a name, an optional fallback_code and a flag for the default. A tag such as es names a language; es-MX adds a region. Entries in different languages are linked by a shared translation_group_id, so the front end can offer the same page in another language.

Locale fallback chainA reader asks for a page in es-MX. There is no es-MX entry, so the chain falls back to es, which has one. The last stop is the default locale en. A locale may never fall back to itself. A reader asks for the About page in es-MXes-MXno entry yetfallback_code: esesentry existsfallback_code: enen (default)entry existsis_default: truemisslast stopThe reader gets the es pageRule: a locale may never fall back to itself
A fallback chain. A reader asks for es-MX. There is no entry, so the module tries es, which has one. If es had none, the last stop would be the default, en. A locale may not fall back to itself, directly or in a loop.

The module tracks translation status for each entry. It can also draft a translation with AI, but a person must review it before it goes live: an AI draft is a draft, and never skips the workflow in chapter 2.

What search engines read

Every entry has an seo field: title, description, canonical address (the one address you want search engines to list for the page) and a social image. From it the module produces four things.

From one seo block to four outputsThe seo block on an entry feeds the head tags, JSON-LD structured data and the sitemap, while the redirect manager keeps old addresses working. Entry seotitle, description,canonical, social imageHead tagstitle, description, canonical, Open GraphJSON-LDschema.org type for the pagesitemap.xmlpublished pages onlyRedirect managerold path to new path
One seo block, four outputs. Head tags for the page, JSON-LD structured data, a sitemap that lists published pages only, and the redirect manager for old addresses.
  • JSON-LD is a block of structured data in the page that tells search engines what the page is, using types from schema.org such as WebPage or Product [2][3]. It describes the visible page; it does not replace it.
  • sitemap.xml lists the addresses of your pages for search engines. The protocol limits one file to 50,000 addresses and 50 MB uncompressed, after which you use several files and an index [4]. Only published entries belong in it.
  • Broken-link checks find links inside content that point to an entry that is archived or gone, before a reader finds them.

Redirects, and the code you choose

When an address moves, a redirect (table cms_redirect) sends the visitor and the search engine to the new one. The code says how long the move lasts. HTTP semantics are defined in RFC 9110 [5].

CodeNameUse it when
301Moved PermanentlyThe page has moved for good and the method may change
308Permanent RedirectThe move is permanent and a POST must stay a POST
302FoundA temporary move, such as a seasonal landing page
307Temporary RedirectA temporary move where the method must not change
Redirect chain and one hopTop: an old address passes through three redirects before the final page. Bottom: the redirect map sends the old address straight to the final page in one hop. A chain after several migrations: 3 hops/old/about301/about-us301/company301/aboutA redirect map built from the final page: 1 hop/old/about301 straight to the final page/aboutEvery migrated address should reach a live page in one hop or fewer.
Chains cost you. Each migration that adds a new redirect on top of an old one lengthens the chain. A map built from the final page sends every old address straight there. This is the pitfall the module teaches: redirect chains after migration lose search traffic.

The hits counter on each redirect shows which old addresses are still used, so you know what is safe to retire.

Speed, measured on real visits

Google's Core Web Vitals are three measures of how a page feels [6]: Largest Contentful Paint (LCP, how long until the main content shows), Interaction to Next Paint (INP, how quickly the page responds after a tap or click) and Cumulative Layout Shift (CLS, how much the layout jumps while loading). A page passes when at least 75 percent of real visits meet the good threshold for each.

Core Web Vitals thresholds to scaleThree bars drawn to scale. Largest Contentful Paint: good up to 2.5 seconds, poor over 4. Interaction to Next Paint: good up to 200 milliseconds, poor over 500. Cumulative Layout Shift: good up to 0.1, poor over 0.25. GoodNeeds improvementPoorLCP (seconds)2.5 s4 sINP (milliseconds)200 ms500 msCLS (score)0.10.25Targets are judged at the 75th percentile of real page loads.
Thresholds to scale. LCP good up to 2.5 seconds; INP good up to 200 milliseconds; CLS good up to 0.1. Above 4 seconds, 500 milliseconds and 0.25 respectively, a visit counts as poor.

Lighthouse, a tool built into the Chrome developer tools [7], gives a score for accessibility and performance on one page in one test. The module's own bar for accessibility is a Lighthouse accessibility score of at least 95 on the seeded templates. A score is only a first check: it cannot see whether alt text makes sense.

Exercise · Audit one page for search and speed15 minutes

You need: A page of your site, Chrome with its developer tools, your sitemap.xml and your AI coding agent

Use a real page from the inventory you made in Session 1. You only read; change nothing on the live site.

Outcome: A one-page audit of a real page: its seo data, accessibility score, sitemap status, the redirect hops for one moved address, and the single redirect row that replaces the chain.

Knowledge check

A seasonal offer page moves to a holding page for three weeks, then comes back. Which redirect code fits?

Knowledge check

Which statement about a locale called es-MX with fallback_code es is right?

References

  1. IETF BCP 47: Tags for Identifying Languages. https://www.rfc-editor.org/info/bcp47
  2. schema.org. https://schema.org/
  3. W3C: JSON-LD 1.1. https://www.w3.org/TR/json-ld11/
  4. sitemaps.org: The Sitemaps protocol. https://www.sitemaps.org/protocol.html
  5. IETF RFC 9110: HTTP Semantics. https://www.rfc-editor.org/rfc/rfc9110.html
  6. web.dev: Web Vitals. https://web.dev/articles/vitals
  7. Chrome for Developers: Lighthouse overview. https://developer.chrome.com/docs/lighthouse/overview

Chapter 4 · From visitor to record, and from old site to new

Forms, knowledge base and the move

A site earns its keep when a visitor becomes a lead or a ticket, when staff find answers without calling anyone, and when the move from the old tool loses nothing. This chapter covers web forms with consent, the internal knowledge base, and a safe migration.

25 min4 form targets4 spam options1 redirect hop at most

By the end of this chapter you can

  • Describe how a web form submission is checked, stored with its consent text, and routed.
  • Explain how the knowledge base is structured, permissioned and measured.
  • Plan a migration so that every old address resolves in one hop or fewer before the domain moves.

Web forms that create records

A web form (table cms_web_form) has a unique key, its fields, a target, the consent_text shown to the visitor, a success_message and a spam_protection choice. The target is one of crm_lead, helpdesk_ticket, email or webhook. Each submission (cms_web_form_submission) stores the payload, the campaign tags from the address (utm), a hashed form of the visitor's network address (ip_hash, a one-way scrambled value, so the raw address is not kept), the time, and a status: received, routed, spam or failed. The consent text shown and the form's version are kept inside the payload, because the table has no separate columns for them.

A form submission from page to targetA visitor fills a web form that shows consent text. The spam check either marks the submission spam or lets it become a stored submission row, which is routed to a CRM lead, a help-desk ticket, an email or a webhook. Web formfields, consent textSpam checkspam_protectionSubmission rowpayload, utm, ip_hashStatus routedrouted_type, routed_idStatus spamcrm_leadhelpdesk_ticketemailwebhookRouted by its target; the optional extension also publishes cms.web_form.submitted.
From visitor to record. The form shows its consent text. The spam check sends a bad submission to status spam. A good one is stored and routed to the CRM, the help desk, an email or a webhook; in the optional extension the module also publishes cms.web_form.submitted.
Spam protectionWhat it isCost
noneNo checkFree, and invites spam
honeypotA hidden field that people leave empty and simple bots fill inFree
turnstileCloudflare's challenge that runs in the visitor's browser [1]Needs an account with the provider: read the price on its page
recaptchaGoogle's challengeNeeds an account with the provider: read the price on its page

The free way comes first: start with a honeypot, measure how much spam still gets through, and move to a provider's challenge only if it does.

The internal knowledge base

The knowledge base is a set of internal spaces. Its pages form a tree through parent_entry_id, its permissions follow the space, and each article collects feedback in cms_kb_feedback: helpful or not, an optional comment, who and when. Help-desk tickets link to articles, and a signal from the help desk, svc.kb_gap.detected, tells the module that people keep asking something no article answers. In the optional extension the catalogue also reacts to plm.part.released: a released part drafts a new version of its product entry for review, never a published change.

The four measures

KPIDefinition
Core Web Vitals pass ratePages passing the LCP, INP and CLS thresholds
Publishing lead timeMedian hours from draft to published
Form conversionSubmissions divided by form views
KB deflectionHelp-desk tickets avoided after an article view

Measure the first number before you change anything. The baseline from Session 1 is what lets you say, at the end, that publishing got faster.

Moving from the old tool

The old content comes out as files: WordPress through its REST API [2] or an export file, Webflow as CMS CSV files, and Contentful as an export. Each maps to your content types; comparisons of the systems you may be leaving or joining are in [5]. The import creates drafts only, so nothing reaches the public site except through the review in chapter 2.

Moving from the old siteSix steps: export the old site, map it to content types, import as drafts, build the redirect map, verify each old address reaches a live page in one hop, then cut over the domain. Export the old sitepages, media, addressesMap to content typesfields to schemaImport as draftsnothing goes live yetBuild the redirect mapevery old addressVerify one hopscript checks each addressCut over the domainon a date you setThe redirect map is finished and checked before the domain moves.
The order matters. Build and check the redirect map from the list of every old address before DNS is cut over. A moved site with broken addresses loses the search standing it earned.

Search engines publish guidance on moving a site [3][4]: keep a permanent redirect from every old address to its new equivalent, and keep the redirects in place long after the move. Your definition of done has three checks you can run by script.

  • The published API never returns draft content (a test).
  • Every migrated address resolves with at most one redirect hop (a script that follows each one).
  • A Lighthouse accessibility score of at least 95 on the seeded templates.
Exercise · Build and check a redirect map20 minutes

You need: The list of public addresses saved in Session 1, a list of the new addresses, a spreadsheet or text file and your AI coding agent

Work on a copy of the lists. Nothing here touches the live site.

Outcome: A redirect map covering every old address (or retiring it with a reason), no chains, a script result showing every address resolves in one hop or fewer, and the map merged on main.

Knowledge check

Why is the consent text stored with each form submission?

Knowledge check

Which step must be finished before the domain is moved to the new site?

References

  1. Cloudflare: Turnstile documentation. https://developers.cloudflare.com/turnstile/
  2. WordPress Developer Resources: REST API Handbook. https://developer.wordpress.org/rest-api/
  3. Google Search Central: Site moves with URL changes. https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes
  4. Google Search Central: Redirects and Google Search. https://developers.google.com/search/docs/crawling-indexing/301-redirects
  5. Rajesh Kumar: Top 10 headless CMS. https://www.rajeshkumar.xyz/blog/?p=1145

Chapter 5 · 12 questions · 80% passes

Final assessment

Twelve questions across the element. Score 80% (10 of 12) to pass. Your LMS records your score and each answer; you can review the chapters and try again.

15 min12 questions≈ 15 minutesRetake allowed

Choose one answer for each question, then submit. You will see the right answer and why for every question.

1. What does "headless" mean for a content system?
2. Which is the best way to design a content type for a product?
3. An editor changes a published entry. What does the module do?
4. What do published_version_id and current_version_id on an entry mean?
5. A visitor opens an entry that has a newer, unapproved version. Which text appears?
6. What does a revalidation webhook do after an entry is published?
7. An image is uploaded to the media library with blank alt text. What should happen?
8. A reader asks for the page in es-MX, which has no entry, but its fallback_code is es and es has one. What do they get?
9. Which redirect code fits a page that has moved for good, when its method may change?
10. Why are redirect chains a problem after a migration?
11. Which statement about Core Web Vitals is right?
12. Why is the consent text stored with each form submission?