Skip to main content

Documentation

No results found.
Features

Client Portal

The Client Portal turns the member area into a real client workspace: the site owner shares files and deliverables with a client (and clients send files back), stored privately and downloadable through the member portal or a tokenized guest...

The Client Portal turns the member area into a real client workspace: the site owner shares files and deliverables with a client (and clients send files back), stored privately and downloadable through the member portal or a tokenized guest link — and asks clients to sign off on work with approval requests they can approve or send back with change notes, no account required.


The problem

Agencies and freelancers deliver work over email attachments, Dropbox links, and "does this look good?" threads. Files get lost, approvals live in someone's inbox, and there's no record of who signed off on what, when. Dedicated client-portal SaaS solves it — for another monthly subscription and yet another login for the client.

The fix

A self-contained feature module under app/Features/ClientPortal/ adds the two missing pieces to the member dashboard the CMS already has (invoices, orders, courses):

  1. File sharing / deliverables — share files with a client both ways, stored on the private disk (never a web path), downloadable via the member portal or a tokenized guest link.
  2. Approval requests — ask a client to approve something (optionally with an attached file); they approve or request changes with a comment, through the member portal or a tokenized guest link. Exactly one response is recorded per request (atomic claim), with the responder's name, IP, and timestamp.

Clients are identified by lowercased email — the established cross-feature linkage (the same way the invoicing billing portal matches members to invoices). No linking step, no foreign keys into the members table.

Like every addon, it's structured as a feature module gated by feature:client_portal middleware. The service provider boots unconditionally; routes 404 and the sidebar entry hides when the feature is off. Toggling it on runs the module's migrations. Disabling preserves all data.

What the dashboard gets

One page under Dashboard → Client Portal (Manager and up; Settings is Admin-only), with two tabs:

  • Files — every shared file with recipient, title, filename + size, direction (To client / From client), download count, and uploaded date/by. Row actions: Copy guest link, Download, Delete (confirm modal; removes the disk file too). Share a file opens a modal: recipient email (with autocomplete suggestions drawn from invoicing clients, CRM contacts, and member emails — whichever features are enabled), the file, an optional title (defaults to the filename) and note, and a send notification email toggle (default on).
  • Approvals — every request with recipient, title, status badge (Pending / Approved / Changes requested), attached file, responded date, and a response-comment preview. Row actions: Copy guest link, Resend email, Reopen (clears the response so the client can respond again — confirm modal), Delete (confirm modal). Request approval opens a modal: recipient email (same suggestions), title, description, an optional attach-a-file select (files already shared with that recipient), and a send email toggle (default on).
  • Settings (admin only) — the owner notification email (defaults to the Business settings email), a client uploads toggle (default on), and the max upload size in MB (default 20, capped at 100).

The main dashboard also gets a Client Portal card: pending approvals count plus client uploads in the last 30 days.

What the client sees

When member accounts exist (Memberships, Ecommerce, Real Estate, Courses, or just the Client Portal itself — enabling the portal alone activates member login/registration), the member dashboard shows a Files & approvals card linking to:

  • /members/files — every file shared with (or sent by) their email, with direction badges, notes, and download buttons. When client uploads are enabled, a Send us a file card lets them upload back (optional note); the owner is notified by email.
  • /members/approvals — pending requests first (description, attached-file download, Approve and Request changes with a comment box — the comment is required when requesting changes), then the resolved history with status badges and comments.

No member account? Every file email carries a tokenized guest download link (/portal/files/{token}/download) and every approval request a tokenized guest respond page (/portal/approvals/{token}) — 40-character random tokens, no login needed. The guest respond page requires the responder to type their name.

File storage & security

  • Files live on the private local disk (storage/app/private/portal-files/{Y}/{m}/) — never web-reachable; year/month folders, like the media library.
  • Allowed extensions: images (jpg/jpeg/png/gif/webp/heic), pdf, txt, csv, zip, and Office documents (doc/docx/xls/xlsx/ppt/pptx). SVG is deliberately rejected — it's a script-capable format (same rule as ticket attachments).
  • Downloads are always attachment-disposition, so an uploaded HTML file can never render in the site's origin.
  • Guest downloads are authorized by the file's unique 40-char download_token; member downloads require the logged-in member's email to match the file's recipient (403 otherwise). Both stamp downloads_count + last_downloaded_at.
  • Deleting a file removes the disk file too. Approvals that referenced it keep their record without the attachment.

Approval integrity

Responding is an atomic claim on responded_at — the update only lands on a row that hasn't been answered yet, so a double-click, or a race between the member portal and the guest link, records exactly one response. Recorded: status, comment, responder name (the member's name, or the typed name on the guest page), IP, and timestamp. Reopen from the dashboard clears the response and lets the client respond again through the same link.

Emails

All transactional mail goes through the shared Marketing transport (CampaignMailer): the file shared email (guest download link + a member-portal pointer when Memberships is on), the approval request email (guest respond link), and owner notifications (client uploads and approval responses) to the configured notification address. If the transport isn't configured, sending fails gracefully — copy-link actions and the portal pages work without email entirely.

Statuses

Approvals: pending → approved or pending → changes_requested; Reopen returns any resolved request to pending. Files have no status — direction (to_client / from_client) plus download stats.

Limitations

  • Clients are matched by email only — files shared to a different address than the member's login won't appear in their portal (the guest link still works).
  • One file per approval request; share the file first to attach it.
  • No file versioning — share a new file (or delete and re-share) for revised deliverables.
  • Guest links don't expire; delete the file or approval to revoke access.