Product Requirements Document (PRD)
Name
Changelogify for Drupal
Summary
Changelogify automatically collects site changes from Drupal, lets admins group them into releases, and publishes a public changelog page. An optional AI submodule can turn raw events into human readable release notes.
Core idea
- Capture events from Drupal (content changes, configuration changes, user and module events) into a normalized event log.
- Provide an admin UI to generate and edit "releases" from these events.
- Publish releases on a public changelog list and detail page.
- Optional AI submodule to summarize and rewrite raw events into polished notes.
- Simple, opinionated way to maintain a public changelog for a Drupal site.
- Reduce manual effort when preparing "what changed" updates.
- Help agencies and teams produce recurring release notes for clients or stakeholders.
- Work on a standard Drupal 10+ site within a ddev environment.
- Respect privacy and work in environments that cannot use external SaaS.
- Not a full compliance or security audit trail.
- Not a deployment orchestration or CI tool.
- Not an analytics or error monitoring suite.
- No cross site multitenant management dashboard (beyond normal Drupal multisite support).
-
Agency developer / site builder
Maintains many client sites and sends monthly maintenance or feature update reports. -
Product owner or marketing manager
Runs a SaaS or product site built on Drupal and wants a public "What is new" page. -
Internal web team
Needs to show stakeholders what changed over time without exposing Git logs or raw system logs.
- Generate a new release entry for "October 2025 updates" that covers content tweaks, new features, and bug fixes.
- Pull all events since the last release and turn them into a draft release.
- Publish a public changelog page at
/changelogwith a list of releases. - Use the AI submodule to draft human readable text from raw events, then refine it.
- Custom content entity for Releases with sectioned items:
- Added
- Changed
- Fixed
- Removed
- Security
- Other
- Internal event log with pluggable event source adapters.
- Admin UI:
- Generate release from events in a date range or since last release.
- Edit and manage releases (draft and publish).
- Public routes:
- Release listing page.
- Single release detail page.
- Permissions for managing releases and configuration.
- Optional AI submodule:
- Summarizes groups of events per section into bullets.
- Optionally rewrites release text for clarity and tone.
- Rich browsing UI for all raw events outside release flow.
- Git integration or deployment log integration.
- Email or Slack notifications.
- Centralized dashboard that manages multiple Drupal instances from one control plane.
-
changelogify
Core module with:- Event entity and adapters.
- Release entity.
- Admin UI and public routes.
-
changelogify_ai(optional submodule)
Adds AI powered features:- Event grouping and summarization.
- Text improvement helpers.
- Hooks and plugins capture events when content, config, and system elements change.
- Events are stored as
changelogify_evententities (or a dedicated table) with structured metadata. - Admin opens the Changelogify UI and chooses a time range.
- The system pulls events in that range and groups them into sections.
- Optional AI processing converts raw events into readable summaries.
- Admin reviews, edits, and saves a Release.
- Releases are published on public pages.
- Namespace:
Drupal\changelogifyandDrupal\changelogify_ai. - Use Drupal 10 coding standards.
- Provide standard services:
- Event manager service for collecting and querying events.
- Release generator service for building draft releases from events.
- AI client service (in
changelogify_ai) abstracted behind an interface.
Create a content entity changelogify_release with storage in SQL.
Fields
id(int, auto generated)uuid(UUID)title(string)- Short label, for example "October 2025 Release" or "v1.2.0".
label_type(list string)- Values:
date_range,custom,semantic_version.
- Values:
version(string, optional)- For semantic versioning, example "1.2.0".
date(timestamp)- Release date, default to now.
date_start(timestamp, optional)- Start of the change window this release covers.
date_end(timestamp, optional)- End of the change window.
sections(JSON or multi value field)- Suggested structure:
{ "added": [ { "id": "uuid-or-random-id", "text": "Added new booking form for tours.", "event_ids": [1, 5, 6] } ], "changed": [], "fixed": [], "removed": [], "security": [], "other": [] }
- Suggested structure:
status(boolean or enum)- Values:
draft,published.
- Values:
created(timestamp)changed(timestamp)uid(entity reference to user, author)
Admin actions
- List releases (filter by status, search by title or version).
- Add, edit, delete release entities.
- Publish or unpublish (draft) releases.
Create an internal entity or storage layer changelogify_event.
You can use a content entity or a lightweight custom table with a small CRUD wrapper. Entity is preferred for Drupal integration.
Fields
id(int)uuid(UUID)timestamp(timestamp)event_type(string)
Examples:content_createdcontent_updatedcontent_deletedconfig_changedmodule_installedmodule_uninstalleduser_createduser_role_changed
source(string)
Example:content_entity,config,user,system.entity_type(string, optional)
Example:node,user,taxonomy_term.entity_id(int, optional)bundle(string, optional) Example:article,page.user_id(int, optional)- Who triggered the event, if known.
message(string)- Short, technical description or log message.
metadata(JSON)- Arbitrary extra data, such as:
- Title
- Path
- Old and new values
- Arbitrary extra data, such as:
section_hint(string, optional)- Suggested mapping to release section:
added,changed,fixed,removed,security,other.
- Suggested mapping to release section:
Behavior
- Events are created as changes occur via hooks.
- Events can be queried by time range and type.
- Events are never exposed directly in public routes.
Define a plugin type: ChangelogifyEventSource.
Plugin interface example
interface ChangelogifyEventSourceInterface {
public function id(): string;
public function label(): string;
public function collectEvents(\DateTimeInterface $start, \DateTimeInterface $end): array;
}For v1, we will primarily log events in real time via hooks, but this plugin type leaves room for future backfill or alternate sources.
-
Content entity adapter (nodes only at first)
- Use
hook_entity_insert,hook_entity_update,hook_entity_deletefornodeentity type. - On insert:
- Create
changelogify_eventwith:event_type = content_createdsource = content_entityentity_type = nodebundle =node typemessageexample:Created Article: "Title".section_hint = added
- Create
- On update:
event_type = content_updatedsection_hint = changed
- On delete:
event_type = content_deletedsection_hint = removed
- Use
-
Module install and uninstall adapter
- Use
hook_module_installedandhook_module_uninstalled. - On install:
event_type = module_installedsource = systemmessageexample:Installed module: module_name.section_hint = addedorother
- On uninstall:
event_type = module_uninstalledsection_hint = removed
- Use
-
User events adapter (simple v1)
- Use
hook_user_insert:- Log
user_created,section_hint = added
- Log
- Use
hook_user_update:- When roles change, log
user_role_changed,section_hint = changed
- When roles change, log
- Use
The adapter system should be easy to extend by other modules that want to register custom events.
Admin creates a new release by choosing:
- Mode
- "Since last release"
- "Custom date range"
-
Determine the time window:
- "Since last release":
- Use the last published release
date_endif present, otherwisedate. start =that timestamp,end = now.
- Use the last published release
- "Custom date range":
- Admin picks start and end date.
- "Since last release":
-
Query events:
- Fetch
changelogify_eventrecords withtimestampin the window.
- Fetch
-
Group events:
- Group by
section_hintinto sections. - Optionally group further by entity type and bundle.
- Group by
-
Populate draft release:
- Create a new
changelogify_releaseentity in Draft status. - Fill
date_startanddate_end. - For each section:
- Create items with:
- A default text such as:
- "Updated Article: Title"
- "Installed module: module_name"
- Store referenced
event_ids.
- A default text such as:
- Create items with:
- Create a new
-
Present draft to admin in UI:
- Editable text per section and item.
- Option to delete or merge items.
- Option to reassign items to a different section.
/admin/config/development/changelogify- Dashboard:
- Button "Generate new release".
- Simple stats:
- Total events in the last N days.
- Number of events since last release.
- Short list of recent releases.
- Dashboard:
/admin/content/changelogify/releases- Table of releases:
- Title, version, date, status, operations.
- Table of releases:
-
Generate Release Form
- Fields:
- Mode:
- Radio: "Since last release" or "Custom date range"
- Start date (if custom)
- End date (if custom)
- Optional freeform version label input
- Mode:
- On submit:
- Use Release generator service to create draft release.
- Redirect to Release edit form.
- Fields:
-
Release Edit Form
- Fields:
- Title
- Version and label type
- Date,
date_start,date_end - Sections:
- Each section displayed in a collapsible fieldset:
- List of items with:
- Text area for bullet text.
- Hidden
event_ids.
- Controls for:
- Add item.
- Delete item.
- Move item up or down.
- Move item to different section.
- List of items with:
- Each section displayed in a collapsible fieldset:
- Status field:
- Draft or Published.
- Actions:
- Save draft.
- Save and publish.
- Fields:
-
/changelog- Public listing of published releases.
- Show:
- Title or version.
- Date.
- Short excerpt (first 1 or 2 bullets or a summary, if available).
- Paged list.
-
/changelog/{changelogify_release}- Public detail page.
- Show:
- Title, date.
- Optional version label.
- Sections rendered with headings:
- Added, Changed, Fixed, Removed, Security, Other.
- Each item rendered as bullet text.
- Use a controller or entity view builder.
- Provide a default View mode for releases that site builders can theme.
- Add a block "Latest Releases" that can be placed in sidebars.
- Requires either:
- A generic "AI" contributed module, or
- A simple configuration for an HTTP based LLM API.
To stay flexible, wrap the HTTP call in a service that can be swapped.
-
Generate section summaries from raw events
- Button on the Release edit form:
- "Generate from events with AI"
- Behavior:
- For each section:
- Collect metadata of events in that section.
- Build a prompt that asks for grouped, human readable bullets.
- Call AI service.
- Replace or append to the section text items with AI generated content.
- Do not overwrite existing admin content without confirmation.
- For each section:
- Button on the Release edit form:
-
Improve wording
- For each section, add a "Rewrite with AI" mini action:
- Sends existing text to AI with a prompt like:
- "Rewrite these release notes to be clear and concise for non technical stakeholders."
- Sends existing text to AI with a prompt like:
- For each section, add a "Rewrite with AI" mini action:
-
Configuration
- Settings form at
/admin/config/development/changelogify/ai:- API key field.
- Model name or endpoint field.
- Toggles for:
- Allow AI generation.
- Allow AI rewriting.
- Settings form at
- All AI interactions should be done via a service:
changelogify_ai.clientwith a method like:generateSummary(array $eventsBySection, array $options = []): array
- Handle errors gracefully:
- Show admin a message when AI fails and keep any existing text unchanged.
Define permissions in changelogify.permissions.yml.
Suggested permissions:
administer changelogify- Access configuration and dashboard.
manage changelogify releases- Create, edit, delete releases.
- Publish or unpublish releases.
view changelogify releases- Required to view public changelog routes.
- By default granted to anonymous and authenticated users.
- For AI module:
use changelogify ai- Controls ability to trigger AI features.
Settings form at /admin/config/development/changelogify/settings:
- Default path for listing:
/changelog(allow override). - Default sections to use (checkbox list, with add or remove support).
- Toggle event sources:
- Track content changes.
- Track module events.
- Track user events.
- Event retention:
- Keep events for X days (integer).
- Cron job to purge old events.
ChangelogifyEventSource- Other modules can provide additional event sources.
hook_changelogify_event_alter(&$event)- Allow other modules to modify event data before it is saved.
hook_changelogify_release_sections_alter(array &$sections, ChangelogifyReleaseInterface $release)- Allow modules to adjust section content before display.
changelogify.event_manager- Methods:
logEvent(array $data): ChangelogifyEventInterfacegetEventsByRange(\DateTimeInterface $start, \DateTimeInterface $end, array $filters = []): array
- Methods:
changelogify.release_generator- Methods:
generateReleaseFromRange(\DateTimeInterface $start, \DateTimeInterface $end, array $options = []): ChangelogifyReleaseInterface
- Methods: