Solavel Solavel Docs

Support Playbook

docs/admin-support/support-playbook.md

Audience: support engineers, on-call admins Difficulty: admin only

What this covers

First-line triage for the most common Solavel and Solabooks support tickets. For each scenario: the questions to ask first, what data to grab, and the page in this docs tree that fixes it.

This is the page you open when a ticket comes in. The other admin pages go deeper.


Triage checklist (always do these first)

Before you change anything, capture:

  1. Username / email — full email, not just first name.
  2. Tenant / client id — visible in the URL when they're signed in, or in /admin/clients.
  3. Organization slug or id — the org they were trying to use.
  4. The literal error message they saw — copy/paste, don't paraphrase.
  5. Browser and device — sometimes a CSP or storage issue.
  6. Timestamp — within ~1 minute, so you can find the request in logs.

Then check:

  • Are they signed in? Is their email verified?
  • Do they have a row in user_organizations for the org they're trying to access?
  • Does their tenant DB exist? (tenant_<clientId> should be there.)
  • Is the relevant feature flag on for their org?

Common ticket patterns

"I can't sign in."

Ask: what URL? What error?

Likely causes:

Symptom Cause Fix
"These credentials do not match" Wrong password Send password reset (/forgot-password)
"Email not verified" Email never confirmed /admin/clients > [user] > Resend verification
"Account is disabled" users.is_active = false Re-enable from /admin/admins (super-admin only)
Login loop Cookie / session storage broken Ask for a hard refresh or different browser
"SSO token expired" between parent and finance Handoff token TTL exceeded Sign in fresh from parent

See access-troubleshooting.

"I get 'No organization found' after login."

The user has no row in user_organizations. Most often happens when:

  • The user signed up but never created an organization.
  • The user accepted an invite but the membership write failed.
  • A migration removed their membership.

Fix. Go to /admin/clients > [their client] > Members. Add them. Or have the org owner re-invite from /portal/orgs/{org}/members.

"I can't see invoices / quotes / sales orders / etc."

Ask: what menu item are you trying to click?

Diagnose: is the feature off for the plan, or off for the org?

  1. /admin/plans > [their plan] — is the relevant tracker.<feature> enabled?
  2. Tenant DB > feature_flags table — is the org's row set to enabled=true?
  3. Their finance role — does it have the right perm: permissions?

See plan-feature-debugging.

"The customer says the link doesn't work."

Ask: when did you send it?

  • More than 24 hours ago → expired. Send again from the document.
  • Less than 24 hours → check customer_portal_links.revoked_at. Was it manually revoked?
  • The customer's email address may have changed. Confirm against the customer record.
  • Check portal_access_logs for that document — did the customer click? From which IP?

See customer-portal/secure-document-links.

"Posting fails with 'Required account missing'."

The org's chart of accounts has no default for the account the posting needs. Most common: AR, AP, Output VAT, Bank.

Fix. Owner opens Settings > Accounting Defaults and picks an account for each role. Save. Retry post.

"Period locked" / "I can't post a backdated invoice."

The invoice date is on or before the lock date. Either:

  • Move the invoice date forward, or
  • Owner moves the lock date forward in Settings > Periods (note this is one-way — going backwards needs periods.unlock).

"Trial Balance doesn't balance / report total mismatch."

Rare. Causes:

  • An out-of-balance journal that bypassed validation (legacy data).
  • A partial period close.
  • A tenant DB that was restored from backup and is out of sync.

Action. Drill into the GL for the offending account. Find the unmatched journal. Escalate to engineering if you can't resolve in 15 minutes.

"I don't see my changes after upgrading my plan."

Plan upgrades are written by the parent app. The finance app reads the entitlements snapshot when the user's session refreshes.

Fix. Ask the user to sign out and back in. If the issue persists, run the parent's subscriptions:resync --client=<id> command (or trigger via /admin/clients).

"I lost data."

Stop and capture. Before any further action:

  • What records are missing?
  • When were they last seen?
  • Who is the user that last touched them?

Check:

  • activity_logs for the document type.
  • system_event_logs for org-level events around the timestamp.
  • Soft-deleted rows — deleted_at IS NOT NULL for the table.

Most "data lost" tickets are: archived not deleted; filtered out by a date range; visible only to a different role; or the user is in a different org now.

True data loss escalates to engineering immediately.


Data to collect for escalation

When handing off to engineering, attach:

  1. Triage output (above).
  2. Direct URL of the failing page.
  3. Browser console errors (F12 > Console > screenshot).
  4. Server log lines for the timestamp window: tail of storage/logs/laravel.log on both apps.
  5. Output of:
    • php artisan route:list --json | grep <route-name>
    • php artisan tinker snapshot of the relevant model.

What you can do without engineering

  • Reset a user's password (admin > admins > [user] > reset).
  • Re-enable a user.
  • Re-add a user to an organization.
  • Toggle a feature flag for one org (Settings > Features on the org).
  • Move a lock date.
  • Re-issue a customer portal link (Send again).
  • Revoke a customer portal link.
  • Resync a subscription.
  • Re-run tenant provisioning (superadmin:setup --client-id=<id> on the finance app).

What you should NOT do

  • Run raw SQL against tenant DBs.
  • Change a user's role in user_organizations directly (always use the UI).
  • Delete rows from customer_portal_links (revoke instead).
  • Edit app.key or services.tap.secret — those break the system.

Related

Source: docs/admin-support/support-playbook.md ← All documentation