Skip to content
All work

Corporate Mental Health SaaS

Clínora Psi

B2B mental health platform connecting companies, employees and therapists, which I took from local development to a self-hosted production deployment with an automated CI/CD pipeline.

Overview

What the product does

A B2B corporate mental health SaaS platform that connects companies, their employees and therapists on one secure, confidential platform. It is a Turborepo monorepo with a Next.js frontend and an Express API running on Bun, live at clinorapsi.ao with the API on its own subdomain.

Problem

The problem it solves

The platform only ran in local development. Going live meant a reproducible way to build the monorepo, a secure single-server production setup with TLS and a firewall, and releases that didn't depend on someone building by hand on the server — all on a 2 vCPU, 4 GB VM.

My role

What I contributed

Production deployment and DevOps: containerising the Turborepo monorepo, provisioning and hardening the server, and automating every release through a GitHub Actions pipeline.

Solution

How the system was designed

Both apps are built as multi-stage Docker images on GitHub-hosted runners and pushed to GitHub Container Registry, so the server never compiles anything. Docker Compose runs Redis, the API, the web app, Nginx and Certbot with healthchecks, restart policies and persistent volumes. Nginx routes the two domains, redirects HTTP to HTTPS and terminates TLS 1.2/1.3 with Let's Encrypt certificates, while PostgreSQL runs on Neon.

Architecture

System architecture

ClientApplicationServicesDataExternalHTTPSProxyAPIVerifyQueriesCacheTokensPaymentsClientCompany · Employee · TherapistNginxReverse proxy · TLSNext.jsStandalone containerExpress APIBun · ts-restBetter AuthSessionsPostgreSQLNeon · PrismaRedisCache · AOFAgoraVideo sessionsAppyPayPayments

Key features

What it does in practice

CI/CD pipeline

Every push to main builds the server and web images on GitHub Actions, pushes them to GHCR, then deploys over SSH: pull the new images, recreate the containers with docker compose, and run prisma migrate deploy.

Challenges

The interesting engineering problems

  • Making the monorepo build in Docker
    Problem
    Production builds failed inside Docker: Turborepo's strict env mode hid backend variables, the workspace lockfile didn't match, over-strict Zod env validation rejected build-time config, and removed lucide-react brand icons broke the frontend build.
    Approach
    Scoped backend env vars per task in turbo.json, fixed the lockfile mismatch, corrected the Zod env schema and replaced the removed icons, so the same build passes locally and in CI.
  • Keeping secrets out of images
    Problem
    The build needs credentials, but anything copied into a Docker layer can be pulled back out of the published image.
    Approach
    Used BuildKit secret mounts at build time and kept every credential in GitHub Actions Secrets, injected only at build and deploy time.
  • Shipping without guesswork
    Problem
    On a single small server, wiring an untested image straight into production turns every mistake into downtime.
    Approach
    Tested each image as a minimal standalone container first — boot, Redis connectivity, HTTP responses and static assets — before adding it to the Compose stack.
  • Going live without breaking email
    Problem
    The domain's DNS zone already carried the company's email records, and a careless change would have taken mail down.
    Approach
    Added only the A records for the frontend and the API, leaving the existing email records untouched.

Technology

The stack behind it

  • DockerContainerization
  • GitHub ActionsCI/CD Pipelines
  • NginxReverse Proxy & TLS
  • Next.jsReact Framework
  • BunRuntime & Package Manager
  • PostgreSQLRelational Database
  • TurborepoMonorepo Builds
  • ReactFrontend UI
  • TypeScriptType Safety
  • Tailwind CSSStyling System
  • Shadcn UIComponent Library
  • Express.jsHTTP Framework
  • NeonServerless Postgres
  • Prisma ORMType-Safe ORM
  • RedisCache & Queues
  • ZodSchema Validation
  • Better AuthAuthentication
  • Agora RTCRealtime Audio & Video
  • Let's EncryptSSL Certificates
  • Ubuntu ServerSelf-Hosted VPS