Chapter 27 — SaaS control panel
Home: /saas/control/
This chapter is for platform staff, not for customers. It describes the panel used to operate TOSS ERP as a service: creating customer workspaces, managing subscriptions, handling tickets and sales leads. Customers never see it.
27.1 Signing in
Screen: /saas/staff/login/
Staff sign in at a separate address from customers, on the platform's own host rather than a customer subdomain.
Two-factor authentication
Screen: /saas/control/2fa/
Superusers may enable two-factor authentication on their own account. It is optional and personal — an organisation-wide requirement is not imposed.
Two methods:
| Method | How it works |
|---|---|
| Authenticator app | Scan the QR code, or enter the key by hand |
| Email code | A short-lived code sent to your address |
On enrolment you are shown ten recovery codes, once. Save them somewhere you can reach without your phone. Each works once.
An account without two-factor enabled signs in exactly as before.
27.2 The dashboard
Screen: /saas/control/
| Panel | Shows |
|---|---|
| Needs attention | Failed provisioning first, then past-due accounts and trials ending within seven days, each with days remaining |
| Stat cards | Tenants, trials, monthly recurring revenue, past due, open tickets, recent leads |
| Recent activity | New tenants, recent tickets, recent leads |
Work "needs attention" top-down. Provisioning failures are listed above every countdown because a customer whose workspace failed to build has verified their email and is now waiting on nothing.
27.3 Tenants
/saas/control/tenants/ list
/saas/control/tenants/new/ create one
/saas/control/tenants/<id>/ detail
/saas/control/tenants/export.csv export
/saas/control/tenants/<id>/impersonate/ sign in as the customer
/saas/control/tenants/<id>/backup/ download their backup
/saas/control/tenants/<id>/delete/ delete the workspace
Creating a tenant
Staff-created tenants may be put on any plan, not only the two self-service ones offered on the public sign-up page.
- Select New tenant.
- Enter the organisation name, the subdomain, the owner's email, and the plan.
- Create. The workspace is provisioned.
The tenant detail page
Everything about one customer: their profile, their subscription, their status, their staff activity log, and the actions below.
A status banner appears where it matters — a countdown for a past-due account, the deletion date for a suspended one, and a reactivation note.
Recording a payment
There is no payment gateway. Payments are recorded by hand.
- Open the tenant.
- In Record payment, enter the amount, the reference, and the number of days to extend by.
- Submit.
Recording a payment extends the period, clears the past-due flag, reactivates a suspended workspace, and clears any deletion warnings already sent. One action covers both a first payment during a trial and a reactivation after suspension.
Changing a plan
Changing a plan changes which modules the customer has.
- Choose the new plan.
- A confirmation step lists exactly what will be granted and what will be revoked. Read it — a downgrade removes access to modules the customer may be using today.
- Confirm, or choose the option to change the plan only, without touching modules.
The grants and revocations are written to the audit log.
Impersonation
Restricted to superusers.
Signing in as a customer to reproduce a problem they are reporting.
- Select Impersonate on the tenant.
- You are taken into their workspace, signed in as one of their administrators.
- A banner is displayed for the whole session, naming you as the staff member impersonating.
- Select End impersonation when finished.
Use it to see what they see, not to do their work for them. Every action you take is recorded as that user, in their workspace, in their audit trail.
Downloading a customer's backup
Restricted to superusers. Produces the same backup file the customer can take themselves (Chapter 26), without needing their password. Take one before any destructive action.
Deleting a tenant
Restricted to superusers. This is irreversible.
- Open the delete page. It shows the ticket and lead counts that will be affected.
- Download a backup first — the page links to it.
- Type the workspace's exact slug to confirm.
- Delete.
The action is written to the audit log before anything is dropped, with the workspace's identifying details recorded inline — the tenant row will not exist afterwards to look them up in.
If the database cannot be dropped, the tenant record is deliberately left in place rather than deleted anyway. An orphaned database with nothing pointing at it is harder to find later than a tenant in a failed-delete state.
27.4 Subscription lifecycle
Sign up ──► Trial (30 days) ──► Active
│ │
└──► Past due ◄─────┘
│
├── grace window, access continues,
│ the customer sees a banner
▼
Suspended
│
payment recorded
│
▼
Active
- Every plan runs a 30-day trial, including the free tier.
- A lapsed subscription is flagged past due, and access continues through a grace window with a warning banner in the customer's workspace.
- After the grace window the workspace is suspended: sign-in is blocked for everyone, and the blocked page carries a form to contact billing without signing in.
- Recording a payment reactivates it, automatically.
A daily job flags past-due subscriptions and suspends those past their grace window.
Deletion warnings
A suspended workspace is warned by email before its data is deleted, at fixed milestones counting down to the retention limit. Recipients are the owner address and the workspace's own administrators.
Two behaviours worth knowing:
- Only the nearest milestone is emailed. A workspace suspended long ago gets one accurate warning, not a burst of backdated ones.
- A failed send records nothing, so the next run retries rather than marking a warning the customer never received.
Deletion itself is manual. The warnings are automated; the deletion is a deliberate superuser action. If staff never act, the customer is warned and nothing happens — so watch the suspended list.
27.5 Plans
/saas/control/plans/ list
/saas/control/plans/new/ create
/saas/control/plans/<id>/edit/ edit
A plan defines the price, the modules included, the user and record limits, and the public marketing copy.
When creating a plan, quick-start buttons prefill sensible defaults for a free/self-serve, standard subscription, or custom/negotiated plan. Everything remains editable.
When editing, a live preview shows how the plan will appear on the public pricing page, rendered from the same code the public page uses — so what you see is what customers will see.
A plan's price and its description must agree. A plan named "Free trial" priced at 50 a month, or described as never expiring while the system expires it, contradicts itself on the one page where a customer commits.
27.6 Support tickets
/saas/control/tickets/ list
/saas/control/tickets/new/ create
/saas/control/tickets/<id>/ detail and reply
/saas/control/tickets/export.csv export
Customer tickets, with an SLA view.
A ticket is stale when staff owe a response and have not given one within a priority-scaled threshold — one day for urgent, two for high, three for normal, five for low. Tickets waiting on the customer are deliberately excluded: the ball is not in your court, and counting them would make the queue lie.
Filter to stale only to see what genuinely needs attention.
Replies are sent from the signed-in staff member's own mailbox where one is configured, so the customer can reply to a person.
Module requests
A ticket whose subject begins with Module request carries a banner linking to the tenant, because the action needed is enabling apps on their record rather than a reply.
27.7 Sales leads
/saas/control/leads/ list
/saas/control/leads/<id>/ detail
/saas/control/leads/export.csv export
Leads from the public marketing site.
The conversation
The lead detail page carries the original enquiry and every staff reply as a thread. Send reply sends from the signed-in staff member's address. Inbound replies are picked up from the capture mailbox and matched to the lead by its reference or by the mail thread; Check email replies fetches now rather than waiting.
A reply moves a new lead to contacted automatically.
Replies sent from your own mail client, outside the panel, do not appear here. The card says so. Reply in the panel if you want the thread to be complete.
Spam handling
Marketing form submissions are checked on arrival: a honeypot field, a rate limit per address, and duplicate detection on email and company. Leads from an address that has already submitted several times are marked as spam automatically.
The lead detail page shows other leads from the same address and offers mark all from this address as spam.
27.8 Website visits and audit
/saas/control/visits/ public site visits
/saas/control/audit-log/ the staff audit log
The audit log records every staff action across all tenants, searchable by target type, staff member, date range and free text. It is the record when a question is asked about who changed what.
27.9 Error monitoring
/saas/control/errors/ unresolved errors first
/saas/control/errors/<id>/ one error, with its traceback
Application faults are captured centrally, grouped so that one bug is one row however many times it occurs, with a count of sightings.
How alerting behaves, because it explains what you will and will not receive:
- The first sighting emails immediately. A bad deploy throws the same error thousands of times, and the first one is the news.
- Repeats stay quiet for a set period afterwards.
- A different fault alerts at once — quiet time applies per fault, not globally.
- A fault marked resolved that happens again alerts immediately and reopens itself. That is the case where someone believes a bug is fixed and it is not.
The Errors tab in the header carries a live count of unresolved faults.
Resolve an error when it is genuinely fixed. Resolved errors age out; unresolved ones are kept regardless of age, because an unfixed fault does not stop mattering.
27.10 Staff users and roles
/saas/control/users/ staff accounts
/saas/control/roles/ staff roles
/saas/control/roles/new/ create a role
Roles are superuser-only to manage, because they control both what a staff member can see and where notifications are routed.
A staff role sets:
| Setting | Effect |
|---|---|
| Allowed tabs | Which of the six gated areas the holder may open — website visits, tenants, plans, support, sales leads, audit log |
| Notify on sales leads | Members are emailed and notified when a lead arrives |
| Notify on ticket categories | Members are notified for tickets in the chosen categories |
Two behaviours to understand:
- The dashboard is always reachable. It is not one of the gated tabs, so a role can never lock its own members out of a landing page — it simply shows less.
- Scoping is enforced on the server, not merely by hiding navigation. A scoped user typing a blocked address is redirected.
Backwards compatibility: a staff account with no role assigned at all keeps full access, exactly as before roles existed. Only an account deliberately given a role is scoped by it. An account whose only role is inactive is scoped to nothing, not unscoped — the distinction is between never assigned and assigned but currently inactive.
27.11 Platform settings
/saas/control/platform-settings/ branding, SMTP, integrations
/saas/control/notifications/ notification routing
Superuser-only. Product name, portal URL, the platform's own SMTP, and integration credentials.
Every field is optional and falls back to the server's environment file. A deployment that never opens this page behaves exactly as it did before.
Some settings genuinely cannot live here, because they are needed before the application can open a database at all: database connection details, the secret key, allowed hosts, debug mode, the task broker, and the SaaS mode flags. Those stay in the server's environment file. The page's sidebar says so, so nobody asks twice.
Secret fields render blank; blank means unchanged.
27.12 Routine
Daily
[ ] Work "needs attention" top-down, provisioning failures first
[ ] Clear stale support tickets
[ ] Respond to new sales leads
[ ] Check unresolved errors
Weekly
[ ] Review past-due accounts and chase
[ ] Review trials ending within seven days
[ ] Review the suspended list — warnings are automatic, deletion is not
[ ] Review new leads for spam patterns
Monthly
[ ] Reconcile recorded payments against the bank
[ ] Review plan data for self-contradiction between price and description
[ ] Review the audit log
[ ] Review staff roles and remove access no longer needed
27.13 Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| A tenant is stuck at provisioning failed | The workspace database could not be built | Read the error on the needs-attention row; retry or create it manually |
| A customer says they never got the verification email | It may not have been sent, or went to spam | Check their tenant record; re-send |
| A suspended customer cannot reach anyone | They can — the blocked page has its own contact form | Point them at it |
| Recording a payment did not reactivate them | The amount extended fewer days than were owed | Check the period end date |
| A plan change removed modules unexpectedly | A downgrade revokes what the new plan excludes | The confirmation step lists this; restore by changing the plan back |
| Impersonation does not work | It is superuser-only, and the link is short-lived | Use a superuser account; retry from the tenant page |
| A staff member cannot see a tab | Their role does not allow it | Amend the role |
| A staff member sees everything unexpectedly | They have no role assigned, which means unscoped | Assign a role |
| No lead notifications arrive | No role has lead notification enabled | Set it on a role |
| An error alert never arrived | Repeats are quiet for a period after the first | Check the error list rather than waiting for mail |
| A tenant deletion failed | The database could not be dropped | The tenant record is left in place deliberately; investigate the database |