Workvisual-studios-lens-nextjs-nestjs

Visual Studios Lens

I built the full platform behind Visual Studios Lens, a South Asian and Muslim wedding photography studio serving NY, NJ and CT.

Role
Full Stack Developer
Timeline
Mar 2026 – Present
Main stack
NestJS & Next.js
Visual Studios Lens — NestJS & Next.js project screenshot

Overview

I built the full platform behind Visual Studios Lens, a South Asian and Muslim wedding photography studio serving NY, NJ and CT. It is a public website plus Studio OS, the internal system the studio runs on, covering quotes, bookings, contracts, invoices, galleries and email.

The frontend is Next.js 16 and the API is NestJS 11 on PostgreSQL, with real-time updates over Socket.IO.

Problem

A wedding studio runs on scattered tools: a brochure site, a separate gallery host, an email inbox, spreadsheets for money, and chat threads for the team. Clients get messages from five places, and the studio cannot see one client's whole story in one screen.

Approach

I built one platform with two faces. The public site is fast and SEO-ready, and Studio OS gives the team ten connected apps over a single API. Clients never need an account: every quote, contract, invoice and gallery opens from a private link. Real-time updates and email run on the same backend, so nothing lives in a separate tool.

Outcome

Frontend routes
112
API endpoints
281
Database tables
43
Studio OS apps
10
Merged pull requests
296
Lines of TypeScript
~98k

What I built

  • Public website with a cinematic portfolio, love stories, journal, prices, packages, store and video pages, all editable from the admin
  • SEO built in: structured data, sitemap, per-page metadata and fallback content so pages never render empty
  • Studio OS: ten internal apps (website admin, operations, team hub, studio manager, client gallery, job history, company brain, brand kit, nightly review, company vault)
  • Quotes and inquiries that flow into a CRM with contacts, projects, bookings and a shoot-day planner
  • Contracts with e-signatures, invoices with derived status, and recorded payments
  • Client galleries with WebP previews, PIN or password protection, quick share links and gallery reminders
  • Client journey page that gathers quotes, contracts, invoices, shoots and galleries behind one private link
  • Studio Inbox: real email in and out through Amazon SES, threaded, with attachments and live updates
  • Team Hub: chat, per-job threads, tasks and notifications with server-scoped access
  • Live visitor traffic for admins over Socket.IO
  • Pixieset import for moving existing galleries across
  • JWT sign-in with rotating refresh tokens, admin and member roles, throttling and request validation
  • Prometheus metrics, Docker multi-stage images and a CI pipeline on both repositories

Architecture

System architecture

Diagram: visitors, clients and the studio team use a Next.js frontend that calls a NestJS API backed by PostgreSQL, Google Drive, S3 storage and Amazon SES.
Three audiences, one frontend, one API. Heavy files stay in Google Drive and storage, mail runs through Amazon SES, and SNS calls back into the API. Open full size ↗

Studio OS: ten apps, one sign-in

Diagram: the ten Studio OS apps shown as a grid that lights up one by one.
Everything the studio runs on lives in one place, from website content to legal documents. A role-aware sidebar shows each person only what they may use. Open full size ↗

Data model

Diagram: 43 PostgreSQL tables grouped into ten domains.
43 tables across ten domains, changed only through 13 migrations. Invoice status is derived from payments when it is read. Open full size ↗

Client lifecycle

Diagram: inquiry, quote, booking, contract, invoice, payment, gallery and review in sequence.
A client moves from first message to delivered photos without a login. One private journey page shows what is waiting for them. Open full size ↗

Gallery delivery

Diagram: originals in Google Drive, WebP previews made with sharp, then a PIN-gated download.
Previews are small WebP files served from storage. Originals come from Drive only after the PIN check, which runs again on every download. Open full size ↗

Studio Inbox

Diagram: inbound email travels through SES, SNS and a verified webhook to a threaded inbox in the browser.
Inbound mail is verified, sanitized, threaded by its headers and pushed to the team live. Replies leave through SES with attachments. Open full size ↗

Real-time channels

Diagram: three Socket.IO namespaces for visitors, team hub and studio inbox.
Each namespace has its own audience and its own authentication. Rooms are scoped on the server. Open full size ↗

Security layers

Diagram: six security layers from edge hardening to signed webhooks.
Six layers, each handling one kind of risk, so no single check carries all the weight. Open full size ↗

Delivery pipeline

Diagram: pull request through lint, format, test, build, malware scan and Docker to deploy.
Every change goes through the same gate. Open full size ↗

Engineering decisions

  1. 01Client pages use random links, not accounts

    Clients open galleries, contracts, invoices and journey pages from links made of 18 random bytes. There is nothing to sign up for or forget, and the links cannot be guessed. Galleries add a bcrypt-checked PIN or password on top.

  2. 02Originals stay in Google Drive

    Full-size files stay in the studio's own Drive, so storage costs stay low and nothing is copied twice. The platform makes small WebP previews with sharp and fetches the original only when a client downloads.

  3. 03Money is derived, not stored

    An invoice's status (draft, sent, partial, paid, past due) is worked out from its payments each time it is read. A stored status could drift from the payments, and the totals the studio sees would be wrong.

  4. 04Webhooks trust signatures, not URLs

    The email webhooks are public by necessity. Each request is accepted only after its SNS signature verifies and its topic matches the expected one exactly, so a guessed URL does nothing.

  5. 05Real-time is scoped on the server

    Socket.IO connections need a valid token, and rooms are filled by the server. A team member never receives a job thread or website task they could not open through the normal app.

  6. 06A test that guards the entity list

    The API lists its database entities explicitly. A missing one once caused a production error on a single endpoint, so a spec now fails if any entity class is left out of that list.

  7. 07Small pull requests with a fixed gate

    The work shipped as 296 merged pull requests across both repositories. Lint, format, tests, build and a malware scan run on every one, which kept a fast-moving product stable.

Need something similar?

Tell me what you are building and I will reply within one working day.

Start a project
↑↓ navigate↵ openesc closeCtrl K toggles this menu