Feature: Entry list of a custom content type As a verified user I want to browse the entries of a custom content type So that I can find an entry before editing it Background: Given the SPA calls the API with relative URLs under /v1 and the "jwt" HttpOnly cookie And API errors are plain text And the route is /content/:key with meta auth "verified" and title "Content", per docs/design/screens/content.md group "5 Content and entry list", states 1 to 9 And the page requests GET /v1/content-type/{key} (the type) and GET /v1/content-type/{key}/entry?page=P&size=S&sort=O (the entries) at the same time; the entries answer {items, total, page, size} (no sort) and each item is {id, content_type (the type key), data, created_by, updated_by, created_at, updated_at} And the sidebar Content group of features/schema_list_and_content_nav.feature is reused unchanged; this slice only checks it in the "Many types" state And page, size and sort live in the URL (/content/events?page=2&size=50&sort=created_at:desc), the defaults (page 1, size 25, sort updated_at:desc) are omitted from the URL, and the request always carries explicit page and size And size is one of 5, 25, 50, 100; sort is :; an invalid value is replaced silently by the default in the URL and in the request, so the API never answers 400 here And a size or sort change resets page to 1; the URL changes when a response succeeds, not when the request is sent And the pager, the page-size select, the summary, the loading page, the page error notice and the out-of-range redirect behave as in features/articles_pagination_screen.feature scenarios 1 to 7, 10, 10b and 11, with the content URL and request And the page size is not remembered And the columns are ID, up to 6 chosen field columns (default: the first 4 fields of the type, fewer if the type has fewer), Created, Updated and Updated by; ID, Created, Updated and Updated by are always shown And a field cell shows: Text truncated on one line with the full text as tooltip; Rich text as its first line in plain text, truncated; Number right-aligned with tabular figures; Yes or no as an icon plus "Yes" or "No"; Date as day, month and year ("21 Nov 2026") with no time-zone shift; Choice as a small outline tag; an empty value as "–" And Created reads "12 Oct 2026" and Updated reads "15 Oct 2026" (date only, local time zone), ID is mono and muted And "Updated by" is the display_name from one GET /v1/user/lookup?ids= sent after the entries answer; until it resolves, and if it fails or does not know the id, the cell shows a muted "–" And the desktop list is a table with a 36 px header and 48 px rows; below md it is a card list with 68 px cards, each card a link with a chevron-right, showing the first field, the second field, the first Choice field as a tag if the type has one, and "· {Updated by}"; cards ignore the column picker And every row is a link to /content/:key/:id (a link on the first field cell on desktop, the whole card on mobile); the click uses the router And "New entry" (primary, plus icon, in the title row on desktop; a floating button on mobile) navigates to /content/:key/new And /content/:key/new and /content/:key/:id are not routed in this slice and land on the catch-all 404 until the entry editor slice And "Edit content type" (ghost, settings-2 icon, right of the toolbar) navigates to /schema/:key; it is shown to owner and admin only and not on mobile And no filter or search exists And every string goes through t() and has a French entry in i18n/messages.ts And a copy tagged "(proposed copy)" is not in the design and is the coder's single point of change Scenario: 1 Populated, one page Given GET /v1/content-type/events resolves 200 with 7 fields and GET .../entry?page=1&size=25&sort=updated_at:desc resolves 200 with 7 items and total 7 When the user navigates to /content/events Then the breadcrumb reads "Content" then "Events", the title "Events" with the subtitle "events · 7 fields" And "New entry" is in the title row and the toolbar reads "Sort by" "Last updated", a direction button, "Columns", then "Edit content type" at the right And the table headers read "ID" "Title" "Starts on" "Ends on" "Online" "Created" "Updated" "Updated by" and the Updated header shows an arrow-down icon And 7 rows show, the first row ID 42 "Lime plaster workshop" "21 Nov 2026" "22 Nov 2026" "No" "12 Oct 2026" "15 Oct 2026" "Marta Alves" And no pager, no page-size select, only the text "7 entries" ("1 entry" for one, proposed copy) And the sidebar row Events is the current page and the URL has no query Scenario: 2 Paginated, 5 per page Given GET .../entry?page=1&size=5&sort=updated_at:desc resolves 200 with 5 items and total 37 When the user navigates to /content/events?size=5 Then the summary reads "Showing 1–5 of 37", the page-size select reads "5 per page" and the paginator shows First, Previous (both disabled), 1 (current), 2, an ellipsis, 8, Next, Last And on mobile the paginator reads Previous (disabled), "Page 1 of 8", Next And activating Next sends page=2 and, on success, the URL is /content/events?size=5&page=2 Scenario: 3 Columns menu Given the populated state of the 7-field type Events When the user activates "Columns" Then a popover opens on desktop and a bottom sheet on mobile, titled "Columns" with "4 of 6" And the sheet adds the text "Choose up to 6 fields to show. 4 selected." and the actions "Reset" and "Done"; the popover has "Reset" only And each of the 7 fields is a checkbox row with its type icon, its label and its key in mono, in schema order; Title, Starts on, Ends on and Online are checked And a last row with a clock icon reads "Created and updated dates always show" with a disabled, unchecked checkbox When the user checks "Capacity" Then the table gets a Capacity column (right-aligned) at once, with no request, and the count reads "5 of 6" And Esc, a click outside or "Done" closes it and returns focus to "Columns" Scenario Outline: The column cap and the stored choice Given the 7-field type Events and When Then Examples: | before | action | after | | 6 fields checked | the user opens the menu | the unchecked fields are disabled and the text "You can show up to 6 fields." (proposed copy) shows | | 5 fields checked | the user checks a 6th | it is checked and the others become disabled | | 6 fields checked | the user unchecks one | the others are enabled again | | the default 4 and nothing stored | the user checks "Capacity" | localStorage renewcms-content-columns-events is ["title","starts_on","ends_on","online","capacity"] | | a stored selection | the user activates "Reset" | the default 4 apply and the stored key is removed | | stored ["title","gone","capacity"] | the page loads | the columns are Title and Capacity, and nothing is written | | stored with 8 valid keys | the page loads | the first 6 in schema order show | | stored "not json" or [] | the page loads | the default 4 show | | localStorage throws or is undefined | the user changes the selection | the columns change for this visit and no error shows | | stored for events | the user opens /content/recipes | Recipes uses its own key and its default | Scenario: The last field column cannot be unchecked Given the 7-field type Events with exactly one field checked When the user opens the Columns menu Then that field's checkbox is disabled, so at least one field column always shows and every row has its link And a stored empty selection loads as the default 4 Scenario: A type with fewer than 4 fields Given a type with 2 fields When the user opens its list Then both field columns show and "of 6" in the menu still reads the cap Scenario Outline: Sort control Given GET .../entry resolves 200 and the user is on /content/events?page=3 When the user chooses "