sadmann7/skateshop

An open source e-commerce skateshop build with everything new in Next.js.

5,483 stars TypeScript 6 components

13 hidden assumptions · 6-stage pipeline · 6 components

Like any codebase, this fullstack makes assumptions it never checks — most are routine. The ones worth your attention are below.

Multi-tenant e-commerce platform where users create skateboard shops with inventory management

Users register and authenticate through Clerk, then create stores with configurable subscription plans. Store owners add products with images uploaded via UploadThing, categorize inventory, and manage orders through the dashboard. Customer-facing storefronts display products filtered by category and availability, while the admin interface handles inventory updates, plan limit enforcement, and Stripe payment processing.

Under the hood, the system uses 2 feedback loops, 3 data pools, 3 control points to manage its runtime behavior.

A 6-component fullstack. 314 files analyzed. Data flows through 6 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If the connection string becomes invalid (credentials expire, server moves, network changes), all database operations fail with connection errors but the application continues running with broken state

Worth your attention first

Calling useSidebar outside the provider throws runtime error 'useSidebar must be used within a SidebarProvider', crashing the component that tries to access sidebar state

Worth your attention first

If UploadThing CDN URLs expire, change domains, or require authentication, product images break silently - users see broken image placeholders but no error is thrown

Show everything (10 more)
Ordering

Route segments array from useSelectedLayoutSegments() has predictable structure where segments[0] is the primary section and segments.includes() accurately reflects nested routes

If this fails: If Next.js changes segment ordering or includes unexpected segments (like dynamic route parameters), navigation highlights wrong sections or shows multiple active states simultaneously

src/app/(dashboard)/store/[storeId]/_components/dashboard-sidebar.tsx:useSelectedLayoutSegments
Contract

storesPromise and planMetricsPromise are actual Promise objects that will resolve successfully with expected data shapes

If this fails: If promises reject or resolve with unexpected data, React.use() throws unhandled errors that crash the component, making store switching completely unusable

src/app/(dashboard)/store/[storeId]/_components/store-switcher.tsx:React.use
Scale

nanoid with 30-character length provides sufficient uniqueness for all database primary keys across all stores and products without collisions

If this fails: ID collisions cause database constraint violations during insert operations, failing store or product creation with cryptic errors that don't indicate the root cause

src/lib/id.ts:generateId
Temporal

Database server clock and application server clock are synchronized when $onUpdate() executes new Date() versus database current_timestamp default

If this fails: Clock skew causes updatedAt timestamps to be inconsistent - some records show future dates, others lag behind, breaking audit trails and temporal queries

src/db/schema/utils.ts:updatedAt
Contract

storeId parameter from URL route [storeId] is always a valid store identifier that matches existing store records in the database

If this fails: Invalid storeId causes selectedStore to be undefined, leading to component render errors when trying to access store properties, making dashboard inaccessible

src/app/(dashboard)/store/[storeId]/_components/store-switcher.tsx:useParams
Domain

stripePriceId corresponds to actual Stripe price objects that exist in the connected Stripe account and remain valid

If this fails: Invalid Stripe price IDs cause subscription upgrades to fail with Stripe API errors, but users see generic error messages without understanding the payment issue

src/types/index.ts:Plan
Shape

JSON-stored StoredFile arrays in product.images column always contain objects with id, name, and url properties

If this fails: Corrupted JSON or missing properties cause runtime errors when components try to render product images, showing TypeScript errors in production instead of fallback images

src/types/index.ts:StoredFile
Resource

Plan metrics calculation completes quickly enough that React.use() doesn't cause UI blocking or timeout issues

If this fails: Slow plan metrics queries cause the store switcher to hang indefinitely during rendering, making multi-store management unusable until the query resolves

src/app/(dashboard)/store/[storeId]/_components/store-switcher.tsx:planMetricsPromise
Environment

PostgreSQL database connection pool can handle concurrent requests from all active dashboard sessions without connection exhaustion

If this fails: During high usage, connection pool exhaustion causes new requests to hang or timeout, making store management randomly unavailable for some users

src/db/index.ts:drizzle
Contract

Only one SidebarProvider exists in the React component tree to avoid context conflicts

If this fails: Multiple providers cause nested context confusion where useSidebar() returns state from the wrong provider level, leading to sidebar state bugs across different dashboard areas

src/components/layouts/sidebar-provider.tsx:SidebarProvider

Open the standalone hidden-assumptions report for skateshop →

How Data Flows Through the System

Users register and authenticate through Clerk, then create stores with configurable subscription plans. Store owners add products with images uploaded via UploadThing, categorize inventory, and manage orders through the dashboard. Customer-facing storefronts display products filtered by category and availability, while the admin interface handles inventory updates, plan limit enforcement, and Stripe payment processing.

  1. User Authentication — Clerk handles user registration, login, and session management, providing user objects with unique IDs that link to store ownership
  2. Store Registration — CreateStoreDialog component validates against plan limits, generates unique store IDs using generateId(), and inserts new Store records with default free plan settings [User → Store]
  3. Product Creation — Dashboard forms collect product details, validate against store limits, upload images via UploadThing to get StoredFile objects, then insert Product records with decimal pricing and integer inventory [Store → Product]
  4. Image Upload Processing — UploadThing middleware handles file validation and CDN upload, returning StoredFile objects with permanent URLs that get stored as JSON in product images columns [File Upload → StoredFile]
  5. Storefront Display — Server components query products by store ID and status, filter by categories and subcategories, and render product cards with images from StoredFile URLs [Product → Product Display]
  6. Dashboard Navigation — DashboardSidebar reads current route segments, matches against NavItem definitions, and renders active states while StoreSwitcher manages multi-store context switching [NavItem → Navigation UI]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

Store src/db/schema/stores.ts
table with id: varchar(30), userId: varchar(36), slug: text, name: text, plan: storePlanEnum('free'|'standard'|'pro'), planEndsAt: timestamp, productLimit: integer, stripeAccountId: varchar
Created when user registers a new store, updated when plan changes, referenced by all store-related operations
Product src/db/schema/products.ts
table with id: varchar(30), name: text, description: text, images: json(StoredFile[]), categoryId: varchar(30), price: decimal(10,2), inventory: integer, status: productStatusEnum('active'|'draft'|'archived'), storeId: varchar(30)
Created by store owners, updated through dashboard, displayed on storefront, archived when discontinued
StoredFile src/types/index.ts
interface with id: string, name: string, url: string extending ClientUploadedFileData
Created during file upload via UploadThing, stored as JSON in product images, served from CDN URLs
NavItem src/types/index.ts
interface with title: string, href?: string, active?: boolean, disabled?: boolean, external?: boolean, icon?: keyof Icons, label?: string, description?: string
Defined statically in components, dynamically constructed based on user permissions and current route
Plan src/types/index.ts
interface with id: Store['plan'], title: string, description: string, features: string[], stripePriceId: string, limits: {stores: number, products: number, tags: number, variants: number}
Defined as configuration, enforced during store operations, updated when user changes subscription

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

PostgreSQL Database (database)
Primary data store containing all relational tables for stores, products, users, orders, and metadata with foreign key constraints
Sidebar Context State (in-memory)
React Context holding boolean open/close state for mobile sidebar across dashboard pages
UploadThing File Storage (file-store)
CDN-backed file storage for product images with permanent URLs referenced in database JSON fields

Feedback Loops

Delays

Control Points

Technology Stack

Next.js 14 (framework)
App Router framework providing server components, file-based routing, and API routes for the e-commerce application
Drizzle ORM (database)
Type-safe database ORM that generates TypeScript types from schema definitions and handles PostgreSQL queries
Clerk (infra)
Authentication provider handling user registration, login, session management, and user profile data
Stripe (infra)
Payment processing and subscription management for store plans and customer transactions
UploadThing (infra)
File upload service that handles product image storage and returns CDN URLs for database storage
Tailwind CSS (framework)
Utility-first CSS framework for styling components with responsive design and dark mode support
shadcn/ui (library)
React component library built on Radix UI primitives providing accessible and customizable UI components

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Fullstack Repositories

Frequently Asked Questions

What is skateshop used for?

Multi-tenant e-commerce platform where users create skateboard shops with inventory management sadmann7/skateshop is a 6-component fullstack written in TypeScript. Data flows through 6 distinct pipeline stages. The codebase contains 314 files.

How is skateshop architected?

skateshop is organized into 4 architecture layers: Database Schema Layer, Data Access Layer, UI Component Layer, Route Handler Layer. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through skateshop?

Data moves through 6 stages: User Authentication → Store Registration → Product Creation → Image Upload Processing → Storefront Display → .... Users register and authenticate through Clerk, then create stores with configurable subscription plans. Store owners add products with images uploaded via UploadThing, categorize inventory, and manage orders through the dashboard. Customer-facing storefronts display products filtered by category and availability, while the admin interface handles inventory updates, plan limit enforcement, and Stripe payment processing. This pipeline design reflects a complex multi-stage processing system.

What technologies does skateshop use?

The core stack includes Next.js 14 (App Router framework providing server components, file-based routing, and API routes for the e-commerce application), Drizzle ORM (Type-safe database ORM that generates TypeScript types from schema definitions and handles PostgreSQL queries), Clerk (Authentication provider handling user registration, login, session management, and user profile data), Stripe (Payment processing and subscription management for store plans and customer transactions), UploadThing (File upload service that handles product image storage and returns CDN URLs for database storage), Tailwind CSS (Utility-first CSS framework for styling components with responsive design and dark mode support), and 1 more. A focused set of dependencies that keeps the build manageable.

What system dynamics does skateshop have?

skateshop exhibits 3 data pools (PostgreSQL Database, Sidebar Context State), 2 feedback loops, 3 control points, 2 delays. The feedback loops handle circuit-breaker and polling. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does skateshop use?

4 design patterns detected: Multi-tenant SaaS Architecture, Server Components with Promises, Schema-First Database Design, Compound Component Pattern.

Analyzed on April 20, 2026 by CodeSea. Written by .