System Architecture

ShopkeeperProMvp (Bambu) utilizes a robust, modern stack optimized for developer velocity and data security.

High-Level Architecture

The core of Bambu is built around Next.js (App Router) as the single full-stack framework handling both UI rendering and API routes.

  • Frontend: React (Next.js 14+), TailwindCSS, Shadcn/UI, Radix Primitives
  • Backend APIs: Next.js Route Handlers (app/api/...)
  • Database Layer: PostgreSQL managed by Prisma ORM
  • In-Memory Store: Redis (for caching, rate limiting, and OTPs)
  • File Storage: (Depending on deployment: local or cloud storage for uploaded receipts/images)

Multi-Tenant Schema Design

This is the most critical architectural decision in the product.

Instead of co-mingling all user data into massive shared tables (and identifying rows with a business_id), Bambu implements Schema-per-Tenant architecture in PostgreSQL.

  1. public schema: Contains global datasets—User, Business, Subscription, Plan.
  2. business_{slug} schemas: When a user creates a new business (e.g., named "My Shop"), a new discrete schema is generated dynamically using Prisma. This schema holds all the business logic tables: Product, Customer, Sale, Debt.

Why Schema-per-Tenant?

  • Security: Impossible to accidentally query another business's private sales data.
  • Backups: Can export a single postgres schema if a business requests their data.
  • Scalability: Indexes and queries stay fast since tables only contain one business's data.

To see the decision history outlining this choice, refer to adr/001-multi-tenant-schema-strategy.md (coming soon).

API & Data Flow

sequenceDiagram
    participant Client (Browser)
    participant Next.js API
    participant Middleware
    participant Redis
    participant Postgres (Prisma)
    
    Client (Browser)->>Next.js API: GET /api/products
    Next.js API->>Middleware: Verify Session Context
    Middleware-->>Redis: Rate Limit Check
    Note over Next.js API: Identifies Tenant Schema (e.g., schema_abc123)
    Next.js API->>Postgres (Prisma): Prisma Schema Context -> Query 'business_abc123.Product'
    Postgres (Prisma)-->>Next.js API: Returns array of Products
    Next.js API-->>Client (Browser): 200 OK + JSON

Folder Structure

The repository is modular and relies heavily on the app/ and lib/ directories:

  • /app/api: All backend endpoint logic.
  • /app/dashboard: The secure area for authenticated users (server/client components).
  • /lib/db: Prisma client singletons and connection handlers.
  • /lib/tenant: The core engine that resolves the current business's schema context.
  • /lib/middleware: Next.js edge middleware for routing and protective layers.
  • /prisma: Contains schema.prisma.

Best Practices

[!IMPORTANT] When querying data inside the tenant, you MUST ensure you are using the wrapped tenant-specific Prisma client instead of the global Prisma client. Failing to do so throws an error as the global client does not have access to the tenant tables.