Skip to content

Multi-bank remittance + public invoice/quotation share links — Production Readiness Audit ​

FieldValue
Date2026-10-10
StatusGo for production
ScopeSettings → Branding invoice_bank_accounts (multi-account enable/disable); guest share links for invoices & quotations (view + branded PDF); catalog invoices 1.11.0 → 1.12.0, quotations 1.9.0 → 1.10.0
CompanionInvoices · Quotations · Tenant settings · Upgrade · CHANGELOG

Executive summary ​

Workspaces can store up to ten remittance bank accounts and toggle which appear on invoice PDFs / guest share pages. Staff with send permission can mint opaque 90-day public share links; guests view the document and download the same branded Dompdf as CRM without logging in. Void (invoice) and reject/expire (quotation) clear tokens. Legacy flat invoice_bank_* keys still hydrate and sync from the first enabled account (cleared when none are enabled).

Go / No-Go: Go.

GateResult
Platform freeze (guest pages under existing SPA hash routes; no parallel shell)Pass
Token opacity (SHA-256 hash in DB; plaintext only in mint URL)Pass
Expiry (90 days) + void/reject/expire clear linkPass — Pest
Entitlement-gated public routes (generic 404)Pass
Rate limits (document-share / document-share-pdf by IP)Pass
Multi-bank PDF + payment_bank.bank_accounts (enabled only)Pass — Pest + headed e2e
Legacy sync when all accounts disabledPass — remediations A1
Catalog migrate-only + CatalogSeeder companionPass — 1.12.0 / 1.10.0
Docs + CHANGELOG same deliveryPass
Playwright headed one-sessionPass — npm run test:e2e:billing-share:headed (4/4)
Pest (banks + share + catalog bump)Pass

Findings ​

Closed (audit remediations) ​

IDSeverityFindingResolution
A1MediumtoLegacyFlat() fell back to a disabled account when none were enabledSync only from enabled accounts; all-disabled clears legacy keys + Pest
A2Mediumdocument-share throttle keyed by authenticated user id when presentAlways key by IP (parity with PDF limiter)
A3MediumNo deployment readiness page / developer-guide lag on public share + multi-bankThis page + invoices developer guide + upgrade + VitePress index
A4LowBank remove control lacked accessible name for e2earia-label="Remove account N" + headed cleanup uses role

Accepted (intentional / ops — not defects) ​

IDSeverityNotes
R1InfoGuest JSON includes contact_name / company_name for document context; SPA bank block shows enabled remittance only
R2InfoCopy share link is on dedicated record pages (not list peeks) — matches billing peek rules
R3OpsDeploy Backend + Frontend together; migrate-only — do not db:seed
R4InfoQuotation Copy accept link remains separate from public share

What shipped ​

Backend ​

  • Migration 2026_10_09_221135_add_public_view_tokens_to_billing_documents_table (+ catalog bumps)
  • InvoiceBankAccounts + settings validation / TenantSettingService sync
  • PublicInvoiceShareController / PublicQuotationShareController; mint on invoice/quotation services
  • PDF Payment Information loops enabled bank_accounts
  • Rate limiters document-share / document-share-pdf
  • Pest: InvoiceBankAccountsSettingTest, CustomerInvoicePublicShareTest, QuotationPublicShareTest, InvoicesQuotationsPublicShareBumpTest

Frontend ​

  • Settings → Branding multi-bank UI
  • Invoice/quotation Copy share link; guest /#/view/invoices|quotations/:token + PDF
  • Playwright: e2e/tests/billing/billing.share-and-banks.headed.spec.ts (test:e2e:billing-share:headed)

Docs ​

  • User / API / tenant-settings / changelog / upgrade / this readiness page

Test evidence ​

herd php artisan test --compact tests/Feature/Tenant/Settings/InvoiceBankAccountsSettingTest.php tests/Feature/Tenant/CustomerInvoice/CustomerInvoicePublicShareTest.php tests/Feature/Tenant/Quotation/QuotationPublicShareTest.php tests/Feature/Central/Catalog/InvoicesQuotationsPublicShareBumpTest.php

Pest: 12 passed (81 assertions).

E2E_BROWSER_CHANNEL=chrome E2E_VIDEO=off npm run test:e2e:billing-share:headed

Playwright headed (--workers=1, one workspace login): 4 passed — banks (one disabled), invoice validation + share, guest invoice PDF, quotation share + guest PDF.

Operator checklist ​

  1. Deploy Backend → php artisan migrate --force (do not db:seed)
  2. Confirm catalog: invoices 1.12.0, quotations 1.10.0
  3. Deploy Frontend SPA
  4. Smoke: Settings → Branding two banks / one disabled → send invoice → Copy share link → guest view + PDF (only enabled bank) → void → link 404; same for sent quotation share (accept link still works)

Official documentation for the EloSync SaaS Platform.