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.
| Element | Source |
|---|---|
| Logo on a light background | public/img/B-Logo.png |
| Logo on a dark background | public/img/W-logo.png |
| Favicon | public/Favicon.png |
| Headings | Azonix |
| Body text | Oxanium |
| Light surfaces | White #ffffff, text #000000 |
| Dark surfaces | Background #121212, panels #1A1A1A, text #E0E0E0 |
| Accent | Gold #AB8100 |
Users
| User | Authenticated | What they do |
|---|---|---|
| Visitor | No | Browses public pages and starts a booking. |
| Customer | Yes, after account setup or an existing login | Pays for a package, tracks approval, opens an approved gallery, rates photos, and spends referral rewards. |
| Photographer and administrator | Yes, ADMIN role | Approves 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
| Topic | Decision |
|---|---|
| Currency | USD only. Stripe charges and refunds in USD. |
| Money storage | Integer cents. The currency column is USD. |
| Booking | Verified payment sets the booking to pending approval. The photographer confirms or rejects it. |
| Payment confirmation | A verified Stripe webhook, or a server-side read of the Stripe payment, confirms payment. The success redirect does not. |
| Authentication | Access token and rotating refresh token. The access token is sent as a bearer token. |
| Database access | The generated Prisma Client is the only query client. It connects with DATABASE_URL. |
| Gallery | Publication and access are separate. Customers need both a published gallery and an approved access decision. |
| Rewards | Percentage of the eligible service amount, credited in cents, redeemed as a discount on a future booking. |
| Architecture | Modular monolith. Next.js, Express, the worker, and PostgreSQL stay logically separate. |
| Documentation | This 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.