From 8df9622f1be7c1adf6788c93406741de913eb081 Mon Sep 17 00:00:00 2001 From: Twyco Date: Mon, 20 Apr 2026 21:03:02 +0200 Subject: [PATCH] Add v0.5 webhook notification release tickets --- docs/releases/README.md | 2 + docs/releases/ticket-implementation-guide.md | 48 +++++++++++++ .../01-notification-action-foundation.md | 62 ++++++++++++++++ .../02-project-notification-settings-ui.md | 69 ++++++++++++++++++ .../03-ticket-status-changed-trigger.md | 67 ++++++++++++++++++ .../04-generic-webhook-delivery.md | 70 +++++++++++++++++++ .../05-discord-webhook-delivery.md | 69 ++++++++++++++++++ ...otification-tests-and-release-hardening.md | 62 ++++++++++++++++ .../v0.5-webhook-notification/README.md | 35 ++++++++++ 9 files changed, 484 insertions(+) create mode 100644 docs/releases/ticket-implementation-guide.md create mode 100644 docs/releases/v0.5-webhook-notification/01-notification-action-foundation.md create mode 100644 docs/releases/v0.5-webhook-notification/02-project-notification-settings-ui.md create mode 100644 docs/releases/v0.5-webhook-notification/03-ticket-status-changed-trigger.md create mode 100644 docs/releases/v0.5-webhook-notification/04-generic-webhook-delivery.md create mode 100644 docs/releases/v0.5-webhook-notification/05-discord-webhook-delivery.md create mode 100644 docs/releases/v0.5-webhook-notification/06-notification-tests-and-release-hardening.md create mode 100644 docs/releases/v0.5-webhook-notification/README.md diff --git a/docs/releases/README.md b/docs/releases/README.md index 55af36d..83d767f 100644 --- a/docs/releases/README.md +++ b/docs/releases/README.md @@ -7,10 +7,12 @@ This directory contains small, ordered implementation tickets grouped by release - [Release 0.1 - Kanban, Ticketing, Users, and Permissions Foundation](0.1-kanban-foundation/01-admin-and-user-management-foundation.md) - [Release 0.2 - Gitea Integration](0.2-gitea-integration/01-git-provider-abstraction-and-gitea-foundation.md) - [Release 0.3 - GitHub Integration](0.3-github-integration/README.md) +- [Release v0.5 - Webhook Notifications](v0.5-webhook-notification/README.md) ## Scope notes - Release `0.1` covers the core Kanban, ticket, user, team, and permission foundation. - Release `0.2` covers the first Git provider integration with Gitea. - Release `0.3` covers GitHub Cloud as the second Git provider using the existing provider abstraction and user connection model. +- Release `v0.5` covers project-scoped webhook notification actions for ticket status changes. - Roadmap and other currently out-of-scope items are intentionally not broken into tickets here. diff --git a/docs/releases/ticket-implementation-guide.md b/docs/releases/ticket-implementation-guide.md new file mode 100644 index 0000000..8682ccf --- /dev/null +++ b/docs/releases/ticket-implementation-guide.md @@ -0,0 +1,48 @@ +# Ticket Implementation Guide + +This guide describes how to implement release tickets in this repository. + +## Branching + +- Use exactly one branch per ticket. +- Use the branch format `codex//`. +- For release `v0.5-webhook-notification`, branch names must look like `codex/v0.5-webhook-notification/01-notification-action-foundation`. +- The first ticket branch starts from the release base branch chosen by the maintainer. +- Every later ticket branch starts from the previous ticket branch: + - ticket 02 branches from ticket 01 + - ticket 03 branches from ticket 02 + - ticket 04 branches from ticket 03 + - continue this pattern until the release is complete +- Do not mix multiple release tickets in one branch. + +## Implementation Flow + +- Read the ticket completely before changing files. +- Keep the implementation limited to the ticket scope. +- Preserve existing UI, API, and MCP behavior unless the ticket explicitly changes it. +- Follow existing project conventions before introducing new patterns. +- Use actions or services for reusable business logic. +- Use FormRequest classes for request validation. +- Keep app-specific frontend types under `resources/js/types`; do not define them inside `.vue` files. +- Generate Wayfinder output when frontend-facing routes or controllers change. + +## Finishing A Ticket + +Each ticket must end with: + +- Relevant automated tests for the changed behavior. +- Formatting and code generation required by the files changed. +- `git diff --check`. +- `git add` for only the ticket's intended files. +- One commit with a concise ticket-specific message. +- `git push origin `. + +Do not leave partially staged work for the next ticket. The next ticket should start from the pushed branch of the completed ticket. + +## Verification Defaults + +- PHP changes: run `vendor/bin/pint --dirty --format agent`. +- Laravel behavior changes: run targeted `php artisan test --compact ...`. +- Route or frontend controller changes: run `php artisan wayfinder:generate --with-form --no-interaction`. +- Vue or TypeScript changes: run `npm run types:check`. +- Documentation-only changes: `git diff --check` is enough unless the ticket says otherwise. diff --git a/docs/releases/v0.5-webhook-notification/01-notification-action-foundation.md b/docs/releases/v0.5-webhook-notification/01-notification-action-foundation.md new file mode 100644 index 0000000..7fe2a0b --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/01-notification-action-foundation.md @@ -0,0 +1,62 @@ +# 01 Notification Action Foundation + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/01-notification-action-foundation` + +Start this branch from the chosen release base branch. + +## Goal + +Create the backend foundation for project-scoped notification actions and delivery logs. + +## Requirements + +- Add database tables for configured notification actions and delivery attempts. +- Add models, factories, resources, enums, and reusable actions or services for notification action management. +- A notification action belongs to a project. +- A notification action has a name, enabled flag, event type, channel, channel configuration, optional message template, and secret delivery URL. +- Supported event type for this release: `ticket_status_changed`. +- Supported channels for this release: `webhook` and `discord`. +- Store webhook and Discord URLs encrypted and hide them from serialized model/resource output. +- Add delivery logs that can record action, event type, channel, delivery status, attempt count, HTTP status, response or error excerpt, payload metadata, and timestamps. +- Keep the schema extensible for later event types and channels. + +## Acceptance Criteria + +- Notification action records can be created, updated, listed, and deleted through backend actions or services. +- Secret URLs are encrypted at rest and are not exposed by resources. +- Delivery log records can represent pending, succeeded, failed, and retryable attempts. +- The foundation does not dispatch external HTTP requests yet. +- Existing ticket, project, API, and MCP behavior is unchanged. + +## Tests + +- Model tests for relationships, casts, enum handling, and hidden secret URL output. +- Factory tests or feature-backed assertions proving webhook and Discord action records can be created. +- Action/service tests for create, update, delete, and project ownership behavior. +- Delivery log tests for supported statuses and relationship integrity. + +## Verification + +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Models tests/Feature/Notifications` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/01-notification-action-foundation`. + +## Out of Scope + +- Project settings UI +- Ticket status changed event dispatch +- Actual webhook or Discord HTTP delivery +- User bell notifications +- Unread counters +- Slack, Teams, email, or other channels +- Incoming webhooks +- API or MCP management endpoints diff --git a/docs/releases/v0.5-webhook-notification/02-project-notification-settings-ui.md b/docs/releases/v0.5-webhook-notification/02-project-notification-settings-ui.md new file mode 100644 index 0000000..1011c0a --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/02-project-notification-settings-ui.md @@ -0,0 +1,69 @@ +# 02 Project Notification Settings UI + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/02-project-notification-settings-ui` + +Start this branch from `codex/v0.5-webhook-notification/01-notification-action-foundation`. + +## Goal + +Add project settings UI for managing notification actions. + +## Requirements + +- Add a project settings page at `projects/{project}/settings/notifications`. +- Add a settings navigation link alongside general, board, ticket, and repository settings. +- Project admins can list, create, update, enable, disable, and delete project notification actions. +- The create and update forms support: + - name + - event type + - channel + - enabled flag + - delivery URL + - message template for Discord +- Existing secret URLs stay hidden after save. +- Updating an action only replaces the secret URL when a new URL is submitted. +- Show the fixed template variables in the UI: `$url`, `$ticket_key`, `$ticket_title`, `$project_name`, `$status_from`, `$status_to`, and `$actor_name`. +- Add frontend types under `resources/js/types`. +- Generate Wayfinder output for the new routes and controller methods. + +## Acceptance Criteria + +- Project admins can manage notification actions from project settings. +- Non-admin project users cannot access the notification settings page or mutate notification actions. +- Validation errors are shown next to the relevant form fields. +- Saved notification actions show their name, event type, channel, enabled state, and created or updated date without exposing the secret URL. +- Existing project settings pages continue to work. + +## Tests + +- Feature tests for page access, create, update, enable/disable, delete, validation, and authorization. +- Inertia prop assertions for the notification action list and template variable metadata. +- Regression test that secret URLs are not rendered back in page props. + +## Verification + +- `php artisan wayfinder:generate --with-form --no-interaction` +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Projects` +- `npm run types:check` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/02-project-notification-settings-ui`. + +## Out of Scope + +- Ticket status changed event dispatch +- Actual webhook or Discord HTTP delivery +- Delivery attempt screens +- User bell notifications +- Unread counters +- Slack, Teams, email, or other channels +- Incoming webhooks +- API or MCP management endpoints diff --git a/docs/releases/v0.5-webhook-notification/03-ticket-status-changed-trigger.md b/docs/releases/v0.5-webhook-notification/03-ticket-status-changed-trigger.md new file mode 100644 index 0000000..9afab29 --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/03-ticket-status-changed-trigger.md @@ -0,0 +1,67 @@ +# 03 Ticket Status Changed Trigger + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/03-ticket-status-changed-trigger` + +Start this branch from `codex/v0.5-webhook-notification/02-project-notification-settings-ui`. + +## Goal + +Trigger notification deliveries when a ticket status actually changes. + +## Requirements + +- Add a `TicketStatusChanged` event or equivalent internal event object. +- Emit the event from the existing ticket move action only when the ticket moves to a different status. +- Do not emit the event for no-op moves where the destination status is already current. +- Build a reusable event payload that includes: + - project id, key, and name + - ticket id, key, title, and absolute ticket URL + - actor id and name when available + - origin status id and label + - destination status id and label + - occurred timestamp +- Add a listener or action that finds enabled project notification actions for `ticket_status_changed`. +- Queue one delivery job per matching action. +- Keep existing worklog behavior for status changes. + +## Acceptance Criteria + +- Moving a ticket to a new status queues delivery jobs for all enabled matching actions in the ticket project. +- Disabled actions are ignored. +- Actions from other projects are ignored. +- No-op moves do not queue delivery jobs. +- Ticket movement responses and worklog entries remain unchanged. + +## Tests + +- Ticket move feature tests asserting jobs are queued for enabled matching actions. +- Tests asserting disabled, foreign-project, and wrong-event actions are ignored. +- Test asserting no-op moves do not dispatch notifications. +- Test asserting the event payload contains the expected ticket URL and status labels. + +## Verification + +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Projects tests/Feature/Notifications` +- `php artisan test --compact tests/Feature/Api/TicketApiTest.php tests/Feature/Mcp` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/03-ticket-status-changed-trigger`. + +## Out of Scope + +- Actual webhook HTTP request execution +- Actual Discord HTTP request execution +- Delivery attempt UI +- User bell notifications +- Unread counters +- Slack, Teams, email, or other channels +- Incoming webhooks +- API or MCP management endpoints diff --git a/docs/releases/v0.5-webhook-notification/04-generic-webhook-delivery.md b/docs/releases/v0.5-webhook-notification/04-generic-webhook-delivery.md new file mode 100644 index 0000000..a5f35dd --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/04-generic-webhook-delivery.md @@ -0,0 +1,70 @@ +# 04 Generic Webhook Delivery + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/04-generic-webhook-delivery` + +Start this branch from `codex/v0.5-webhook-notification/03-ticket-status-changed-trigger`. + +## Goal + +Deliver `ticket_status_changed` notifications to classic JSON webhook URLs. + +## Requirements + +- Implement queued delivery for notification actions using the `webhook` channel. +- Send an HTTP `POST` JSON request to the configured webhook URL. +- Include a structured payload suitable for n8n: + - event type + - project object + - ticket object + - actor object or null + - from status object + - to status object + - ticket URL + - occurred timestamp +- Use Laravel's HTTP client with a sensible timeout. +- Configure job retry/backoff so temporary webhook failures can retry. +- Persist delivery logs for success and failure. +- Store HTTP status and a short response or error excerpt when available. +- External delivery failures must not roll back ticket moves. + +## Acceptance Criteria + +- Webhook actions receive a JSON `POST` for ticket status changes. +- The payload contains enough context for n8n to route and format follow-up automation. +- Successful responses mark the delivery log as succeeded. +- Failed responses or connection errors mark the delivery attempt as failed or retryable according to the job state. +- Discord actions are not delivered by this ticket. + +## Tests + +- HTTP fake tests asserting method, URL, headers, and JSON payload. +- Tests for successful delivery log updates. +- Tests for non-2xx responses and connection failures. +- Queue/job tests for retry/backoff configuration where practical. +- Regression test that ticket moves still succeed when webhook delivery fails later. + +## Verification + +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Notifications tests/Feature/Projects` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/04-generic-webhook-delivery`. + +## Out of Scope + +- Discord delivery +- Custom webhook headers or signing secrets +- Delivery attempt UI +- User bell notifications +- Unread counters +- Slack, Teams, email, or other channels +- Incoming webhooks +- API or MCP management endpoints diff --git a/docs/releases/v0.5-webhook-notification/05-discord-webhook-delivery.md b/docs/releases/v0.5-webhook-notification/05-discord-webhook-delivery.md new file mode 100644 index 0000000..8a7cb8b --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/05-discord-webhook-delivery.md @@ -0,0 +1,69 @@ +# 05 Discord Webhook Delivery + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/05-discord-webhook-delivery` + +Start this branch from `codex/v0.5-webhook-notification/04-generic-webhook-delivery`. + +## Goal + +Deliver `ticket_status_changed` notifications to Discord webhooks with configurable message text. + +## Requirements + +- Implement queued delivery for notification actions using the `discord` channel. +- Send an HTTP `POST` request to the configured Discord webhook URL. +- Render the configured message template before delivery. +- Supported template variables: + - `$url` + - `$ticket_key` + - `$ticket_title` + - `$project_name` + - `$status_from` + - `$status_to` + - `$actor_name` +- Send Discord payload `{ "content": "" }`. +- Validate or guard that rendered Discord messages are non-empty. +- Respect Discord content length limits. +- Persist delivery logs using the same delivery logging rules as the generic webhook channel. + +## Acceptance Criteria + +- Discord actions receive a rendered text message for ticket status changes. +- Template variables are replaced with event payload values. +- Unknown template text remains literal text. +- Empty rendered messages are rejected before delivery and logged as failed. +- Generic webhook actions continue to deliver their JSON payload unchanged. + +## Tests + +- Template rendering tests for every supported variable. +- HTTP fake tests asserting Discord payload shape. +- Tests for empty template output and content length validation. +- Delivery log tests for successful and failed Discord requests. +- Regression tests proving webhook channel behavior remains unchanged. + +## Verification + +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Notifications` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/05-discord-webhook-delivery`. + +## Out of Scope + +- Discord embeds or rich formatting +- Discord bot tokens +- Slack, Teams, email, or other channels +- Delivery attempt UI +- User bell notifications +- Unread counters +- Incoming webhooks +- API or MCP management endpoints diff --git a/docs/releases/v0.5-webhook-notification/06-notification-tests-and-release-hardening.md b/docs/releases/v0.5-webhook-notification/06-notification-tests-and-release-hardening.md new file mode 100644 index 0000000..c9346e7 --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/06-notification-tests-and-release-hardening.md @@ -0,0 +1,62 @@ +# 06 Notification Tests and Release Hardening + +Implementation guide: [Ticket Implementation Guide](../ticket-implementation-guide.md) + +## Branch + +`codex/v0.5-webhook-notification/06-notification-tests-and-release-hardening` + +Start this branch from `codex/v0.5-webhook-notification/05-discord-webhook-delivery`. + +## Goal + +Complete release-level coverage and polish for v0.5 webhook notifications. + +## Requirements + +- Review the full v0.5 implementation against the release README and all prior tickets. +- Fill missing tests for permissions, validation, hidden secrets, queued delivery, delivery logs, disabled actions, no-op moves, and multiple actions per event. +- Confirm project settings navigation is consistent across settings pages. +- Confirm existing ticket move flows still behave the same for web, API, and MCP clients. +- Confirm documentation matches the implemented behavior. +- Update release ticket docs only when they differ from the finished implementation. + +## Acceptance Criteria + +- All v0.5 acceptance criteria are covered by automated tests. +- A ticket status change can trigger multiple enabled actions for the same project. +- Failed external deliveries do not prevent ticket status movement. +- Secrets are never exposed in resources, Inertia props, logs, or tests. +- Existing web, API, and MCP status movement tests pass. +- The release docs are accurate after implementation. + +## Tests + +- End-to-end feature tests for creating actions and triggering deliveries from ticket status movement. +- Authorization tests for project admin management and non-admin denial. +- Regression tests for web, API, and MCP ticket status moves. +- HTTP fake tests for webhook and Discord delivery. +- Queue tests for dispatch behavior and retryable failures. + +## Verification + +- `php artisan route:list --except-vendor` +- `php artisan wayfinder:generate --with-form --no-interaction` +- `vendor/bin/pint --dirty --format agent` +- `php artisan test --compact tests/Feature/Notifications tests/Feature/Projects tests/Feature/Api/TicketApiTest.php tests/Feature/Mcp` +- `npm run types:check` +- `git diff --check` + +## Commit And Push + +- Commit only this ticket's changes. +- Push with `git push origin codex/v0.5-webhook-notification/06-notification-tests-and-release-hardening`. + +## Out of Scope + +- New notification channels beyond webhook and Discord +- User bell notifications +- Unread counters +- Incoming webhooks +- API or MCP management endpoints +- OAuth, scoped notification tokens, or external app installations diff --git a/docs/releases/v0.5-webhook-notification/README.md b/docs/releases/v0.5-webhook-notification/README.md new file mode 100644 index 0000000..d2518e1 --- /dev/null +++ b/docs/releases/v0.5-webhook-notification/README.md @@ -0,0 +1,35 @@ +# Release v0.5 - Webhook Notifications + +## Purpose + +Add project-scoped notification actions that can react to KanbanGit events and deliver outbound webhook-style messages. + +The first supported event is `ticket_status_changed`. The first supported channels are a classic JSON webhook for tools like n8n and a Discord webhook with configurable message text. + +## Release Decisions + +- Notification actions are configured per project in project settings. +- Project admins manage notification actions. +- Delivery is queued so ticket status moves are not blocked by slow external services. +- Every delivery attempt is logged for debugging. +- Webhook and Discord URLs are stored as secrets and are not shown back to the user after save. +- Template rendering uses a fixed variable set: `$url`, `$ticket_key`, `$ticket_title`, `$project_name`, `$status_from`, `$status_to`, and `$actor_name`. + +## Tickets + +- [01 Notification Action Foundation](01-notification-action-foundation.md) +- [02 Project Notification Settings UI](02-project-notification-settings-ui.md) +- [03 Ticket Status Changed Trigger](03-ticket-status-changed-trigger.md) +- [04 Generic Webhook Delivery](04-generic-webhook-delivery.md) +- [05 Discord Webhook Delivery](05-discord-webhook-delivery.md) +- [06 Notification Tests and Release Hardening](06-notification-tests-and-release-hardening.md) + +## Out of Scope + +- User bell notifications +- Unread counters +- Slack, Teams, email, or other channels +- Incoming webhooks +- Per-user notification preferences +- API or MCP management endpoints for notification actions +- Event types beyond `ticket_status_changed`