Files
ignacionelson f06a3c7ab3 Put a new client account in front of the staff who administer clients
Invitations produced no in-app notification at all, and neither did
self-registration: the whole Clients module raised none. The only
admin-facing signal when an account appeared was an email to whatever raw
addresses an operator typed into a setting -- addresses that need not
correspond to any account in this installation, and that plenty of
installations never fill in. An invitation could be accepted and nobody
signed in would ever be told.

So: one new type, client_registered, reaching the bell and /notifications.
One type for both doors on purpose. A client arriving through the public
form and one arriving through an invitation are the same event to the
person being told -- an account now exists that did not -- and a second
type would buy nothing, because preferences here govern email only, so it
could not have been switched off separately anyway. Which door it came
through is one click away in the activity log and on the invitations
screen.

In-app only, the reasoning client_uploaded already states: email for this
event is sent separately to that address list, and routing it through
Notifier's mail dispatch too would risk double-emailing any staff member
who is also on it.

Two things worth stating about who gets it. Recipients are resolved at the
call site, because Notifier authorizes nothing by design -- its security
contract is explicit that a broad query must never be handed to it. And a
client-scoped staff member is deliberately not told: their whole view is
the clients assigned to them, and a brand-new account is assigned to
nobody, so it would link them to a screen they are refused.

Which is also why the notification links to the clients list filtered to
the address, and not to clients.edit: that route is gated by edit_clients
while these recipients are chosen by manage_clients. A notification that
refuses the person it was sent to is worse than one that lands a click
short.

Translated in all sixteen locales, and the redemption was driven through a
real browser to see the row arrive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPk8qAs38pudYGWwmGkYPe
2026-09-12 17:34:47 -03:00

28 lines
931 B
PHP

<?php
use App\Modules\Api\ApiServiceProvider;
use App\Modules\Audit\AuditServiceProvider;
use App\Modules\Clients\ClientsServiceProvider;
use App\Modules\Comments\CommentsServiceProvider;
use App\Modules\Files\FilesServiceProvider;
use App\Modules\Groups\GroupsServiceProvider;
use App\Modules\Identity\IdentityServiceProvider;
use App\Modules\Notifications\NotificationsServiceProvider;
use App\Modules\Platform\Branding\BrandingServiceProvider;
use App\Modules\Platform\PlatformServiceProvider;
use App\Providers\AppServiceProvider;
return [
ApiServiceProvider::class,
AuditServiceProvider::class,
ClientsServiceProvider::class,
CommentsServiceProvider::class,
FilesServiceProvider::class,
GroupsServiceProvider::class,
IdentityServiceProvider::class,
NotificationsServiceProvider::class,
PlatformServiceProvider::class,
BrandingServiceProvider::class,
AppServiceProvider::class,
];