Skip to main content

Project overview

KStudeo already publishes a marketing site for portrait, wedding, family, travel, modeling, photography, video, and design work, plus contact, about, and privacy pages. This design retains that public experience and extends it with booking, checkout, a customer portal, and a photographer administration dashboard.

The target interface is a Next.js and TypeScript application. The current marketing site is a Vite and React application in this repository. The move onto Next.js keeps the public pages and adds the authenticated product around them. Express, PostgreSQL, private storage, and a worker are new services. They do not exist in the marketing site today.

Interface​

The portal and this documentation site use the public KStudeo brand.

ElementSource
Logo on a light backgroundpublic/img/B-Logo.png
Logo on a dark backgroundpublic/img/W-logo.png
Faviconpublic/Favicon.png
HeadingsAzonix
Body textOxanium
Light surfacesWhite #ffffff, text #000000
Dark surfacesBackground #121212, panels #1A1A1A, text #E0E0E0
AccentGold #AB8100

Users​

UserAuthenticatedWhat they do
VisitorNoBrowses public pages and starts a booking.
CustomerYes, after account setup or an existing loginPays for a package, tracks approval, opens an approved gallery, rates photos, and spends referral rewards.
Photographer and administratorYes, ADMIN roleApproves bookings, refunds rejected paid bookings, publishes galleries, grants or revokes access, and reviews audit history.

A visitor who pays with a new email address becomes a customer only after following the account setup link. A returning customer signs in and keeps that account. The photographer is the administrator of this product. There is one administrative role.

Product decisions in this edition​

TopicDecision
CurrencyUSD only. Stripe charges and refunds in USD.
Money storageInteger cents. The currency column is USD.
BookingVerified payment sets the booking to pending approval. The photographer confirms or rejects it.
Payment confirmationA verified Stripe webhook, or a server-side read of the Stripe payment, confirms payment. The success redirect does not.
AuthenticationAccess token and rotating refresh token. The access token is sent as a bearer token.
Database accessThe generated Prisma Client is the only query client. It connects with DATABASE_URL.
GalleryPublication and access are separate. Customers need both a published gallery and an approved access decision.
RewardsPercentage of the eligible service amount, credited in cents, redeemed as a discount on a future booking.
ArchitectureModular monolith. Next.js, Express, the worker, and PostgreSQL stay logically separate.
DocumentationThis Docusaurus site, plus an OpenAPI description of the API.

In scope​

  • Service and package catalog with server-trusted USD prices.
  • Booking creation, photographer approval, rejection, cancellation, and completion.
  • Orders, order-item price snapshots, Stripe checkout, Stripe refunds, and webhook deduplication.
  • Account setup for new payers, login, access and refresh tokens, password recovery, and administrator multi-factor authentication.
  • Private photo storage, thumbnails, publication, access approval history, downloads, and ratings from 1 to 5.
  • Referral codes, one attribution per referred customer, percentage policies, an immutable reward ledger, and discount redemption.
  • In-app notifications, email delivery tracking, background jobs, and audit logs.

Out of scope for this edition​

  • Currencies other than USD.
  • Tax calculation and travel charges. If those charges are added later, they are stored apart from the service subtotal and are excluded from referral rewards and reward discounts.
  • Cash withdrawal of referral rewards.
  • Microservices, one deployable per business capability.
  • Customer access to a gallery because it was published, without an access approval.
  • Treating a payment-provider success URL as proof of payment.

Modular monolith​

One Express codebase owns authentication, bookings, orders, payments, gallery permissions, referrals, notifications, and audit. Modules call each other inside the process and share one PostgreSQL database. They do not call each other over the network. Next.js is the interface. The worker is a separate process that claims jobs from the same database. Splitting a module into its own service waits until operations has a measured reason to do so.