Spillway CMSStructured content like Drupal. Page building like Puck. Setup like Ghost. AI that drafts, people who approve.
Menu

Gap analysis: KWALL Drupal starter vs. Spillway

Read-only comparison of the higher-education Drupal starter at kwall-drupal-starter (Drupal 11 on Pantheon, custom upstream) against Spillway on the phase-2b branch, as of 2026-11-05. Spillway status was taken from the code, not the roadmap: "Shipped" means a route, table and admin screen exist; "In progress (2b)" means the branch has a dependency, contract or scaffold but no working feature yet; "Planned" cites the roadmap phase; "Missing" means neither.

What is actually on phase-2b beyond the committed v0.2: a 0008_api_tokens migration, a packages/fleet scaffold (types, errors, http), pg and @extism/extism added to core/package.json, jose and node-saml added in the last commit, and a Phase 3 contract block in packages/shared/src/index.ts for API tokens and the MCP server. No SSO, menu, personalization, analytics, Postgres dialect, MCP endpoint or module runtime code exists yet.

1. Inventory of the Drupal starter

The starter is Pantheon's drupal-composer-managed upstream with KWALL's modules, theme and config. config/ and recipes/ are empty; the real site configuration (1,634 files) is shipped inside web/modules/custom/kwall_starter_helper/site-configs/full-feature-edu, with variants city (adds a Services type and a water-leak webform), portal (adds an Audience vocabulary, permissions_by_term, masquerade and a login-walled site) and news-site-fixes. core.extension.yml enables 264 modules on the standard profile. Thirty-one composer patches are carried against core and contrib.

Contrib modules by purpose

PurposeModules (composer require; those not enabled in the edu config are marked with an asterisk)
Content modelingparagraphs, paragraphs_library, layout_paragraphs, entity_reference_revisions, field_group, field_permissions, auto_entitylabel, name, address, telephone_*, time_field, date_recur, date_recur_modular, color_field, tablefield, block_field, viewsreference, inline_entity_form, entity_reference_tree, entity_type_clone, entity_clone\, quick_node_clone\, replicate(+ui, actions), single_content_sync, default_content, storage, year, maxlength, node_title_help_text, allowed_formats\*
Editorial workflow and schedulingcontent_moderation, workflows, moderation_sidebar, moderation_dashboard\, scheduler, scheduler_content_moderation_integration, content_lock (+timeout), diff, workbench_email, node_revision_delete, views_cm_current_state, override_node_options\, entity_usage, paragraphs_report\, checklistapi\
Mediamedia, media_library, media_directories (+ui, editor), media_entity_browser\, entity_browser, entity_embed, embed, focal_point, crop, image_effects\, imagemagick, exif_orientation\, file_mdm, filefield_paths, media_entity_file_replace, media_file_delete, media_library_edit\, media_link_enhancements\, media_pexels, svg_image, webp, blazy, slick (+paragraphs), file_download_link, imce\, responsive_image, stage_file_proxy\*
WYSIWYGckeditor5, linkit, anchor_link, ckeditor_bs_grid, ckeditor_iframe\, ckeditor5_icons\, ckeditor5_paste_filter\*, token_filter, responsive_tables_filter, openai_ckeditor
SEOmetatag (+open_graph, twitter_cards, async_widget), schema_metatag (article, event, person, place), simple_sitemap, pathauto, token, rabbit_hole, easy_breadcrumb
Redirectsredirect, path_redirect_import\, views_url_alias\
Menusmenu_block, menu_item_extras, menu_link_attributes, fontawesome_menu_icons, group_content_menu
Searchsearch_api, search_api_solr, search_api_pantheon, search_api_autocomplete, facets, facets_pretty_paths, better_exposed_filters, selective_better_exposed_filters, select2
Formswebform (+ui, submission_log, export_import), captcha, recaptcha, honeypot
Layoutlayout_builder (+restrictions, modal, iframe_modal, styles, admin_theme), layout_paragraphs, bootstrap5 theme, views_bootstrap, fences, block_class, collapsiblock\*, inline_block_title_automatic
Accessibilityeditoria11y, extlink, accessible-slick library, dubbot\*
Performance and cachingredis, memcache\, pantheon_advanced_page_cache\, cache_control_override (portal only), minifyhtml, variationcache, blazy lazy-load
Securityseckit, password_policy, username_enumeration_prevention, userprotect, autologout\, shield\, flexible_permissions, permissions_by_term (portal), masquerade (portal), reroute_email, mail_login
Authenticationsamlauth\, simplesamlphp_auth\, cas\*, externalauth
Analytics and marketinggoogle_tag, google_analytics, addtoany, social_media_links, eu_cookie_compliance\*, smart_content (+block, browser) for personalization, gtranslate
AIai, ai_provider_anthropic, ai_provider_openai, gemini_provider (not enabled); openai (+chatgpt, ckeditor, content, prompt) enabled
Higher-ed and site featurescalendar, calendar_link, views_ical, date_recur (events); geolocation, geofield, geocoder (campus map); group, gnode, gcontent_moderation (department delegation); feeds\, migrate_plus, migrate_tools, migrate_source_csv (imports); taxonomy_manager, taxonomy_import, taxonomy_unique, tvi; entityqueue\; views_bulk_operations, views_bulk_edit\*
Admin and devadmin_toolbar, module_filter, environment_indicator\, config_ignore, config_log, config_partial_export, config_rewrite, config_filter, devel\, upgrade_status, responsive_preview, theme_switcher, twig_tweak, asset_injector, jsonapi_extras\*

