Back to DevLog

Client Portal Polish: Real-time Updates, File Uploads, and Invoice Display

3 min read

Just wrapped up a massive feature sprint on AdminStack's client portal system, and I'm pretty excited about how it turned out.

The Problem: Static Portal Experience

Our client portals were functional but felt pretty dead - no real-time updates, clients couldn't share files with us, and they had to ask about invoices separately. Not exactly the smooth experience I wanted.

What Got Built

Real-time Everything

Implemented dual polling strategies: 15-second updates for portal data and invoices, 10-second polling for messages. Chat needs to feel snappy, but we don't need to hammer the server for progress updates.

Client File Uploads

Clients can now drop files directly in their portal. Built a new API endpoint that handles uploads to our Supabase storage with a separate {portalId}/client/ path structure. On our dashboard side, client-uploaded files get a clear "From Client" badge so we know what's what.

Invoice Integration

Portals now pull in invoice data with status badges and a running total of outstanding amounts. Clients only see sent/paid/overdue invoices - drafts stay hidden until we're ready.

Message Archiving

Added the ability to archive old messages (team-only action) with a toggle to show/hide archived content on both sides. Keeps active conversations clean.

The Polish Details

Spent time on the little things that make it feel premium:

  • Cards with subtle borders and rounded corners
  • Progress bars with CSS gradients and glow effects
  • Milestone dots that fill with teal when complete
  • Proper loading states with spinners
  • "Saved ✓" feedback that auto-resets after 2 seconds
  • Hover effects on file downloads

Technical Decisions

Had to add /portal to the public routes in middleware so client portals load without requiring login - seems obvious in retrospect but caught me initially.

For the database changes, added a source column to track team vs client files, and an archived flag for messages. Migration 038 handles the schema updates.

The dual polling approach feels right - messages need that responsive chat feel, but we don't need to poll project progress every 10 seconds.

What's Next

The portal system feels functionally complete now. Next step is getting some real client data flowing through it and seeing how it performs in the wild. Always feels different when actual users start clicking around vs my localhost testing.

Pretty solid day of shipping - from basic auth fixes to a full-featured client experience.

Share this post