Skip to content

feat(newsletters): complete HTTP layer (AdonisJS)#88

Merged
mpge merged 11 commits into
mainfrom
feat/newsletter-http-layer
Jun 20, 2026
Merged

feat(newsletters): complete HTTP layer (AdonisJS)#88
mpge merged 11 commits into
mainfrom
feat/newsletter-http-layer

Conversation

@mpge

@mpge mpge commented Jun 2, 2026

Copy link
Copy Markdown
Member

What

Brings escalated-adonis from engine-only to full newsletter parity. Adonis had the tables + Lucid models + 6 services but no HTTP layer — this adds admin/public/webhook controllers, the dispatch ace command, enabled gate, permission enforcement, and tests.

Part of the full-parity program (mirrors the Laravel + NestJS references against escalated/docs/superpowers/specs/2026-06-02-newsletter-http-parity-contract.md).

Added

  • Admin controllers (campaigns/lists/templates/settings) registered in start/routes.ts under /newsletters with correct ordering (static segments before /:newsletter) and exact escalated.admin.newsletters.* route names.
  • Public controller (open-pixel, click redirect, unsubscribe show/store, view-in-browser) under escalated/n + ESP webhook controller (postmark/mailgun/ses/sendgrid) under escalated/webhooks/newsletter, both behind EnsureNewslettersEnabled middleware.
  • Dispatch worker: node ace escalated:newsletters:dispatch (plan due + dispatch batch).
  • Enabled gate: ensure_newsletters_enabled middleware (default off).
  • Permissions: newsletters.manage (admin actions) / newsletters.send (store-when-sending + test-send) via NewsletterPermissionService; seeded in the permission seed command + DB seeder.
  • Tests: Japa HTTP tests + engine contract coverage.

Verification

  • npm run build: PASS. Full suite: 509 node + 15 Japa, 0 failures.

Host-setup note

Adonis Shield CSRF is host-configured, so the host app must exempt POST escalated/n/u/:token (unsubscribe) from CSRF — documented in the command output. (Same public-unsubscribe behavior as the Laravel reference, where the plugin exempts it directly.)

mpge and others added 11 commits June 2, 2026 18:38
Co-authored-by: Cursor <cursoragent@cursor.com>
…utes

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Supports scheduling failed sends before they are eligible to be claimed again.

Co-authored-by: Cursor <cursoragent@cursor.com>
…laim, backoff, first-N auto-pause).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…t allowlist.

Co-authored-by: Cursor <cursoragent@cursor.com>
- pretest: run the build before `node --test` so the newsletter engine
  contract test can import the compiled service. It loads from build/,
  which CI never produced (only the author's stale local build existed),
  causing ERR_MODULE_NOT_FOUND on the Node 24 job.
- eslint --fix across the newsletter HTTP layer (prettier formatting),
  plus manual eqeqeq fixes — the `== null` idioms are expanded to explicit
  null/undefined checks to preserve their null-or-undefined semantics —
  and de-shadow the `router` parameter in registerNewsletterAdminRoutes
  (the module-level router is already in scope at the call site).
- prettier formatting for scripts/copy-build-assets.mjs.

Local: ESLint clean, Prettier clean, 514 node + 15 Japa tests, 0 failures.
@mpge mpge merged commit 2d2b922 into main Jun 20, 2026
3 checks passed
@mpge mpge deleted the feat/newsletter-http-layer branch June 20, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant