NeoFlow Hub
Self-Hosted Workspace Platform
A complete self-hosted team workspace platform unifying team chat (Slack replacement), Kanban project boards (Trello/Jira replacement), and an isolated white-labeled client portal (ManyRequests replacement) - into one fully owned, zero-vendor-dependency system. 82 features. 18-week delivery. ~$15/month to run vs. $50–200/month on SaaS.
SaaS charges per seat. Self-hosted charges once.
Slack + Trello/Jira + ManyRequests (or SuiteDash) combined cost $50–200/month for a small agency team. They're also three separate logins, three separate data sources, and three vendor contracts that can change their terms. NeoFlow Hub replaces all three with one self-hosted platform on a single VPS at ~$15/month running cost.
Full Ownership
No vendor lock-in, no recurring per-seat fees.
Brand Control
Client portal on your own domain - not a third-party tool.
Data Sovereignty
Messages, files, and project data on your own VPS.
Cost Efficiency
~$15/month VPS vs. $50–200/month SaaS stack.
Three SaaS tools. One platform.
Team Chat
Project Management
Client Portal
Full-stack workspace engineering.
Real production code from NeoFlow Hub.
Custom WebSocket server handles channel subscriptions, DM routing, and presence tracking. Each team workspace maps to isolated namespaces - client portal traffic is fully separated from internal team channels.
1import { WebSocketServer, WebSocket } from "ws";2import { verifyJwt } from "@hub/auth";34const wss = new WebSocketServer({ port: 3100 });5const rooms = new Map<string, Set<WebSocket>>(); // channelId → connected clients67wss.on("connection", async (socket, req) => {8 const token = new URL(req.url!, "ws://hub").searchParams.get("token");9 const user = await verifyJwt(token ?? "");10 if (!user) return socket.close(4001, "Unauthorized");1112 socket.on("message", async (raw) => {13 const msg = JSON.parse(raw.toString());1415 if (msg.type === "JOIN_CHANNEL") {16 const room = rooms.get(msg.channelId) ?? new Set();17 room.add(socket);18 rooms.set(msg.channelId, room);19 broadcastPresence(msg.channelId, user.id, "ONLINE");20 }2122 if (msg.type === "SEND_MESSAGE") {23 const saved = await db.messages.create({ data: { ...msg, userId: user.id } });24 rooms.get(msg.channelId)?.forEach(client =>25 client.send(JSON.stringify({ type: "NEW_MESSAGE", data: saved }))26 );27 }28 });2930 socket.on("close", () => {31 rooms.forEach(room => room.delete(socket));32 broadcastPresence("*", user.id, "OFFLINE");33 });34});Turborepo monorepo. Isolated portals.
Main workspace Next.js app (team login, chat, boards)
Client portal subdomain app (isolated session, filtered data)
Custom WebSocket server (Node.js, port 3100)
9 core tables. One relational database.
6 phases. 9 sprints. Signed off at each gate.
Foundation & Validation
Auth, RBAC & Workspace Core
Chat + Kanban Core
Advanced Features + Client Portal
Power Features & Admin
QA, Polish & Launch
Real-time. Self-hosted. Fully owned.
Channels (Public & Private)
Per-project channels, department channels, and general channels. Public channels visible to all workspace members. Private channels require explicit invite.
Threads
Reply in-thread to any message without interrupting the channel feed. Thread count and latest reply shown inline.
Direct Messages
1:1 DMs and group DMs with up to 8 participants. Notification badge on sidebar for unread DMs.
File Sharing (MinIO)
Drag-and-drop file upload to MinIO S3-compatible storage. Images, PDFs, and design files inline-rendered in chat.
Presence Indicators
Online / Away / Do Not Disturb status broadcast via WebSocket. Typing indicators shown in real-time.
Message Search
PostgreSQL full-text search (tsvector + pg_trgm) across all channels. Filter by channel, sender, and date range.
Your brand. Your domain. Your client's window.
Clients access a clean, professionally branded portal - completely separated from internal team workspace. They see only what the team has explicitly toggled as 'Client Visible'. Internal notes, private threads, and in-progress drafts are never surfaced.
Isolated Subdomain
Client portal runs on portal.[your-domain].com - not a shared third-party platform URL. Your brand, your domain.
Task Visibility Toggle
Every Kanban card and file has a 'Client Visible' toggle. Internal work-in-progress is hidden until the team explicitly shares it.
Approval Workflow
Clients review submitted deliverables and action with Approve or Request Changes. Status tracked on the team's board in real-time.
File Deliverables with Versioning
Design files, reports, and documents shared to the client portal with version history - client always sees the latest, with access to previous versions.
Client Notification Preferences
Clients configure which events they want notified on: new deliverable, approval requested, message. Email and in-portal notification channels.
Zero Internal Leak Guarantee
Next.js middleware + clientId context injection ensures every database query in portal mode is automatically scoped to client-visible records only.
Enterprise security. Self-hosted simplicity.
WebAuthn / TOTP 2FA
Time-based OTP or hardware security key 2FA enforced for all admin accounts. Optional for all workspace members.
Immutable Audit Log
Append-only audit_log table captures every security-relevant action: login, permission change, file access, client portal data access.
Portal Isolation (Middleware)
Client portal middleware injects clientId context - impossible for a portal session to access another client's data without explicit DB query manipulation.
End-to-End TLS (Cloudflare)
All traffic terminated at Cloudflare edge with TLS 1.3. Internal VPS communication via Docker bridge network - no public exposure of database or Redis ports.
Every sprint ships to staging first.
Unit Tests (Vitest)
- tRPC procedure input validation
- Risk/permission logic
- Utility functions (date, string, auth helpers)
Integration Tests (Playwright)
- Chat flow: send message, thread reply, file upload
- Board flow: create card, move, assign, due date
- Client portal: login, visibility filter, approval
Performance Gates (Lighthouse)
- Performance ≥90 on staging
- Accessibility ≥90 (WCAG AA)
- LCP < 2.5s on 3G throttle (Next.js ISR pages)