Custom modules

ModuleWhat it does
kwall_starter_helperShips the full site config sets, Google-font catalog endpoints, and a Drush command that pulls brand colors, fonts and logo from KWALL's customer portal (Accorbis) on Pantheon.
kwall_academic_programsProgram content type, Degree Type and Interest Area vocabularies, program grid with AJAX program finder.
kwall_calendarMonth/week/day/year calendar views over recurring events, iCal feed, mini calendar, current-week and list/calendar toggle blocks.
kwall_directoryPerson content type, Department and Person Type vocabularies, filterable faculty and staff directory.
kwall_newsArticle form and image styles, Newsroom and related/featured article views, News Category and Article Type vocabularies.
kwall_alertsAlert content type with level, expiry and dismissability; alert block fed by a REST export with a dismissed-cookie.
kwall_header_bannerHeader Banner paragraph and block (image, color filter, style, hide-title) per page.
kwall_mapLocation content type with address and geolocation and a Google Maps campus map with custom overlay.
kwall_groupBlocks that render a Group's menu (department sub-navigation) for the site_section group type.
kwall_breadcrumbsThree breadcrumb builders (node, views, path).
kwall_share_barSocial share block.
kwall_componentsPreprocess and templates for document list, heading, CTA, news list and glossary paragraphs.
kwall_custom_adminAdmin theme CSS and JS tweaks, paragraph widget adjustments.
kwall_media_directories_extenderFolder-style media browser tweaks.
kwall_cityCity variant: Services content type and grid (depends on webform).
kwall_portalLogin-walled site: anonymous redirect to login, permissions_by_term integration.
kwall_samlDomain-aware SAML redirect and attribute mapping on top of simplesamlphp_auth.
curatorImports Curator.io social posts as Social Post nodes on cron.
custom_moduleSite glue: entity access, AJAX program-finder and calendar subscribers, year exposed-filter helper, token alters.

Content types and fields

TypeFields (short)Path pattern
Basic Pagebody, hero_content (header_banner), paragraphs (21 component types), below_content_paragraphs (full-width, 28 types), page_summary, thumbnail, hide_sidebar, meta_tags[menu parents]/[title]
Landing Pagebody, banner_content (header_banner, hero_slideshow, hero_video), paragraphs, below_content_paragraphs, page_summary, thumbnail, legacy_url, migration_status/notes, meta_tagssame
Homepagehero_slideshow (slideshow or video), below_content_paragraphs, meta_tagsfront
Layout Builderlayout_builder__layout, hero_slideshow, meta_tagssame
Articlebody (required), article_type, categories, featured, publish_date (required), thumbnail, paragraphs, sidebar components, redirect, legacy_url, migration fieldsarticle/[title]
Eventrecurring_dates (date_recur, required), body, event_type, topics, event_location (term) plus location name/address/geo/link, featured, featured_image, paragraphsevents/[title]
Personfirst/last name (required), title, department, person_type (required), email, phone, photo (person_image), biography, hero_contentdirectory/[title]
Programbanner image and thumbnail (required), description, page_summary, degree_type, academic_interest, related_programs, program components, sidebar components, hero_contentprograms/[title]
Locationaddress, geolocation, description, images, images block, more link, related links, link_from_map, section_titlecampus-map/[title]
Alertalert_body, alert_level (required), expiration_date, not_dismissablenone
Testimonialbody, image, person_info, link_to_page, link_to_other_pagetestimonials/[title]
Social Postcurator id/feed, network, body, date, image, url, author fieldsnone
Services (city only)description, phone, thumbnail, services_area, paragraphsservices/[title]

