Solavel Solavel Docs

Logs and Error Channels

docs/admin-support/logs-and-errors.md

Audience: support engineers, admins Difficulty: admin only

What this covers

Where the platform records what happened, what each log gives you, and how to find the row that matches a user complaint.


Quick reference

Channel URL Best for
System Event Logs /admin/system-event-logs Cross-app audit trail (parent ⇄ finance)
Form Monitor /admin/form-monitor "User clicked submit but nothing happened"
User Monitor /admin/user-monitor "Who is online right now?"
Admin Errors /admin/errors Captured runtime exceptions surfaced to users
Beta Reports (admin queue) /admin/beta-reports User-submitted feedback / bug reports
Telegram error notifier (chat) Real-time push on uncaught exceptions
Laravel logs storage/logs/laravel.log (each app) Stack traces, raw exceptions
Apache logs /var/log/apache2/{access,error}.log HTTP-level failures, 5xx
Solabooks Activity Logs /finance/admin/activity-logs (in-tenant) Per-document edit trail
Portal Access Logs tenant DB portal_access_logs Customer-portal opens

System Event Logs (/admin/system-event-logs)

Three routes:

  • index — list with filters (event type, source app, organization, date).
  • show — single event detail.
  • ingestPOST /api/system-events/ingest — receives events from the finance app via HMAC.

What it captures. Events the finance app emits to the parent for audit. Examples:

  • Tenant provisioning started/completed.
  • A user's role changed in finance.
  • A subscription was applied/cancelled.
  • A workspace handoff happened.

What it does NOT capture. Per-document edits inside the tenant DB (see Solabooks Activity Logs for those).

How to use. Filter by organization_id (or client_id), pick a narrow time window. Each row links back to the user and the source controller.

Note. The audit flagged this ingest endpoint as having only api middleware (no HMAC) — confirm the controller verifies the signature.


Form Monitor (/admin/form-monitor)

Captures form-submit telemetry. The finance app's FormEventController forwards submit_attempt, submit_success, submit_failure events to the parent.

Best ticket type. "I clicked Save and nothing happened."

What you get. For each tracked form:

  • The form name (route name).
  • User and organization.
  • Validation errors (when the failure was a 422).
  • Server response time.

If the user reports a hang, look for matching submit_attempt rows without a paired submit_success or submit_failure — that's the classic broken-form signature.


User Monitor (/admin/user-monitor)

Live presence ping. Each authenticated request from a user updates their last_seen_at. The page tails the table.

Best ticket type. "Did anyone make this change in the last hour?"

What you get. Email, role, last URL, last activity timestamp, client.


Admin Errors (/admin/errors)

The parent app exposes POST /error-report (open) and POST /api/errors/ingest (HMAC). Either path writes a row to the errors table.

What you get. Stack class, message, file, line, request URL, timestamp, organization (if available).

Best ticket type. A user reports a 500. Filter by their email and the timestamp; find the matching row; pull the stack.

The Telegram error notifier (configurable in config/telegram.php or similar) pushes the same rows to a Telegram chat in real time. Useful for catching outages.


Beta Reports (/admin/beta-reports)

User-submitted feedback. The flow:

  1. User clicks Send Beta Feedback (top right of finance UI when tracker.feedback_widget or similar is on).
  2. Solabooks app forwards to parent via POST /api/beta-reports (HMAC-signed).
  3. Admin queue at /admin/beta-reports.

Each report has: title, description, screenshot URL, user, org, app. Admin can mark resolved or wont-fix.

Best ticket type. "I submitted feedback last week and never heard back" — find their row.


Laravel logs (storage/logs/laravel.log)

Both apps write here. Daily rotation. Look in:

  • /var/www/html/solavel/storage/logs/laravel.log (parent)
  • /var/www/html/solavel-finance/storage/logs/laravel.log (finance)

Tail commands.

tail -200 /var/www/html/solavel/storage/logs/laravel.log
tail -200 /var/www/html/solavel-finance/storage/logs/laravel.log
grep -A 5 "<email>" /var/www/html/solavel/storage/logs/laravel.log

Search by: email, organization id, exception class, request URL.


Apache logs

For 5xx responses or strange redirect behaviour, Laravel may not have captured anything (Apache rejected before PHP). Look in:

  • /var/log/apache2/access.log — every request (status, URI, IP).
  • /var/log/apache2/error.log — virtual-host errors, fcgi crashes.

The vhost config is at ops/apache/solavel.com.conf — useful when debugging mounting issues for the /finance/ path.


Solabooks Activity Logs (in-tenant)

Inside the finance app at /finance/admin/activity-logs. Per-document edit trail kept by Activity/ActionLogController.

What you get. Every CRUD on invoices, bills, journal entries, payments, etc. Plus posting/unposting events. Plus deletes (soft and hard).

This is the only log that surfaces per-tenant document history. The parent-side System Event Logs do not see inside the tenant DB.

Search by: user, document type, document id, date range.


Portal Access Logs (in-tenant)

Tenant DB table portal_access_logs. One row per customer-portal open. Fields: customer id, document id, IP, user agent, opened_at.

Best ticket type. "Customer says they never received the link" or "Customer says the link doesn't work."

If the table is empty for that document: customer never clicked. Otherwise: each open is timestamped — you can see if and when they got in.


Putting it together

Walking from a complaint to a row:

  1. Capture timestamp.
  2. Apache access.log — confirms the request hit the server.
  3. Laravel log — captures any exception.
  4. Admin Errors — same exception, indexed by user.
  5. Form Monitor — only if a form submit was involved.
  6. System Event Logs — only if it was a cross-app event.
  7. Activity Log (in finance) — only for per-document edits.

If none of those have a row, you're looking at a problem outside the captured surface — likely client-side (browser, network, browser extension blocking JS).


Related

Source: docs/admin-support/logs-and-errors.md ← All documentation