Skip to main content

Architecture Overview

Gully Sports is built with modern web technologies following best practices for performance, scalability, and maintainability.

Tech Stack​

Frontend​

Backend​

Payment Processing​

Image Storage​

Deployment​

  • Vercel - Hosting & CI/CD (recommended)
  • Compatible: Netlify, Railway, DigitalOcean, AWS

Core Architecture Patterns​

Dual Database Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Supabase β”‚ β”‚ CockroachDB β”‚
β”‚ (Auth Only) β”‚ β”‚ (App Data) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Users (Auth) │────────▢│ β€’ Users (Data) β”‚
β”‚ β€’ Sessions β”‚ Sync β”‚ β€’ Products β”‚
β”‚ β€’ OAuth β”‚ β”‚ β€’ Bookings β”‚
β”‚ β€’ Tokens β”‚ β”‚ β€’ Orders β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β€’ Lanes β”‚
β”‚ β€’ Payments β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why Dual Database?

  • Separation of Concerns: Auth logic separate from business data
  • Supabase Strengths: Built-in auth, OAuth providers, email verification
  • CockroachDB Strengths: Distributed SQL, high availability, PostgreSQL compatible
  • Automatic Sync: User data synchronized between databases

Learn more about Database Setup β†’

Feature Flag System​

Control major features via environment variables:

// utils/featureFlags.ts
export const ENABLE_LANE_RENTAL =
process.env.NEXT_PUBLIC_ENABLE_LANE_RENTAL === "true";

export const PAYMENT_PROVIDER =
process.env.NEXT_PUBLIC_PAYMENT_PROVIDER || "intuit";

Benefits:

  • Toggle features without code changes
  • A/B testing capability
  • Gradual feature rollout
  • Environment-specific features

Learn more about Feature Flags β†’

Checkout Session Management​

Modern session-based checkout with clean URLs:

// utils/checkoutSession.ts
export function createCheckoutSession(
items: CheckoutItem[],
email?: string
): string {
const session = {
sessionId: generateSessionId(),
amount: calculateTotal(items),
items,
email,
expiresAt: Date.now() + 30 * 60 * 1000, // 30 min
};

localStorage.setItem("checkout_session", JSON.stringify(session));
return session.sessionId;
}

Features:

  • 30-minute session expiration
  • Automatic session extension
  • Backward compatible with URL params
  • Migration path to backend sessions

Learn more about Checkout Sessions β†’

Application Layers​

1. Presentation Layer (UI)​

Location: src/app/ and src/components/

src/
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ page.tsx # Homepage
β”‚ β”œβ”€β”€ shop/ # E-commerce
β”‚ β”œβ”€β”€ bookings/ # Lane bookings
β”‚ β”œβ”€β”€ checkout/ # Payment flow
β”‚ └── admin/ # Admin dashboard
└── components/
β”œβ”€β”€ Header.tsx # Navigation
β”œβ”€β”€ Footer.tsx # Site footer
└── AuthButtons.tsx # Auth UI

2. API Layer (Backend)​

Location: src/app/api/

src/app/api/
β”œβ”€β”€ products/ # Public product API
β”œβ”€β”€ bookings/ # Public booking API
β”œβ”€β”€ payments/ # Payment processing
β”‚ └── submit/
└── admin/ # Protected admin API
β”œβ”€β”€ products/
β”œβ”€β”€ lanes/
β”œβ”€β”€ upload/
└── intuit/

3. Business Logic Layer​

Location: src/utils/

src/utils/
β”œβ”€β”€ featureFlags.ts # Feature configuration
β”œβ”€β”€ intuitPayments.ts # Intuit logic
β”œβ”€β”€ squarePayments.ts # Square logic
β”œβ”€β”€ checkoutSession.ts # Checkout management
β”œβ”€β”€ adminAuth.ts # Admin authorization
└── userSync.ts # Database synchronization

4. Data Layer​

Location: prisma/

prisma/
β”œβ”€β”€ schema.prisma # Database schema
β”œβ”€β”€ migrations/ # Migration history
└── seed.js # Sample data

Request Flow Examples​

User Registration​