Paragraph (component) types: 58

Layout: layout (margins, padding, background color or media), from_library, drupal_block, view_reference, webform_reference. Hero and banners: header_banner, hero_slideshow and hero_slide, hero_video, banner_with_* (three), announcement_banner. Content: wysiwyg, heading, image, gallery, media_with_text, video_text, embedded_video, uploaded_video, accordion and accordion_item, tabs and tab_item, glossary, document_list and item, label_with_text, countdown. Calls to action: cta_block, buttons, buttons_cta, button_with_label, full_width_image_and_cta, featured_image_text_cta, icon_link, icon_links_grid, colored_icons_grid, sidebar_links_with_icons, menu_quick_links. Data-driven: news_list, featured_news, featured_events, featured_news_and_events, testimonials, person_spotlight, stat_row and stat_item, colored_stat_bar_item, card_item, card_with_image_item, contact_information, hours_of_operation and item, social_media_icons, footer_links_column, footer_contact_link.

Block content types: basic, component_block, paragraphs_block, header_banner, layout_block, links_with_heading, footer_block (site name, logo, address, phone, copyright, links, social links).

Taxonomies (15)

article_type, categories, tags, news_category, degree_type, interest_area (with icon), department, person_department, person_type, event_type, event_topic, event_location (links to a campus-map Location), document_category, glossary_section, media_directory (folders for the media browser). Hierarchy is Drupal-native; tvi lets a vocabulary pick its term-page view.

Roles, workflow, moderation

Roles: administrator, content_editor (create and edit all content types, draft and review transitions, schedule, view scheduled, editoria11y, media browsers), content_publisher (editor plus publish and archived_published transitions, homepage), group_member (media and toolbar only; real rights come from group roles), plus anonymous and authenticated. Editorial workflow: Draft, Needs review, Published, Archived, applied only to article, homepage and page bundles. Group type site_section (departments) with group roles group_administrator, group_publisher, group_editor, member, outsider; group content is page only, group menus via group_content_menu. Content lock on nodes with a 180-minute timeout; diff on revisions; workbench_email enabled with no templates in config; scheduler enabled for alert, article, event and page (publish and unpublish), with "view scheduled content" and three scheduled-content views.

Views (58)

Public: newsroom (keyword, category, publish year, 10 per page), directory (keyword, department), programs_grid (keyword, AJAX finder), calendar_main_page (day, week, month, year, list; keyword, date, type), calendar_calendar_view, mini_calendar, ical_events_feed, campus_map, documents (keyword, department, category), glossary, search (Solr full text with excerpt), archive, taxonomy_term, frontpage. Blocks and attachments: featured news and events, related articles/events/programs, news_lists, filtered listings for articles and events, alerts (block and REST export), social_grid, connect_with_us. Admin: content, moderated_content, moderated_group_content, scheduled content/media/terms, locked_content, redirect, media and media_library, paragraphs_library, config_log, editoria11y results, webform_submissions, group members and nodes, social_post_dashboard.

Menus, webforms, SEO, theme

