Foundations
Chapter 1 — Your Role as a Trenvar Employee
If you're reading this, you work for Trenvar (the platform company), not for a tenant. Your job is to make sure tenants can run their warehouses; not to run their warehouses for them.
What you'll do
- Onboard new tenants — provision their account, set up their owner login, walk them through first steps.
- Manage their lifecycle — suspend, resume, archive when needed.
- Configure their plan and modules.
- Run the platform's monthly billing cycle (charge tenants what they owe).
- Watch the audit log and analytics for unusual activity.
- Respond to support tickets and incidents.
What you won't do
- Run a tenant's day-to-day operations (their staff does that).
- See inside a tenant's data unless you impersonate (and impersonation is logged + restricted).
- Set per-customer pricing inside a tenant (the tenant's company_admin does that).
Chapter 2 — Platform vs. Tenant
Trenvar has two entirely separate worlds. They share infrastructure but the data, controls, and visibility are different.
Platform world
- Database collection:
platformTenants/*,platformAudit/*. - Console:
/console/owner/*. - Roles:
system_admin(only). - Permissions start with
platform.*. - What it controls: tenant lifecycle, module enablement, platform billing.
Tenant world
- Database collection:
tenants/{tenantId}/*. - Console:
/console/business/*,/console/operator/*, etc. - Roles: company_admin, operations_manager, operator, driver, customer_service, accounting, customer_*.
- Permissions start with
tenant.*,wms.*,dispatch.*, etc. - What it controls: warehouse, fulfillment, billing of downstream customers, etc.
Chapter 3 — Logging In to the Owner Console
Getting your account
Your manager creates your account in platformUsers with role system_admin. You'll receive a Firebase invite email. Set a password and you're in.
The owner console URL
Production: www.trenvar.com/owner/login. After signing in you land at /console/owner/tenants by default.
Chapter 4 — What system_admin Can and Cannot Do
Can
| Permission | What it lets you do |
|---|---|
| platform.tenants.list / read | See every tenant. |
| platform.tenants.create | Create new tenants. |
| platform.tenants.update | Edit tenant fields including modules, owner login, status. |
| platform.tenants.suspend | Suspend tenants. |
| platform.entitlements.configure | Toggle OSes/addons on or off per tenant. |
| platform.billing.read / update | See and edit platform billing — what we charge tenants. |
| platform.analytics.read | See MRR, ARR, plan mix, churn. |
| platform.impersonation.start | Start an impersonation session into a tenant. |
| platform.impersonation.write_enable | Enable WRITE during impersonation (extra dangerous). |
| platform.security.read | Read security events. |
| audit.security_events.read | Same. |
Cannot
- Read or write tenant business data without impersonation.
- Set tenant-internal user roles (company_admin does that).
- Configure customer-specific pricing inside a tenant.
- Modify another platform user's role without elevation.
Tenant Onboarding
Chapter 5 — The Trial Signup Flow (Customer's Path)
Most tenants come in via self-serve trial. This is what they experience.
- Visitor lands on the Trenvar website and clicks "Start Free Trial."
- Form: company name, email, password.
- Submit goes to
POST /api/public/trial-signup. - Backend creates a
trialSignuprecord withsignupSource: "public_trial", encrypts password, redirects to Stripe Checkout insetupmode (collects card, no charge). - Customer enters card. Stripe returns to
/trial/activation?signupId=...&session_id=.... - Stripe webhook hits
/api/billing/stripe/webhook. Backend creates the actual tenant intrialingstatus. - Customer logs in for the first time and lands at
/console/business/settings/company.
Your involvement
Usually none — it's fully automated. You only step in when:
- The customer reports the activation didn't work.
- The card was declined and you need to follow up.
- The trial signup landed in pending_approval (we have a manual gate enabled).
- The customer wants to skip self-serve and have you provision them.
Chapter 6 — Provisioning a Tenant Manually
Sometimes you create a tenant by hand — an enterprise sales handoff, an internal test, a partner.
- Click Create Tenant.
- Fill the form:
- Company Name — full legal name.
- Company Slug — short URL-safe ID. Lowercase. Cannot change after creation.
- Tax ID — optional but recommended for billing.
- Address — street, city, state, zip, country.
- Domain — their primary domain, used for email.
- Contact Name + Email — primary contact at the tenant.
- Plan — pick a plan that turns on the right OSes.
- Free Platform Access — tick if they don't pay us (internal/partner).
- Click Create. Tenant status starts as pending_approval (or active if you have auto-approve on).
acme-logistics. They cannot change this after onboarding.
Chapter 7 — Setting Up the Owner Login
A tenant exists, but no one can log in until you set up their owner login (their first company_admin user).
Check current state
The tenant detail page shows:
loginStatus: configured or not_configured.ownerLoginUid,ownerLoginEmail: who their admin is.loginUrl: where they log in.
Create the owner login
- Click Set Up Owner Login.
- Enter:
- Email — their admin's email (matches Contact Email if you provisioned).
- Display Name — their full name.
- Password — leave blank to auto-generate, or set one.
- Submit. The API returns:
temporaryPasswordif you didn't set one.passwordGenerated: true/false.
- Send the credentials to the customer via secure channel (encrypted email, password manager share — not Slack, not plain email).
Reset password for an existing owner
- From the tenant detail, find the credentials section.
- Click Reset Owner Password.
- Enter the existing UID or email + new password.
- Submit. Send them the new password securely.
Chapter 8 — Approving or Rejecting Pending Tenants
If your platform has manual approval enabled, every signup lands in pending_approval.
Reasons to reject
- Sketchy company name or contact.
- Disposable email domain.
- Already known fraud signal.
- Industry doesn't match Trenvar's target.
Workflow
- Filter tenants by status = pending_approval.
- Open one. Review company info, contact, signup source.
- Either click Approve (status → active) or Reject (status → rejected) with a reason.
Chapter 9 — The New-Tenant Onboarding Checklist
A reliable script you can hand to every new tenant — keeps onboarding consistent.
| # | Step | Who does it |
|---|---|---|
| 1 | Provision tenant + owner login | You (system_admin) |
| 2 | Send credentials securely | You |
| 3 | Customer logs in for first time | Customer's company_admin |
| 4 | Complete company profile + branding | Customer |
| 5 | Set up email provider (Resend) — optional but recommended | Customer |
| 6 | Invite their team (operators, accounting, etc.) | Customer's company_admin |
| 7 | Create warehouse locations | Customer |
| 8 | Build Item Master | Customer |
| 9 | Configure Service Catalog | Customer |
| 10 | Configure Pricing Rules (if 3PL OS on) | Customer |
| 11 | Configure storage rules (if 3PL OS on) | Customer |
| 12 | Configure tax regions | Customer |
| 13 | Create AWB provider env (if Air Cargo OS on) | You + Customer |
| 14 | Run a test pre-alert → receive → put away → invoice | Customer |
| 15 | Verify with you on a 30-min check-in call | You + Customer |
Full worked example — onboarding "Acme Corp" Tuesday morning
You receive a sales handoff Monday EOD: Acme Corp signed for Warehouse + 3PL, Net 30, $899/mo. Tuesday at 9 AM you sit down to provision them.
09:00 — provision the tenant
- Sign in to
/console/owner/tenants. - Click Create Tenant.
- Fill: Company Name "Acme Corp", Slug "acme-corp", Tax ID "12-3456789", Address (sales handoff has it), Domain "acme.com", Contact "Jane Smith / jane@acme.com / +1-555-0100", Plan "WMS+3PL bundle", Free Platform Access OFF.
- Click Create. Tenant lands in status pending_approval (your tenant has manual approval on).
- Filter list to pending. Open Acme. Click Approve. Status flips to active.
09:10 — set up owner login
- From Acme's tenant detail, find the Credentials section. Status: not_configured.
- Click Set Up Owner Login.
- Email = jane@acme.com (matches the contact). Display Name = Jane Smith. Password = leave blank (auto-generate).
- Submit. Modal returns: temporaryPassword=Tj4kP9!mZx2v.
- Open 1Password. Create a shared item: title "Acme Corp — Trenvar owner login (TEMP)", note that it expires after first use, expires_at=24h, share with Jane via 1Password's secure-share URL.
- Send Jane an email: "Your Trenvar tenant is live at www.trenvar.com/acme-corp/login. Your temporary password is in this 1Password share: [link]. Please change it on first login."
09:20 — enable modules
- Acme's tenant detail → Modules section.
- Tick: wms_core, module_3pl. Untick the rest.
- Save. Audit log records the change.
09:25 — send the guides
- Email Jane separately: attach (or link) TRENVAR_FOUNDATIONS.html, TRENVAR_WAREHOUSE_OS.html, TRENVAR_3PL_OS.html, TRENVAR_WAREHOUSE_3PL_COMBO.html.
- Add note: "Read Foundations first (10 min). Then the Warehouse + 3PL combo guide for end-to-end. Reference the OS guides for specific functions."
09:30 — book a 30-min check-in for Friday
You'll walk Jane through her first test pre-alert → receive → put-away → invoice. By Friday she should have set up locations, item master, services, pricing, and storage rules. The check-in catches any blockers.
Done. Total time: 30 minutes for you. Acme is live and self-serving.
Tenant Lifecycle
Chapter 10 — Suspending and Resuming
Reasons to suspend
- Non-payment past grace period.
- Terms-of-service violation.
- Customer requested temporary pause.
- Security incident requiring lockdown.
How
- Open the tenant.
- Change status from active to suspended.
- Enter a suspension reason (becomes part of the audit trail).
- Save.
Effect: all tenant users immediately get blocked at the auth layer. Their data is not deleted. Webhooks pause. Stripe charges pause.
Resuming
Same screen. Status: suspended → active. Tenant users can log in again immediately. No data loss.
Chapter 11 — Archiving (Off-Boarding)
When a tenant churns and won't return.
- Confirm cancellation in writing from the tenant's company_admin.
- Run a final billing cycle if there are unbilled accruals.
- Offer a data export (we'll do CSV exports of their key collections).
- In
/console/owner/tenants/[tenantId], change status to archived. - Set
autoChargeEnabledto false. - Document the off-boarding in the audit notes.
Chapter 12 — Tenant Data on Suspension and Archive
| State | Login | Data | Webhooks | Stripe billing |
|---|---|---|---|---|
| active | Allowed | Live | Active | Active |
| suspended | Blocked | Frozen, retained | Paused | Paused |
| archived | Blocked | Read-only retained for retention window, then purged | Disabled | Disabled |
| rejected | Blocked | Minimal record retained for compliance | — | — |
Plans, Modules, Pricing
Chapter 13 — The Platform Billing Model
We charge tenants a recurring monthly fee for the modules they have enabled.
How it adds up
- Each tenant has a set of major modules (wms_core, module_3pl, module_tms, module_ground_ops, module_b2b_storefront, module_crm).
- Each module has a
monthlyPriceCentsin the platform pricing config. - Each tenant's monthly bill = sum of enabled modules' prices.
- Plus optional minor modules (add-ons like advanced returns, EDI integration).
Default pricing
| Module | Default price (USD/mo) |
|---|---|
| wms_core | $299 |
| module_3pl | $300 |
| module_tms | $200 |
| module_ground_ops | $400 |
| module_b2b_storefront | $99 |
| module_crm (sales CRM add-on) | $150 |
OS bundles
| OS Bundle | Modules included | Bundle price (USD/mo) |
|---|---|---|
| Warehouse OS | wms_core | $299 |
| 3PL OS | wms_core + module_3pl | $599 |
| Transport OS | wms_core + module_tms | $499 |
| Air Cargo OS | wms_core + module_ground_ops | $699 |
| Commerce OS | wms_core + module_b2b_storefront | $398 |
Chapter 14 — Module Pricing Configuration
Editing the global price
- Open the modules screen.
- Edit
monthlyPriceCentsfor any module. - Click Save Pricing Config. PATCH goes to
/api/owner/modules-pricing.
Changes apply at the next billing cycle. Existing tenants on the old price keep that price until you renew them or until the cycle hits.
The pricing config schema
{
"modules": {
"wms_core": { "enabled": true, "monthlyPriceCents": 29900 },
"module_3pl": { "enabled": true, "monthlyPriceCents": 30000 },
"module_tms": { "enabled": true, "monthlyPriceCents": 20000 },
"module_ground_ops": { "enabled": true, "monthlyPriceCents": 40000 },
"module_b2b_storefront": { "enabled": true, "monthlyPriceCents": 9900 },
"module_crm": { "enabled": true, "monthlyPriceCents": 15000 }
},
"minorModules": {
"advanced_returns": { "enabled": true, "monthlyPriceCents": 4900 },
"edi_integration": { "enabled": false, "monthlyPriceCents": 9900 }
},
"currency": "USD",
"invoiceIssueDay": 1,
"paymentDueDays": 14,
"enforceSubscription": true
}
Chapter 15 — Enabling and Disabling OSes per Tenant
A tenant's enabled modules are stored in their tenant record under majorModules.
- Open the tenant.
- Find the Modules section.
- Tick the modules to enable; untick to disable.
- Save.
What happens when you toggle
- Server checks dependency rules (e.g., Commerce OS auto-enables Warehouse OS).
- UI screens appear or disappear for the tenant on next page load.
- Module entitlement caches are invalidated.
- Audit log records the change with your UID.
- Next platform invoice reflects the new module set.
Chapter 16 — Free Platform Access
Some tenants don't pay us — internal demos, partner test environments, sales-funded pilots.
- On the tenant record, tick Free Platform Access.
- Subscription cycle skips them (no Stripe charges).
- Document the reason in the tenant notes.
Chapter 17 — Running the Subscription Cycle
Monthly: charge every billable tenant for what they owe.
Triggering the run
POST /api/owner/billing/subscriptions/run creates platform invoices for every active billable tenant in the current period.
What returns
{
"billingLifecycle": {
"periodFrom": "2026-05-01",
"periodTo": "2026-05-31",
"createdCount": 42,
"skippedExistingCount": 3,
"skippedFreeCount": 5,
"skippedStatusCount": 2,
"skippedNoChargeCount": 1
}
}
| Counter | What it means |
|---|---|
| createdCount | New invoices generated. |
| skippedExistingCount | Tenant already has an invoice for this period. |
| skippedFreeCount | Tenant has freePlatformAccess. |
| skippedStatusCount | Tenant suspended/archived/rejected. |
| skippedNoChargeCount | No enabled modules to charge for. |
Walkthrough — run the subscription cycle on the 1st of the month
Prerequisites
- system_admin with
platform.billing.update. - It's the 1st of the month (or you're running back-fill).
- You've already verified module pricing config is current.
Step-by-step
- Sign in to
/console/owner/plans. - Find the Run Subscription Cycle button.
- Click it. A confirmation modal opens:
- Period From → defaults to first of current month.
- Period To → defaults to last of current month.
- Dry Run toggle → tick to preview without creating invoices.
- First time? Always Dry Run first. Tick it. Click Run.
- Result panel shows the counts (createdCount, skippedExistingCount, etc.) without persisting anything.
- If counts look right (e.g., 42 expected new invoices), untick Dry Run and click Run again. Real invoices are created.
- Stripe auto-charge runs against tenants with autoChargeEnabled=true. Card declines flow back as invoice status "payment_failed" — investigate per tenant.
When to run
Either schedule it (cron at /api/cron/platform-subscriptions at 02:00 UTC on day 1 of each month) or run manually on the 1st of each month. Default invoiceIssueDay = 1, paymentDueDays = 14.
Audit, Analytics, Security
Chapter 18 — The Audit Log
Every meaningful action across the platform is logged immutably.
What's recorded
| Field | Notes |
|---|---|
| action | create / update / delete / revoke / rotate / transition / etc. |
| entity_type | tenant / user / pod / invoice / api_credential / api_rate_limit / abuse_protection / etc. |
| entity_id | ID of the thing acted on. |
| tenant_id | Scope. |
| actor_uid | Who did it (user UID, or "air_awb_webhook" for system actors). |
| actor_role | Their role at the time. |
| created_at_ms | When (server-time). |
| metadata | Action-specific extras (retry hints, throttle reasons, etc.). |
Filters
Filter by action, entity_type, tenant_id, actor_role. Use date range. Search free-text in metadata.
Chapter 19 — Throttle Awareness
The audit log surfaces rate-limit / abuse-protection events at the top of the page.
| Metric | What to do |
|---|---|
| Throttles in last 1h | Spike means someone (or something) is hammering the API. |
| Throttles in last 24h | Trend. |
| Max retry-after observed | How aggressively we're pushing back. |
If you see a sustained throttle stream from one tenant, drill in:
- Filter by tenant_id.
- Look at action = "throttle" and entity_type = "api_rate_limit".
- Check which credential/IP is hitting limits.
- Decide: contact tenant, raise their quota, or revoke an abusive credential.
Chapter 20 — Platform Analytics
MRR, ARR, plan mix, churn, total tenants.
Backed by /api/owner/analytics/financial-rollups. View shows:
- MRR — total monthly recurring revenue.
- ARR — annual run rate.
- Active tenant count.
- Plan mix — breakdown by which OS bundles tenants have.
- Churn — tenants archived this period.
- New tenants — onboarded this period.
Chapter 21 — Impersonation
Sometimes you need to log in as a tenant user to debug. This chapter walks through how, with a strong emphasis on doing it correctly.
Walkthrough — start a read-only impersonation session
Prerequisites
- system_admin with
platform.impersonation.start. - Explicit permission from the tenant (over email, ticket, or call) — document who gave it and when.
- You know which user you need to impersonate and why.
Step-by-step
- Sign in to the Owner Console.
- Go to
/console/owner/tenants. Find the target tenant. Click its row. - Tenant detail page → Users tab.
- Find the user you have permission to impersonate. Click the three-dot menu next to their row.
- Click Impersonate. Modal opens with three fields:
- Reason → mandatory free text. ("Debugging Jane's reported invoice issue, ticket #4521.")
- Permission Source → mandatory dropdown: Email from user / Phone call / Ticket / Other.
- Permission Reference → ticket number, email subject, or call timestamp.
- Write Mode → off by default. Leave off unless you absolutely need to make changes.
- Click Start Impersonation. New tab opens; you're now signed in as the target user.
- An orange banner appears at the top of every screen: "IMPERSONATING jane@acme.com (read-only) — End session". The banner is sticky and unmissable.
- Reproduce the issue from the user's perspective. Take screenshots if needed.
- When done, click End session in the banner. You return to your owner console.
Walkthrough — write-mode impersonation (rare, dangerous)
When to use
Almost never. Only when fixing a stuck record on behalf of a customer who can't fix it themselves and explicitly asked you to. Most "fixes" should be done by the customer's company_admin under their own session, with you walking them through it.
Step-by-step
- You need both
platform.impersonation.startANDplatform.impersonation.write_enable. Most system_admins don't have the second one — only senior or designated admins do. - In the Impersonate modal, tick Write Mode.
- Banner color changes from orange to red.
- Make the minimum-needed change. Document everything in your own notes (what record, before/after).
- End session immediately when done. Don't browse around.
- Email the customer afterwards: "I made the following change on your behalf at your request: [details]. Audit reference: [link]."
The audit trail (always-on, unhideable)
Every impersonation event is logged immutably with:
- Your UID + role.
- The impersonated user's UID + role + tenant.
- Reason, permission source, permission reference (the fields you filled in).
- Mode (read or write).
- Session start + end timestamps.
- Every action taken during the session, with full payloads.
The customer's company_admin can see every impersonation in their own tenant audit log. So can you in the platform audit. So can future-you in 3 years if there's a dispute.
Chapter 22 — Security Read Access
platform.security.read and audit.security_events.read let you see security events.
Examples:
- Failed login attempts above threshold.
- Unusual API access patterns.
- Cross-tenant data access attempts (always investigated).
- Webhook signature verification failures.
Use during incident response. Document everything you find.
Operations & Runbooks
Chapter 23 — Common Support Tickets
"My team can't log in"
- Confirm tenant status is active (not suspended).
- Confirm Firebase Auth is healthy globally.
- Have the user try password reset.
- If multi-user: check if their tenant slug or domain has changed.
"I forgot the company_admin password"
- Verify identity (email match, phone confirmation, contact-of-record).
- Use Reset Owner Password flow (Chapter 7).
- Send new password securely.
"Module X stopped working"
- Open the tenant's modules section. Is X still ticked?
- Check entitlement keys via Firestore inspection (or via owner console).
- Check audit log: was anything changed in last 24h?
- If a deploy went out: check for related incidents.
"I want to upgrade to a bigger plan"
- Tick the additional modules in the tenant's modules section.
- Save.
- Run the next subscription cycle (or wait for the scheduled one).
- Confirm with tenant that screens are now visible.
"I want to downgrade"
- Confirm in writing from company_admin.
- Note any data they'll lose access to (drivers can't log in if Transport OS goes off).
- Untick modules.
- Save.
Chapter 24 — Provider Outage Runbook
Resend, Stripe, AWB carrier, Shopify, or any third-party we depend on goes down.
- Confirm the provider's status page is showing degradation.
- Check audit log for related throttle/error events.
- Estimate impact: which tenants are affected? (e.g., AWB outage only affects Air Cargo OS tenants.)
- Post a notice via /console/owner notices to affected tenants.
- Disable any retry loops that might be aggravating the provider.
- Monitor; when provider recovers, resume retries.
- For failed deliveries during the outage: bulk replay from the deliveries queue.
- Post-mortem if outage was >30 minutes.
Chapter 25 — Webhook Backlog Runbook
A tenant's webhook endpoint is failing or slow, and our retry queue is backing up.
- Identify the affected endpoint from the audit log throttle/failure events.
- Open the tenant's webhooks settings (impersonate if needed).
- Check the Deliveries tab: how many queued? How many failed? What's the lastErrorMessage?
- If their endpoint is the bottleneck: contact the tenant, suggest scaling.
- If signature verification is failing: rotate signing secret, alert the tenant.
- Use API to retry in batches; avoid thundering-herd retries.
- For dead-letter deliveries that should be replayed: flag for manual reattempt once root cause is fixed.
Chapter 26 — Credential Leak Runbook
A tenant's API credential or webhook signing secret has been exposed (committed to public repo, posted in support ticket, leaked any other way).
- Confirm the leak: see the actual exposed credential.
- Impersonate the tenant's company_admin (with permission) and revoke the credential immediately. Add reason: "Exposed publicly on YYYY-MM-DD".
- Create a replacement credential with the same scope. Send it to the tenant securely.
- Audit the platform audit log for unusual access during the leak window.
- If the leak was a Resend or Stripe key, rotate at the provider as well.
- Document the incident: who, what, when, scope, response.
- Post-incident review with the tenant — how did the leak happen, how to prevent next time.
Chapter 27 — Replay Storm Runbook
An integration or test script is hammering an endpoint, generating a flood of throttled requests.
- Identify the source from the audit log throttle events.
- Disable the misbehaving endpoint or revoke the credential.
- Contact the integration owner (the tenant or one of their developers).
- Diagnose root cause (infinite loop, unbounded retry, runaway test).
- Re-enable when the loop is fixed.
- If the storm caused customer-facing pain, post-mortem.
Chapter 28 — Cross-Tenant Data Leak Runbook
Worst-case scenario: a tenant or customer reports they can see data from another tenant.
- Get screenshots and exact timestamps from the reporter.
- Capture URL, Firestore paths, exact data they saw.
- Reproduce in a controlled environment (impersonate carefully if needed).
- Identify the offending code path. Bug or config?
- Patch immediately if it's a bug. Lock down config if it's config.
- Audit who else might have seen what (search the access logs).
- Notify both tenants involved.
- If material data was exposed, follow legal/compliance breach notification process.
- Post-mortem mandatory.
New Employee Cheat Sheet
Chapter 29 — Your First Day
- Get your
system_adminaccount from your manager. Set a strong password. Add to password manager. - Log in to
/console/owner/tenants. Browse the tenant list. Get a feel for the scale. - Open one tenant. Read every section without changing anything. Understand what's there.
- Read TRENVAR_FOUNDATIONS.html — what your tenants are looking at.
- Read this manual cover-to-cover. Yes, all of it.
- Shadow your manager through one tenant onboarding before doing one yourself.
- Shadow them through one support ticket triage.
- Ask questions. The platform is small — anyone will help.
Chapter 30 — Common Gotchas
- Slug is immutable. Triple-check before saving a new tenant.
- Disabling a module hides screens but doesn't delete data. Tenant data persists across module toggles.
- Free Platform Access is sticky. Once granted, no one ever audits it. Quarterly review.
- Stripe webhook signing matters. If you regenerate keys, the webhook stops working until you update both ends.
- Impersonation is logged forever. Don't be the person who shows up in someone's audit and can't explain why.
- Suspending without warning destroys trust. Communication first.
- "customer" is overloaded. "Trenvar's customer" = tenant. "Tenant's customer" = downstream. Always clarify.
- The owner login email is hard to change. Get it right at provisioning.
Chapter 31 — Where to Escalate
| Situation | Escalate to |
|---|---|
| Cross-tenant data leak | Platform engineering lead + legal |
| Active credential leak | Security team + tenant's company_admin |
| Suspected payment fraud | Finance + Stripe |
| P0 incident (full outage) | On-call engineer + leadership |
| Tenant threatening churn | Customer success + sales |
| "This tenant is doing something we don't allow" | Trust & safety / legal |
| "I touched something I shouldn't have" | Your manager — immediately |
Appendix A — Owner Console Paths
| Path | Screen |
|---|---|
| /console/owner/ | Owner home |
| /console/owner/tenants | Tenant list + lifecycle |
| /console/owner/tenants/[tenantId] | Tenant detail (status, modules, owner login) |
| /console/owner/plans | Plans + subscription run |
| /console/owner/modules | Module pricing config |
| /console/owner/audit | Platform audit log |
| /console/owner/analytics | Financial rollups, MRR/ARR, plan mix |
Critical APIs
| Endpoint | Purpose |
|---|---|
| POST /api/public/trial-signup | Public trial signup intake |
| POST /api/billing/stripe/webhook | Stripe events (incoming) |
| GET/POST/PATCH /api/owner/tenants/[tenantId]/credentials | Set up + reset owner login |
| POST /api/owner/billing/subscriptions/run | Run monthly subscription cycle |
| PATCH /api/owner/modules-pricing | Update pricing config |
| GET /api/owner/audit | Audit log feed |
| GET /api/owner/analytics/financial-rollups | MRR/ARR analytics |
| GET /api/cron/platform-subscriptions | Cron-driven trial conversion check |
Appendix B — Platform Permissions
| Permission | Default holder | Notes |
|---|---|---|
| platform.tenants.list / read | system_admin | Browse tenants. |
| platform.tenants.create | system_admin | Manual provisioning. |
| platform.tenants.update | system_admin | Edit tenant fields. |
| platform.tenants.suspend | system_admin | Suspend/resume. |
| platform.entitlements.configure | system_admin | Toggle modules per tenant. |
| platform.billing.read / update | system_admin | Platform billing. |
| platform.analytics.read | system_admin | MRR/ARR/churn. |
| platform.impersonation.start | system_admin | Begin impersonation. |
| platform.impersonation.write_enable | system_admin | Make changes during impersonation. Audit-loud. |
| platform.security.read | system_admin | Security events. |
| audit.security_events.read | system_admin | Same. |
Appendix C — Glossary (Employee Perspective)
Tenant — Our customer. One company that uses Trenvar.
Tenant's customer — A downstream customer of one of our tenants. We rarely deal with these directly.
Owner Console — The internal control plane at /console/owner/*.
system_admin — Your role. Platform-wide access.
OS bundle — A commercial package of modules (Warehouse, 3PL, Transport, Air Cargo, Commerce).
Module — A specific capability, billed individually.
Entitlement — The switch that turns a module on for a tenant.
Free Platform Access — Tenant flag that exempts them from platform billing.
Subscription Cycle — Monthly batch job that creates platform invoices for billable tenants.
Impersonation — Logging in as a tenant user (with audit trail) to debug or support.
Throttle event — Rate-limit hit. Surfaced in audit log.
Trial signup — Self-serve flow where a new tenant signs up and converts after 7 days.
Cross-tenant leak — A user seeing data outside their own tenant. Critical security incident.
End of Trenvar Platform Admin Manual · v1.0 · May 2026
Internal use only.