1. User clicks "Sign Up"
↓
2. Supabase Auth (client-side)
↓
3. POST /api/auth/callback
↓
4. Create User in CockroachDB (server-side)
↓
5. Store Supabase ID for mapping
↓
6. Redirect to homepage (authenticated)

Product Purchase​

1. User adds items to cart (client-side state)
↓
2. Click "Checkout"
↓
3. Create checkout session (localStorage)
↓
4. Navigate to /checkout (clean URL)
↓
5. Load payment SDK (Intuit or Square)
↓
6. User enters payment details
↓
7. SDK tokenizes payment (PCI compliant)
↓
8. POST /api/payments/submit with token
↓
9. Server processes payment
↓
10. Create Order in database
↓
11. Clear checkout session
↓
12. Redirect to success page

Admin Product Management​

1. Admin logs in (Supabase Auth)
↓
2. Middleware checks admin role
↓
3. Load /admin/inventory
↓
4. GET /api/admin/products
↓
5. Prisma query to CockroachDB
↓
6. Return products with images
↓
7. Admin uploads new image
↓
8. POST /api/admin/upload (get signed URL)
↓
9. Client uploads to Vercel Blob
↓
10. POST /api/admin/products/[id]/images
↓
11. Save image URL in database
↓
12. Display updated product

Security Architecture​

Authentication Flow​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client │────▢│ Supabase │────▢│ Middleware β”‚
β”‚ β”‚ β”‚ Auth β”‚ β”‚ (Check) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Protected β”‚
β”‚ Route β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Authorization Layers​

  1. Client-Side: UI elements hidden/shown based on auth state
  2. Middleware: Route protection for admin pages
  3. API Routes: Server-side role verification
  4. Database: Row-level security via Prisma queries

Payment Security​

  • PCI Compliance: Card data never touches server
  • Tokenization: Provider SDKs handle sensitive data
  • HTTPS Only: All payment requests encrypted
  • Idempotency Keys: Prevent duplicate transactions
  • Server Validation: Double-check amounts server-side

Performance Optimizations​

Frontend​

  • Next.js Image: Automatic optimization, lazy loading
  • Code Splitting: Automatic with App Router
  • Server Components: Reduced JavaScript bundle
  • Caching: Static generation where possible
  • Prefetching: Next.js Link prefetching

Backend​

  • Database Indexes: On frequently queried fields
  • Prisma Select: Only fetch needed fields
  • Connection Pooling: Efficient database connections
  • Edge Functions: Vercel Edge for global performance

Images​

  • Vercel Blob: CDN-backed storage
  • Next.js Image: WebP/AVIF conversion
  • Lazy Loading: Load images as they enter viewport
  • Responsive Sizes: Serve appropriate image sizes

Scalability Considerations​

Horizontal Scaling​

  • Stateless API: No server-side sessions
  • Database: CockroachDB scales horizontally
  • Images: CDN distribution
  • Checkout Sessions: Currently localStorage (migrate to Redis)

Vertical Scaling​

  • Database Connections: Configure connection pool
  • API Routes: Serverless auto-scaling
  • Caching: Add Redis for sessions/cache

Development Workflow​

# 1. Clone repository
git clone <repo-url>
cd gully-store-consumer-app

# 2. Install dependencies
npm install

# 3. Set up environment
cp .env.example .env.local

# 4. Initialize database
npx prisma generate
npx prisma db push

# 5. Run development server
npm run dev

# 6. Open browser
http://localhost:3000

Deployment Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Vercel Edge β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Edge 1 β”‚ β”‚ Edge 2 β”‚ β”‚ Edge 3 β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Next.js Application β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Frontend β”‚ β”‚ API Routes β”‚ β”‚
β”‚ β”‚ (React) β”‚ β”‚ (Serverless) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓ ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Vercel Blob β”‚ β”‚ CockroachDB β”‚
β”‚ (Images) β”‚ β”‚ (Data) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓ ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Supabase β”‚ β”‚ Payment APIs β”‚
β”‚ (Auth) β”‚ β”‚ (Intuit/Square)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Need help with architecture decisions? Open an issue on GitHub or check our documentation sections above.