Menus: main, mega-menu (menu links carry a Layout Builder layout), footer, header-action-navigation, utility-navigation left and right, plus account, admin, tools. Webforms: contact (two email handlers, captcha), email_signup, review_webform (fieldsets, flexbox, radios, checkboxes, datetime, terms of service). Metatag defaults for global, front, node (title, description from page summary, OG image from thumbnail), taxonomy term, user, 403 and 404; schema.org via schema_metatag for article, event, person, place; simple_sitemap per bundle with priorities; pathauto patterns per type; redirect with auto-redirect on alias change and query passthrough; rabbit_hole per type. Theme kwall_starter on bootstrap5: twelve regions (alerts, nav branding, nav main, nav additional, hero, breadcrumb, two sidebars, content, content bottom, footer, invisible), theme settings for eleven colors (three primary, secondary, three alert levels, four neutrals), three fonts from a Google-font catalog, logo; Webpack and SCSS build; 67 image styles and 6 responsive image sets on bootstrap5 breakpoints; Twig overrides for 27 paragraphs, menus, views, nodes.

Conventions from CLAUDE.md and README

Pantheon Integrated Composer; composer code-sniff and code-fix with Drupal and DrupalPractice standards; frontend assets built per module with Gulp or Webpack and committed; configuration shipped in module config/install and the helper's site-config sets rather than config/sync; Quicksilver scripts run drush site-install and notify a Firebase function on deploy_product; branding is pulled from the KWALL customer portal by site slug.

2. Comparison table

