Skip to content

🔧 Extract invitations module + signup eligibility-hook inversion #3810

Description

@PierreBrisorgueil

Phase 2 of the invitations↔org decouple epic. Plan Phase 2.

Extract the signup-invitation into a standalone optional modules/invitations/ module; invert the dependency so auth no longer imports invitations.

Module tree: invitations.init.js, config/, routes/ (/api/invitations), controllers/, services/, repositories/, models/ (schema + mongoose Invitation), policies/, lib/events.js (invitationEvents, config-free), lib/constants.js, full tests/ incl. invitations.init.unit.tests.js.
Auth side: new modules/auth/services/auth.eligibility.js (registerSignupEligibility/assertSignupEligible/_reset); auth.controller.js replaces the two inline findValid/findValidByEmail calls with assertSignupEligible({ email, body, req }) (ctx MUST carry req) and drops the InvitationService import. invitations.init.js registers the checker.

⚠️ E13 token source: Vue sends the token as ?inviteToken= (query), NOT in the body. The checker reads req.query.inviteToken ?? req.body?.inviteToken. Tests: query-token (canonical), body-token, no-token.

Move auth.invitation.* + the /api/auth/invitations* routes into the module (tests repointed to /api/invitations). Mandatory invitationEvents.on('error', …) in init (else process crash), mirroring billing.init.js.

Acceptance: auth.controller.js has no InvitationService import; signup still gates; modules/auth has no *invitation* files; coverage ≥ patch target.


🛑 Fable review corrections (2026-06-10, code-verified vs origin/master)

  • 🔴 Deprecation alias REQUIRED: the Vue admin store calls /api/auth/invitations until P6. P2 MUST keep the old path working — mount the module handlers ALSO under /api/auth/invitations* + register the path-subject for BOTH prefixes; add a test asserting both /api/auth/invitations and /api/invitations resolve. Remove the alias only after P6 repoints the Vue store. Without this, master ships a broken admin tab for ~4 PRs and /dev:verify-qa fails on P2-P5.
  • Rate limit: reuse limiters.auth on admin CRUD + verify/:token (dev config = passthrough; prod-only — same as today's auth routes).
  • registerPathSubject precedent confirmed at lib/middlewares/policy.js; billing.init.js error-listener pattern confirmed — prescribed code is idiomatic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions