Skip to main content

Architecture Overview

CakeMarket v2.0 is built on a modern full-stack TypeScript architecture.

Technology Stack

LayerTechnology
FrameworkNext.js 14+ (App Router)
LanguageTypeScript
DatabaseSQLite via Drizzle ORM (better-sqlite3)
AuthenticationAuth.js v5 with JWT strategy
StylingTailwind CSS
ValidationZod
PaymentsStripe Connect
IDsUUID v4 for all primary keys
i18nJSON-based translations (English + Polish)
PWAService worker + manifest.json

App Router Structure

The application uses Next.js route groups to separate concerns:

src/app/
├── (buyer)/ # Buyer-facing pages
├── (seller)/ # Seller portal
│ └── seller/
│ ├── dashboard/
│ ├── requests/
│ ├── orders/
│ ├── organisation/
│ ├── profile/
│ ├── payments/
│ ├── onboarding/
│ └── pending/
├── (admin)/ # Admin panel
│ └── admin/
│ ├── disputes/ # Legacy compatibility redirect; no active dispute UI
│ └── orders/
├── about/ # Marketing pages
└── api/ # API routes
├── admin/
├── guest/
├── images/
├── messages/
├── offers/
├── orders/
├── organisations/
├── payments/
├── profile/
├── requests/
├── reviews/
└── seller/

Key Architectural Patterns

Data Access Layer (DAL)

All database queries go through src/lib/dal/. Components and API routes never import Drizzle directly — they use DAL functions instead.

src/lib/dal/
├── organisations.ts
├── orders.ts
├── offers.ts
├── requests.ts
├── users.ts
├── payments.ts
├── messages.ts
├── reviews.ts
└── ...

Auth Helpers

Centralised authentication functions in src/lib/auth/helpers.ts:

  • getCurrentUser() — Get the current session user
  • requireAuth() — Require authentication (returns user or throws)
  • requireAdmin() — Require admin role
  • requireOrgMember() — Require membership in a specific organisation
  • requireOrgAdmin() — Require admin role within an organisation

Guest Sessions

Guest users are supported via localStorage tokens and browser fingerprinting. Guests can:

  • Create cake requests
  • Receive and accept offers
  • Place orders

Guest sessions can be converted to full accounts via POST /api/guest/convert, which migrates requests, orders, and preferences.

Price Handling

All prices are stored as integers in grosze (1/100 PLN) to avoid floating-point issues:

  • formatPrice() — Converts grosze to display format
  • calculateDeposit() — Computes deposit from total
  • calculateCommission() — Computes platform fee
  • calculateBalance() — Computes remaining balance

Business Constants

Defined in src/lib/utils/constants.ts:

ConstantValue
Commission rate10%
Deposit range20–100%
Request expiry24 hours
Smart sort: rating weight40%
Smart sort: price weight35%
Smart sort: certification weight25%

Component Architecture

src/components/
├── ui/ # Reusable UI primitives (buttons, modals, badges, etc.)
├── shared/ # Shared components (FAQ accordion, etc.)
├── buyer/ # Buyer-specific components
└── seller/ # Seller-specific components
├── OfferForm.tsx
├── RequestCard.tsx
├── RequestDetailModal.tsx
├── OrderCard.tsx
├── OrderDetail.tsx
├── MessageThread.tsx
├── PortfolioManager.tsx
├── MembersList.tsx
├── CertificationManager.tsx
├── SidebarNav.tsx
├── BottomTabs.tsx
└── TopBar.tsx

Validation

All input validation uses Zod schemas defined in src/lib/validation/schemas.ts. Schemas are shared between client-side forms and API route handlers.

Email Notifications

24 HTML email templates (Polish + English) in src/lib/notifications/email.ts:

  • Production: Sent via Resend
  • Development: Logged to console

Helper functions include sendOfferReceivedEmail, sendBalancePaymentDueEmail, sendSellerMarkedDeliveredEmail, sendReviewPromptEmail, and sendNewOrganisationAdminEmail.