CapabilityStarterSpillway statusNote
Scheduled publish and unpublishscheduler + scheduler_content_moderation_integration, per-type, cron, "Scheduled content" viewsMissingNo publishAt/unpublishAt on Entity, no scheduler, no cron. Roadmap does not mention it.
Content moderation statescontent_moderation: draft, review, published, archived with per-role transitions; only 3 bundlesShipped v0.1/v0.2draft, review, published; submit, publish, unpublish, reject (v0.2). archived is defined but no endpoint sets it. Applies to every type.
Revision history and diffcore revisions + diff module (inline, split, unified)Shipped v0.1 (list, restore); diff MissingRevisions are full snapshots; no comparison view.
Revision pruningnode_revision_delete per typeMissingRevisions grow unbounded.
Redirectsredirect module, auto-redirect on alias change, query passthrough, admin view, CSV importShipped v0.2301/302, enabled flag, hit counter, auto-redirect on slug change, query passthrough, 404 log with counts. No bulk import, no wildcard.
404 handlingmetatag 404 defaults, fast_404Shipped v0.2Rendered 404 page in site shell, path_miss table. No custom 404 page content.
Menu managementcore menus (9), menu_block, menu_item_extras, mega-menu with Layout Builder, group menusIn progress (2b), nothing in codeNo menu table, API or admin; blocks take raw hrefs.
Taxonomy15 vocabularies, hierarchy, term pages via tvi, taxonomy_managerMissingOnly select options and reference fields. No vocabulary entity, no hierarchy, no term pages.
Media librarymedia types (8), media_directories folders, entity browsers, Pexels, file replace, usageShipped v0.1 (basic)Flat library, upload, alt, title, search, MIME sniffing, 25 MB cap. No folders, no media types, no replace, no usage.
Image styles, responsive, focal point67 image styles, responsive_image, focal_point, crop, imagemagick, webpMissingFiles are served as uploaded; Image block sets loading="lazy" only.
WYSIWYGCKEditor 5: headings, styles, alignment, tables, Bootstrap grid, anchors, linkit to nodes and files, media embed, video embed, OpenAIShipped v0.1 (Tiptap richtext)Internal link picker, media embed, tables and embeds in rich text are not present; Text block has an HTML mode.
Components vs blocks58 paragraph types, layout_paragraphs, paragraphs library, Layout BuilderShipped v0.1 (13 Puck blocks)Hero, Heading, Text, Image, Columns, CallToAction, Cards, Spacer, Divider, Embed, Button, Form, Collection. No reusable (library) blocks, no accordion, tabs, gallery, stats, video, person spotlight, news list.
Listings with exposed filtersViews with BEF, selective filters, pagers, AJAXShipped v0.2 (partial)Collections: admin-defined filters, sort, limit, paginated items API, Collection block. No visitor-facing filters or keyword search on a listing.
Site search with facetssearch_api_solr on Pantheon, facets (5 sources), autocompleteShipped v0.2 (basic)SQLite FTS5 over title and text fields, /search page, type filter. No facets, no autocomplete; Meilisearch planned (Phase 3).
Webformswebform: 40+ element types, wizard pages, conditional logic, file uploads, email handlers, submission views, CSV export, captcha, honeypotShipped (Phase 4)9 field types, required, conditional logic (visibleWhen, server and browser), multi-step forms with server-side step validation, file uploads (private store, type from bytes, download for submission viewers), Turnstile or hCaptcha by site setting, submissions list, CSV, redeliver, webhook/HubSpot/email connectors, honeypot, timing, rate limit, UTM capture. Salesforce, Slate, Mailchimp still planned.
Meta tags per pagemetatag field on page types, defaults per bundle, OG and TwitterShipped v0.1/v0.2 (partial)seoTitle, seoDescription on Page; site-level suffix, description, OG image, robots. No per-entity OG image or Twitter card fields on other types.
Schema.orgschema_metatag (article, event, person, place)Shipped v0.2 (partial)WebSite, Organization, WebPage, Article, BreadcrumbList generated automatically. No Event, Person, Place, Course.
XML sitemapsimple_sitemap with per-bundle priority, cron generationShipped v0.2/sitemap.xml, lastmod; no priority, no exclusion per type. Also /robots.txt and /llms.txt.
Google Tag Manager and GAgoogle_tag, google_analytics with path and role exclusionsMissingNothing in the shell; "personalization and analytics" is in progress for 2b but no code.
Accessibility toolingeditoria11y (in-page checker and reports), extlink, accessible-slickShipped v0.2 (partial)Pre-publish checks: alt text, heading order, one H1, SEO length, banned words, dead internal links; publish blocked on errors. No site-wide report or in-page checker.
Alerts and emergency bannerkwall_alerts type, level, expiry, dismissable, REST feed, blockMissingNo site-wide region, no expiry.
Events with recurrence and calendardate_recur with modular widget, calendar views, iCal feed, Add-to-calendar linksMissingdate field only; no ranges, recurrence, calendar or iCal.
People and faculty directoryPerson type, department and type vocabularies, filterable directory viewMissing (kit possible)A person type can be modeled; no directory listing with filters.
Programs and degreesProgram type, degree and interest vocabularies, AJAX program finderMissing (kit possible)Same: fields can be modeled; finder needs filters and taxonomy.
Course catalogNot in the starter (programs only)MissingNeither product has one.
News and pressArticle type, categories, newsroom with filters, featured and related views, press release article_typeShipped v0.1 (Post type), listing partialPost has summary, body, hero, date. Collections give latest and filtered lists; no related-content or category filters for visitors.
Global header and footerTheme regions, footer_block content block, branding block, utility menus, share bar, social linksMissingThe shell renders site name and theme CSS only; no header or footer configuration.
Multi-site and department delegationgroup + gnode + gcontent_moderation: site sections with their own roles, menu, moderated contentPlanned (Phase 3 multisite); delegation MissingSpillway roles are global; no ownership scope smaller than the site.
Rolescontent_editor, content_publisher, group roles, administrator; 50+ granular permissionsShipped v0.1viewer, author, editor, manager, admin with 16 permissions. Authors edit own only. No per-type permissions.
Workflow notificationsworkbench_email (enabled, no templates), user mailMissingReview queue exists; no email or in-app notification on submit, reject or publish.
Content lockingcontent_lock on all node types, 180-minute timeout, break-lockMissingConcurrent saves last-write-wins.
URL aliases and patternspathauto patterns per type including menu-parent paths; bulk regenerateShipped v0.1pathPattern per type with slug, id, type, yyyy, mm tokens; no menu-parent token, no bulk regenerate.
Translation and multilinguallanguage module enabled (en only), gtranslate widget, content_translation settings presentPlanned (Phase 3)locale column and locales setting exist; one locale rendered. AI translate task exists.
CachingPantheon AGCDN, redis, page cache 24h, cache tags via pantheon_advanced_page_cacheShipped v0.1In-process LRU with tag invalidation, Cache-Tag and s-maxage headers for a CDN; no purge call; Redis planned.
Environment configurationpantheon.yml, settings.php per environment, config_ignore, config_log, environment_indicator, reroute_emailShipped v0.1 (partial)Env vars for port, data dir, DB path, secret, base URL, log level. No environment indicator or mail reroute.
BackupsPantheon automated backups and multidevShipped v0.1 (documented)SQLite online backup plus the media folder; spillway export and import CLI.
Config as codeDrupal config export, module config/install, site-config setsMissingTypes, collections and forms are only in the database; no export or import of structure separate from content.
Clone contentquick_node_clone, replicate, entity_cloneMissingNo duplicate action.
Bulk operationsviews_bulk_operations, bulk edit, pathauto bulkMissingLists have no multi-select actions.
Audit and config logconfig_log, dblog, webform_submission_logShipped v0.1 (table only)audit_log written on every write; no UI or API.
SSOsamlauth, simplesamlphp_auth, cas (required, not enabled), kwall_saml, externalauthIn progress (2b): jose and node-saml deps onlyRoadmap Phase 2: OIDC, SAML, SCIM.
API for integrationsJSON:API, REST (alerts), jsonapi_extrasIn progress (2b): API token contract and tableFull JSON API shipped with cookie auth; bearer tokens and MCP are contract-only.
AI assistanceopenai (CKEditor, content, prompt), ai module with Anthropic, OpenAI, Gemini providersShipped v0.2Brand profile, page from brief, assist, type from description, alt text, usage report; multi-provider.
Personalizationsmart_content with browser segmentsMissing (2b in name only)Roadmap Phase 3.
Spam protectioncaptcha, recaptcha, honeypotShipped (Phase 4)Honeypot, timing and rate limit on form submit; Cloudflare Turnstile or hCaptcha verified server-side (Site settings → Forms); reCAPTCHA is not offered.
Campus mapkwall_map with geolocation and overlayMissingNot in the spec.
Social feed importcuratorMissingNot in the spec.
Glossary, documents library, hours of operation, countdown, testimonials, share barParagraphs and viewsMissingNot in the spec; see gap list.

3. Ranked gap list

Critical

  1. Scheduled publish and unpublish. The starter enables scheduler on pages, articles, events and alerts, with a "Scheduled content" view and moderation integration, and a campus communications team relies on it for embargoed news, term-start pages and alert expiry. Spillway has no date on the entity and no clock. Implement in core, Phase 2b: add publishAt and unpublishAt columns to entity, a content.schedule permission (editor and up), POST /api/entities/:id/schedule and unschedule, and a lightweight in-process ticker (every 60 seconds, plus a spillway run-scheduled CLI for cron on multi-instance setups) that publishes through publishEntity so checks, cache tags and audit all apply. Show a "Scheduled" filter in the content list and a banner on the entity. Unpublish-at should move the entity to archived, which also gives that status its first endpoint.
  1. Menu management. Every site in the starter has a main menu, a mega menu, two utility menus, a footer menu and department sub-menus; pages pick their menu parent on the edit form and pathauto derives the path from it. Spillway has no menu at all and the shell has no navigation. Implement in core, Phase 2b (already listed as in progress): a menu and menu_item table (label, link to entity or URL, parent, weight, new tab, optional description and icon), GET/PUT /api/menus/:key, a drag-and-drop tree editor, a "Menu placement" rail on the entity editor, a {menu} path token, and a Navigation block plus header and footer slots in the shell that render named menus.
  1. Global header and footer. The starter configures branding, utility navigation, search, social links, address and copyright through theme regions and a footer block. Spillway renders a bare shell. Implement in core alongside menus: a per-site "layout" document with header and footer zones edited in Puck (logo from media, menus, search toggle, social links, address, copyright) and rendered around every page; cache-tag it site:<id> so one save invalidates the whole site.
  1. Taxonomy. Fifteen vocabularies drive every listing filter (department, category, degree type, event type) and several term pages. Spillway's select options are flat strings owned by one type. Implement in core, Phase 2b or early 3: a vocabulary and term model (hierarchy via parent, slug, description, optional path pattern for term pages), a taxonomy field type that references a vocabulary (single or multiple), term pages rendered as a Collection filtered by term, and term filters exposed to Collections and search.
  1. Image styles and responsive images. The starter has 67 styles, focal-point cropping and WebP. Spillway serves originals, so a 4 MB hero is sent to a phone. Implement in core, Phase 2b: on-demand resizing with sharp behind /media/:id/:filename?w=&h=&fit=&format=, a focal point stored on MediaItem, named presets in site settings, srcset and sizes emitted by the Image, Hero and Cards blocks, and cached derivatives under DATA_DIR/media/derived.

