Platform admin panel
The platform admin panel (ADR-024) is where the operator sees every shop and every account on Flowery and does the few things an operator must be able to do without a database console. It lives on the root domain at https://flowery.com.ua/admin (locally http://flowery.test/admin), outside every tenant.
Who gets in
Section titled “Who gets in”Three conditions, all enforced server-side by the platform.admin middleware:
| Condition | How |
|---|---|
The account is flagged is_platform_admin |
Only from the command line: php artisan admin:grant <email>. The column is not mass assignable and no page changes it |
| Two-factor authentication is on for the account | Until then the panel shows a page that points at the account’s two-factor settings (in its own shop) and nothing else |
| The person signed in with a confirmed address | The usual auth and verified middleware |
Anyone else, signed in or not, gets a 404: the panel does not advertise itself to a shop user who guesses the address. The admin paths exist only on the root domain; on a shop host they are a 404 too.
php artisan admin:list # who is flagged and whether the panel is open to themEach grant and revoke is written to the audit log with the actor console:<system user>.
An administrator who has no shop of their own lands on the panel after sign-in and from the home page, instead of being sent to onboarding. Administrators normally do have a shop (two-factor is set up in a shop’s settings), and the user menu in any control panel links them to the panel.
What the panel shows
Section titled “What the panel shows”| Page | Content |
|---|---|
Overview /admin |
Counts of shops (total, active, suspended, onboarded, websites published, taking online orders, demo loaded, on their own domain), accounts (total, confirmed, with two-factor, Google, without a shop, administrators), sign-ups in 7 and 30 days, orders in the last 30 days (total, from websites, demo, in how many shops). A “needs attention” card: suspended shops, onboarding not finished for over a week, addresses not confirmed for over a week. The newest shops and accounts and the last administrative actions |
Shops /admin/shops |
Every workspace with owner, team size, order count and last order, website published and online ordering flags, own domain, created date, active or suspended. Search by name, address, owner name or email, or own domain (Unicode or punycode); filter by active, suspended, onboarding not finished, demo loaded, taking online orders; sort by name, created or onboarded |
Shop page /admin/shops/{slug} |
The shop’s dates (created, onboarded, welcome steps, trial end, last change), currency and timezone, links to its website and control panel; website and ordering state (theme, published, versions, pickup, delivery, Uklon), own domains with their status; catalogue counts; orders by status, from the website, demo, first and last; the team with each member’s role, address confirmation and two-factor state; the administration history of this shop; Suspend and Reactivate |
Clients /admin/clients |
Every account with its shops and roles, address confirmation, two-factor, Google link, administrator flag, registration date. Search by name or email; filter owners, unconfirmed, without a shop, without two-factor, administrators |
Client page /admin/clients/{id} |
The account’s state and memberships (shop, role, joined, shop active), its current shop, the administration history for it, Resend confirmation email (unconfirmed accounts) and Send password reset link |
Activity /admin/activity |
The audit log, newest first, filtered by action or administrator |
What the panel does not show: order contents, customer names and phones, prices, costs, provider keys or any shop’s money figures. It is an operator’s directory, not a back door into a shop’s trade. The one catalogue fact is the count of flowers and bouquets.
Actions and their protections
Section titled “Actions and their protections”| Action | Effect | Protection |
|---|---|---|
| Suspend a shop | workspaces.is_active = false. Its subdomain, control panel and own domain answer 403 to everyone, including its team (IdentifyTenant). No data changes |
Password confirmed again (Fortify password.confirm, three-hour window), a reason of 5 to 500 characters, 30 a minute, audited in the same transaction |
| Reactivate a shop | is_active = true; the hosts answer again |
The same |
| Send a password reset link | Fortify’s own reset email to the account’s address. The panel never sets a password and never signs in as anyone | Password confirmed, the broker’s own throttle, 10 a minute, audited |
| Resend the confirmation email | The standard verification email, only to an unconfirmed address | Password confirmed, 10 a minute, audited |
There is no impersonation (“sign in as the owner”) and no editing of a shop’s settings, catalogue or orders from the panel: those happen in the shop’s own control panel by its own team, and a support case that needs them is handled by asking the owner to invite the operator (team invitations).
The audit log
Section titled “The audit log”platform_admin_actions is append-only: PlatformAdminAction has no updated_at, nothing updates or deletes rows, and every write goes through App\Services\Platform\PlatformAudit. A row holds who (the account id and its email, or console:<user>), what (shop.suspended, shop.reactivated, client.password_reset_sent, client.verification_sent, admin.granted, admin.revoked), the subject (type, id, and its name at the time, so the row still reads if the subject is gone), the details (the reason), the address and the time. The Activity page lists it; a shop’s and a client’s page show their own slice.
Reading across tenants safely
Section titled “Reading across tenants safely”Tenant-scoped models (orders, storefront versions, domains, catalogue) carry a global scope that falls back to the signed-in user’s own current workspace when the request has no tenant, which is the case on the root domain. App\Services\Platform\PlatformDirectory, the panel’s read model, drops that scope on every query on purpose, and writes nothing. A test shows that an administrator whose current workspace is one shop still sees the others.
Browser testing
Section titled “Browser testing”The account needs two-factor on; the seeded demo accounts have it (dev:login --list shows the 2FA state). See browser testing.
tests/Feature/Admin/: access (404 for owners and on shop hosts, the two-factor gate, the sign-in landing, the content security policy), shops (list, search including by domain and with % as a letter, filters, the shop page, suspend and reactivate with password confirmation, reason validation, the audit rows, the 403 on the shop’s hosts, an owner refused with a confirmed password), clients (list, filters, the page without secrets, both emails with their audit rows, an unconfirmed-only rule), activity and the commands (grant, list, revoke with their rows; the log’s filters; dev:login --admin).