ProcusMeet - Design Documentation 1.0
Idea
procusMeet is a high-performance video consultation booking platform. what really makes it different from other consulting platforms is that procusMeet is solving two problems at once, one is to ease access to critical information for clients. it's a place you jump to when you need real experience information about anything. the second is to support experts to monetize their experience and market their skills. the solution to this is a calendly + google meet + public marketing with an emphasis on reliability, performance and clean architecture.
goals
- deliver a seamless, high-quality video consultation experience
- build a maintainable secure system
- support both individual experts and growing marketplace usage
highlevel overview

procusMeet is built as a monolithic go api server with a react single page application frontend. the backend is written in go using the gin framework and connects to a postgresql 16 database for persistence. minio (s3-compatible) handles object storage, and livekit handles all webrtc video infrastructure as an sfu. the frontend is a vite react spa that communicates with the go api and connects directly to livekit for media streams.
on the backend, the code follows a strict layered architecture with a one-way dependency flow. the entrypoint wires everything together. the router registers routes and middleware. handlers parse requests and write responses. services contain business logic and orchestration. the store layer handles raw sql. the domain layer holds pure go structs and business entities with zero dependencies. this layering prevents circular dependencies and makes testing straightforward.
call lifecycle

a call starts when a client requests a slot booking. the scheduling handler resolves the client from the jwt claims and delegates to the scheduling service. the service validates that the area of expertise belongs to the expert, checks no existing booking overlaps the slot, then creates a call record with status scheduled and a booking record with status pending. the expert gets an in-app notification. the expert can accept or decline โ accepting moves the booking to confirmed.
when it's time for the call, the user goes through a pre-call lobby which uses raw webrtc to capture local audio and video for a preview, with a mic level meter. on joining, it fetches a livekit token from the api and navigates to the video call page. the backend's livekit service creates a signed jwt using the livekit protocol auth library. the token grants access to a room named after the booking with publish and subscribe permissions โ both participants publish and subscribe, making the media flow through the sfu. the identity is the user id and the display name is the user's full name. the token has a configurable ttl defaulting to 2 hours.
on the frontend, a livekit room component connects to the livekit sfu websocket endpoint with the token. local participant hooks manage the local user's mic and camera tracks. track hooks subscribe to both local and remote camera and microphone tracks, rendering them with video and audio components. livekit runs as an sfu โ each participant publishes their media to the server and receives everyone else's forwarded streams. this means even in a two-person call, media goes through the sfu rather than peer-to-peer, which simplifies nat traversal and allows future recording, transcoding, or broadcasting. connection state hooks track the connection status. remote participant hooks detect when the other party leaves.
when the call ends, an api call sets ended at to now and flips both call and booking status to completed. the livekit room unmounts which cleanly disconnects from the sfu. experts can also add private notes attached to the call after it ends.
scheduling engine
the scheduling engine generates candidate 15-minute slots from two sources: recurring weekly availability defined per day-of-week with start and end time in the expert's timezone, and one-off overrides. it deduplicates overlapping slots and then subtracts any that overlap with existing calls that have pending or confirmed bookings. the comparison accounts for per-call duration minutes. the result is a list of slot start times returned as rfc3339 strings. when booking, it checks the slot is still free, then inserts a call row and a booking with status pending. the booking entity supports rescheduling โ an expert proposes a new time, the client accepts (which updates the call's scheduled time) or declines (which cancels the booking).
auth architecture
auth is built on hs256 jwt with an access and refresh token pair. the jwt service has configurable access and refresh expiry durations. tokens carry the user id, email, and role, and are generated and validated with golang-jwt. login authenticates the user via bcrypt compare, then generates the token pair. the refresh token is hashed with sha256 and stored in the database with an expiry. refreshing a token validates the old refresh, checks it exists in the db and hasn't expired, then rotates both tokens and deletes the old hash. logout deletes the token hash from the db, and logout all deletes all tokens for a user. google login verifies a google oauth access token against google's userinfo endpoint, then finds or creates the user โ linking existing users by email or creating a new user with a client or expert profile in a transaction. the auth middleware extracts the bearer token, validates it, looks up the user to check they're active, and sets the user context. role-based middleware gates specific endpoints. the refresh token is also set as an http-only samesite lax cookie on login and cleared on logout, with the cookie being secure in non-development environments. an endpoint returns all active sessions for a user by querying the tokens table.
payment
payment processing uses paystack with an escrow model to protect both sides. when a client books a call, the full amount is charged upfront and held by paystack โ it's not released to the expert yet. the payment record is created with status pending and linked to the call record. once the call is completed, the payment status moves to succeeded and the expert becomes eligible for payout. the platform takes a 10% service fee, so the expert receives 90% of the booking amount. if the call is cancelled before it happens โ whether by the client, the expert declining, or a no-show โ the payment is refunded in full to the client. the payout service tracks an expert's balance by summing completed earnings minus what's already been paid out. experts can request a payout at any time, which creates a pending payout record for processing through paystack's transfer api.
frontend architecture
the frontend is a react spa built with vite and typescript. state management is split between zustand for auth and global ui state, and react query for server state with caching and background refetching. routing uses react router v6 with separate layouts for protected routes and guest routes. the ui is built with radix ui primitives, tailwind css for styling, and shadcn/ui components.
infrastructure & deployment
in development, everything runs in docker compose โ the api server, postgres, minio, and livekit all spin up together. air provides hot reload for the go backend. in production, the app is deployed on coolify with traefik handling reverse proxy and tls termination. livekit runs on its own dedicated vm with udp ports open for webrtc traffic. database and object storage each have their own environments.
major design decisions
go was chosen over node.js for the backend because of its performance, concurrency model, and type safety. raw database/sql was preferred over gorm or sqlboiler for full control over queries and maximum performance. livekit was picked over mediasoup or custom webrtc because it delivers faster with proven reliability. the dual jwt with http-only refresh cookie balances security and user experience. zustand and react query were chosen over redux for simplicity and powerful caching out of the box. minio was chosen over directly using aws s3 for self-hosted control and lower cost.
scalability, performance & reliability
the api is stateless which makes horizontal scaling straightforward. sql queries are efficient with proper indexing. livekit handles all the media load. the main bottlenecks are the scheduling service which is cpu-intensive under high load, and postgres if it's not properly indexed or sharded. future plans include read replicas for heavy read pages, redis caching for expert listings and availability, and background workers for notifications and payouts.
security
cors uses a strict allowlist. there's a security headers middleware and rate limiting for both global and auth-specific endpoints. livekit tokens are scoped to the minimum permissions needed. all input is validated and sanitized. passwords are hashed with bcrypt and google oauth provides an alternative auth path.
failure modes & resilience
booking race conditions are prevented with database-level checks. if livekit goes down, the user sees a graceful degradation message instead of a crash. token refresh has smart logic with request queuing so multiple simultaneous refreshes don't conflict. database failures are handled gracefully with sentry monitoring in place.
what's missing & future work
notifications are currently in-app only and need real-time delivery via sse or websocket. advanced analytics and expert performance insights are planned. mobile apps with react native are on the roadmap.
conclusion
procusmeet is built with intentional architecture, strong separation of concerns, and production-grade patterns. the combination of a clean go backend, modern react frontend, and reliable livekit video creates a solid foundation for a high-quality expert consultation marketplace. the system prioritizes reliability and maintainability while delivering a good user experience.