High

  1. Visitor-facing listing filters and pagination. The newsroom, directory, calendar and program finder all have keyword plus taxonomy and date filters with pagination. Spillway Collections are fixed queries. Extend the Collection block (core, Phase 2b): filters: 'none' | 'inline', an exposed list of fields (keyword over searchable fields, taxonomy, date range, select), server-rendered filter form with query-string state, page size and pager, and an items.json endpoint for progressive enhancement. This unlocks the directory, newsroom and program finder as kits rather than code.
  1. Events with recurrence and calendar. Events are the highest-traffic listing on most campus sites. Implement as a module and kit, Phase 3 once modules exist (or as core field types sooner): a daterange field type with timezone, an recurrence field (RRULE, exclusions, occurrence expansion stored in a side table so Collections can sort by next occurrence), an event type in a higher-ed kit, a Calendar block (month, week, list), an /events.ics feed and per-event add-to-calendar links.
  1. Higher-ed content kit (people, programs, news, alerts). The starter ships Person, Program, Article, Event, Alert, Location and Testimonial with their vocabularies, listings and components. Spillway should ship an installable "Higher education" kit (Phase 2b, after taxonomy): content types, vocabularies with seed terms, collections and block presets, plus sample pages. Alerts need a small core hook: a site-level alerts setting rendered above the header with level, expiry and a dismissed cookie.
  1. Rich text internal links and media embed. Editors link to pages by searching for them (linkit) and embed images, documents and videos inline. Implement in core, Phase 2b: a link dialog in the Tiptap editor that searches entities and media (storing entity:<id> so links survive slug changes, resolved at render), image and document embeds that reference media ids, and tables. Keep the HTML sanitized with an allow-list rather than the current trust-the-editor policy.
  1. Reusable component library. paragraphs_library and from_library let one promo or contact card be placed on many pages and edited once. Implement in core, Phase 2b: a shared_block entity (a saved Puck component tree with a label), a "Save to library" action on any block, a Shared block that references it and is resolved at render, tagged shared:<id> for invalidation.
  1. Department delegation. The site_section group type gives a department its own editors, publishers, pages and menu while the central team keeps the shell. Spillway roles are site-wide. Implement in core, Phase 3 alongside multisite: a section entity (name, path prefix, menu), sectionId on entities, and section-scoped role assignments (editor of section X). Permissions checks already go through requireEditAccess, which is the seam.
  1. Workflow notifications. workbench_email is enabled for submit, approve and reject emails. Implement in core, Phase 2b: an outbox table plus the existing SMTP connector; events entity.submitted, entity.rejected, entity.published, comment.added with templates in site settings; a per-user digest preference; and the same events on a webhook for Slack or Teams.

Medium

  1. Content locking. Two editors on one landing page is common on a marketing team. Implement in core, Phase 2b: entity_lock (entity, user, expires) acquired on open, refreshed by heartbeat, released on close, breakable by content.edit_any, with a 409 on save when another user holds it.
  1. Revision diff and pruning. Add a side-by-side comparison of two revisions (field by field, block by block for layouts) in the admin and GET /api/entities/:id/revisions/:a/diff/:b; add a per-type "keep N revisions" setting and a prune job. Core, Phase 2b.
  1. Webform parity: conditions, multi-step, file uploads, captcha. Done in Phase 4: visibleWhen on fields, steps, a file field type stored under DATA_DIR/form-uploads, Turnstile or hCaptcha by site setting (docs/api.md "Forms"). Salesforce, Slate and Mailchimp connectors stay on the roadmap.
  1. Google Tag Manager and analytics settings. A tracking section in site settings (GTM container id, GA4 id, consent mode, path exclusions), emitted by the shell, with a dataLayer event on form submit. Core, Phase 2b; small.
  1. Per-entity SEO fields on every type and richer schema.org. Promote seoTitle, seoDescription, ogImage, noindex and canonical to built-in fields on any type with a path (hidden behind an "SEO" tab), and generate Event, Person and Course JSON-LD from the kit's types. Core, Phase 2b.
  1. Search facets and autocomplete. Add type and taxonomy facets with counts to /search and /api/search, and a suggest endpoint; this stays on FTS5 until Meilisearch (Phase 3).
  1. Config as code. The starter's whole structure is YAML that ships with the upstream, which is how one team runs dozens of sites. Add spillway export --structure and import --structure for types, vocabularies, collections, forms, menus and theme, with a kit manifest format; this is also what the fleet API will push. Core, Phase 3 with fleet.
  1. Clone and bulk actions. Duplicate entity, and multi-select publish, unpublish, archive, delete and change-author on the content list. Core, Phase 2b; small.

