Solavel Solavel Docs

Customer portal

docs/solavel-finance/customer-portal.md

Who can use this: the customer portal is built for your customers — the people you sell to. They sign in with their own email and a password your organization invites them to set up. Inside Solabooks, the team members who manage portal links and customer accounts are Owner, Manager, and Accountant. URL / Route: two distinct entry points exist:

  • Account-based portal at /customer-portal/* (customer-portal.* routes) — dashboard, invoices, quotes, orders, payments, settings.
  • Token-based document links at /i/{token} (portal.* routes) and the legacy alias /portal/{token} — single-document share links sent in document emails. A separate route /q/{token} (quote.customer.*) exists for the older standalone quote share. Plan / feature gate: none — customer-portal access is part of every plan. Permissions (internal): the portal does not consume Solabooks's role-permission system; customer-portal accounts are scoped to one customer in one organization. Internal staff don't need a special permission to send a portal link — sending an invoice/quote by email automatically issues a link.

Purpose

The customer portal is the read-only (mostly) view your customers see when you share a quote, invoice, sales order, or statement with them. Two flavours coexist:

  • Token-based links are stateless one-document URLs you send by email — no signup required. Best for one-off quotes or invoices.
  • Account-based portal is a real login with email + password, where a customer can browse all their open and historical documents at once.

Most organizations start with token-based links and turn on the account-based portal later when their customers ask for a single login.

Token-based document links — /i/{token} and /portal/{token}

Used automatically when you click Send by email on an invoice, quote, sales order, sales receipt, refund, credit note, or statement.

What the customer sees

Opening the link shows the document on a clean public page with:

  • Download as PDF (portal.pdf).
  • For quotes: Accept (portal.quotes.accept) and Decline (portal.quotes.decline) buttons.
  • For invoices/statements: a "Pay now" path is reserved but not always wired up to a payment gateway in this build.
  • A Settings link (portal.settings) where the customer can set or change a password to access the account-based portal.
  • An End access action (portal.end) that revokes the link from the customer's side.

Lifecycle and security

  • The token is a hashed random string stored against customer_portal_links. The raw token is in the email URL only.
  • Token lifespan: 24 hours. After that the link returns "Link expired" and the customer can request a fresh one (see below).
  • The token is bound to the document, the customer, and the organization — Solabooks verifies all three before allowing access (defence in depth).
  • The customer can ask for a new link via Request access (portal.request-access) and Send again (portal.send-again), both rate-limited (throttle:portal-recovery).
  • Read endpoints are rate-limited too (throttle:portal-public).
  • The legacy alias /portal/{token} accepts the same tokens for older URLs already in customer inboxes.

When you send a document

On posted documents, the Send by email action:

  1. Generates a fresh customer_portal_links row with a new 24-hour token.
  2. Builds the email using your active PDF template (if pdf_templates_enabled is on), with the token URL embedded.
  3. Sends and logs the send on the document's activity tab.

Account-based portal — /customer-portal/*

This is a full login page set scoped to one customer in one organization.

Routes (17 total)

  • customer-portal.login (GET) and customer-portal.login.submit (POST, throttled customer-portal-login).
  • customer-portal.logout.
  • customer-portal.setup and customer-portal.setup.submit — first-time password setup.
  • customer-portal.forgot-password and customer-portal.forgot-password.submit — password reset request.
  • customer-portal.reset-password.show (GET, with token) and customer-portal.reset-password.submit (POST).
  • customer-portal.dashboard — landing page with totals and the most recent activity.
  • customer-portal.invoices — open + paid invoices.
  • customer-portal.quotes — pending and historical quotes.
  • customer-portal.orders — sales orders.
  • customer-portal.payments — payments the customer made or had refunded.
  • customer-portal.settings and customer-portal.settings.update.
  • customer-portal.settings.password.

Lifecycle

  • Setup tokens (customer_portal_setup_tokens) and password-reset tokens (customer_portal_password_reset_tokens) both expire after 60 minutes. Tokens are stored hashed and consumed transactionally so they cannot be reused.
  • A customer's password is local to their customer_portal_accounts record — there is no cross-organization sign-in for customers.
  • All POST endpoints are rate-limited (throttle:customer-portal-login and throttle:customer-portal-password).

Inviting a customer to the account portal

  1. Open the customer's record (/finance/customers/{id}).
  2. Click Invite to customer portal. Solabooks generates a 60-minute setup token and emails the customer a link.
  3. The customer follows the link, sets a password, and lands on customer-portal.dashboard.

If the customer never finishes setup, you can re-issue an invitation from the same screen.

Quote-only public link — /q/{token}

A separate, narrower share URL exists at /q/{token} (quote.customer.show, accept, decline). It is used for older quote-share emails that pre-date the canonical /i/{token} routes. The throttle bucket is throttle:quotes-public.

Behaviour and rules

  • Token-based links are per document. Sending the same document twice issues two tokens.
  • Account-based portal is per customer. One account can see all documents of that one customer.
  • A customer who has both a portal account and a token link will see the token-link page when they click an emailed link; the portal login is not required.
  • Multitenancy: each portal is scoped to one organization. A customer who works with two of your orgs will have two separate portal accounts.
  • The portal does not have its own permission keys in finance_permissions.php; access is enforced by middleware (portal.token, customer-portal.tenant, customer-portal.auth, customer-portal.guest) and by the portal services (PortalLinkService, CustomerPortalTokenService).

Permissions / restrictions

  • Customers authenticate against customer_portal_accounts rows; they do not see Solabooks roles.
  • Internal staff do not need a separate permission to send portal links — sales.invoices.send, quotes.send, etc. cover the act of sending the email.

Related

Source: docs/solavel-finance/customer-portal.md ← All documentation