Low

  1. Media folders, media types and replace-in-place. Folders (or tags) in the media library, a document type with a download block, replacing a file while keeping its id, and "where is this used" from the existing reference table.
  2. Campus map and locations. A location type with address and coordinates and a Map block; a kit item once a map provider setting exists.
  3. Glossary, documents library, hours of operation, countdown, stats, testimonials, share bar, social feed. Blocks for the higher-ed kit; the social feed importer is a module candidate.
  4. Environment indicator and mail reroute. An ENVIRONMENT variable shown in the admin header and a MAIL_REROUTE_TO that catches all outbound mail outside production.
  5. Translation widget. gtranslate-style machine translation is a stopgap; proper localization is Phase 3 and already has the locale column and AI translate task.

Items the starter has that the Spillway spec never mentions: scheduling, taxonomy, menus, image styles and focal point, alerts, events and calendar, content locking, revision diff and pruning, department delegation via groups, GTM, campus map, glossary, documents library, social feed import, config as code, clone and bulk actions, environment indicator, mail reroute, captcha.

4. Already better in Spillway

  • Review workflow in one piece. Draft, review, publish, reject with a note, a review queue, field-level comments and pre-publish checks that block publishing on errors are core, where the starter needs content_moderation, workflows, moderation_sidebar, moderation_dashboard, workbench_email and editoria11y and still has no comments.
  • Redirects with a 404 log. The starter needs redirect plus a custom view and path_redirect_import; Spillway logs top misses next to the redirect screen and creates redirects on slug changes automatically.
  • Forms with CRM delivery and UTM capture. Webhook with HMAC signature, HubSpot, email, redelivery, CSV, UTM and referrer capture, honeypot and rate limiting are built in; the starter needs webform, webform_submission_log, captcha, honeypot and a third-party HubSpot bridge.
  • Collections for marketers. A saved query with a preview and a block, instead of Views UI, viewsreference and the news_list paragraph's hand-built curation fields.
  • SEO files and structured data. sitemap.xml, robots.txt, llms.txt and JSON-LD (WebSite, Organization, WebPage, Article, BreadcrumbList) without metatag, schema_metatag, simple_sitemap or easy_breadcrumb.
  • AI with governance. Brand profile with banned words, page from brief, assist, alt text, type design, per-task provider routing across Anthropic, OpenAI, Google and xAI, a token cap, a usage report and an audit row per call; the AI never publishes. The starter has openai_* and the ai module with no brand layer or cap.
  • Audit log on every write in the same transaction, versus config_log for configuration and dblog for events.
  • Cache tags on every page from one process, with no Pantheon-specific module, and headers a CDN can purge by.
  • Security defaults without seckit, password_policy or username_enumeration_prevention: scrypt, HMAC-stored sessions, CSRF header, login rate limit with constant-time email handling, MIME sniffing and sandboxed SVG.
  • One process, one file. Install in five minutes with Docker and SQLite, backups as a file copy, versus Composer, Solr, Redis, MariaDB and a Pantheon workflow.
  • Same JSON API for everything the admin does, with the API tokens and MCP contract on this branch extending it to agents, where the starter adds jsonapi_extras and a bespoke REST export for alerts.

Spillway 0.1.0 · Edit this page on GitHub

Was this page helpful?