-
Notifications
You must be signed in to change notification settings - Fork 20
Description
Layered Architecture Implementation Plan
Overview
Separate "Vendure core" code from "merchant customizable" code to enable:
- Easy upstream updates via git merge
- Clear boundaries between editable and protected code
- Theme and component customization without touching core files
Approach: Incremental migration with core/ and merchant/ naming. Slot system deferred.
Target Directory Structure
/src/
├── core/ # VENDURE-MAINTAINED (do not modify)
│ ├── components/
│ │ ├── commerce/ # ProductCard, ProductGrid, etc.
│ │ ├── layout/ # Navbar, Footer, HeroSection
│ │ └── shared/ # Pagination, skeletons
│ ├── lib/
│ │ └── vendure/ # GraphQL API, queries, mutations
│ ├── hooks/
│ ├── contexts/
│ └── theme/
│ └── base.css # Core design tokens
│
├── merchant/ # MERCHANT-CUSTOMIZABLE
│ ├── components/
│ │ ├── overrides/ # Replace core components by name
│ │ └── custom/ # New merchant-specific components
│ ├── theme/
│ │ ├── tokens.css # Design token overrides
│ │ └── components.css # Component style overrides
│ └── lib/
│ └── graphql/ # Custom queries/fragments
│
├── config/ # CONFIGURATION
│ ├── storefront.config.ts # Store settings, features
│ ├── theme.config.ts # Logo, fonts, layout
│ └── components.config.ts # Component overrides registry
│
├── components/ui/ # shadcn/ui (unchanged, shared)
├── app/ # Next.js routes (merchant-owned)
└── graphql.ts # gql.tada (unchanged)
Implementation Phases
Phase 1: Infrastructure Setup
Goal: Create directory structure and update configuration without breaking existing code.
-
Create directories:
src/core/ src/core/components/commerce/ src/core/components/layout/ src/core/components/shared/ src/core/lib/vendure/ src/core/hooks/ src/core/contexts/ src/core/theme/ src/merchant/ src/merchant/components/overrides/ src/merchant/components/custom/ src/merchant/theme/ src/merchant/lib/graphql/ src/config/ -
Update
tsconfig.json- Add path aliases:"paths": { "@/*": ["./src/*"], "@core/*": ["./src/core/*"], "@merchant/*": ["./src/merchant/*"], "@config/*": ["./src/config/*"] }
-
Create empty placeholder files:
src/core/theme/base.css(empty)src/merchant/theme/tokens.css(empty)src/merchant/theme/components.css(empty)
-
Verify build:
npm run build
Phase 2: Extract Theme Tokens
Goal: Move CSS variables to layered theme files.
-
Create
src/core/theme/base.css:- Move
:rootand.darkCSS variable definitions fromglobals.css - Keep
@layer basestyles
- Move
-
Update
src/app/globals.css:@import "tailwindcss"; @import "tw-animate-css"; @import "@core/theme/base.css"; @import "@merchant/theme/tokens.css"; @import "@merchant/theme/components.css"; @custom-variant dark (&:is(.dark *)); @theme inline { /* ... existing mappings ... */ }
-
Verify: Dark/light theme switching still works.
Phase 3: Extract Commerce Components
Goal: Move commerce components to core, update imports.
-
Move files:
src/components/commerce/*→src/core/components/commerce/
-
Update imports in app routes:
- Find all files importing from
@/components/commerce/ - Update to
@core/components/commerce/
- Find all files importing from
-
Files affected:
src/app/page.tsx(featured-products)src/app/product/[slug]/page.tsxsrc/app/collection/[slug]/page.tsxsrc/app/search/page.tsxsrc/app/account/orders/page.tsx
-
Verify:
npm run build
Phase 4: Extract Layout Components
Goal: Move layout components to core.
-
Move files:
src/components/layout/*→src/core/components/layout/
-
Update imports:
src/app/layout.tsx(Navbar, Footer)src/app/page.tsx(HeroSection)
-
Verify:
npm run build
Phase 5: Extract Shared Components
Goal: Move shared utilities and skeletons.
-
Move files:
src/components/shared/*→src/core/components/shared/
-
Update imports in collection and search pages.
-
Verify:
npm run build
Phase 6: Extract Library Code
Goal: Move Vendure API, contexts, hooks to core.
-
Move files:
src/lib/vendure/*→src/core/lib/vendure/src/lib/utils.ts→src/core/lib/utils.tssrc/lib/format.ts→src/core/lib/format.tssrc/contexts/*→src/core/contexts/src/hooks/*→src/core/hooks/
-
Keep in original location (merchant-owned):
src/lib/metadata.ts(merchant customizes site name)src/lib/auth.ts(may need merchant customization)
-
Update all imports across the codebase.
-
Verify:
npm run build
Phase 7: Component Registry
Goal: Create registry pattern for component overrides.
-
Create
src/config/components.config.ts:// Core component imports import { ProductCard } from '@core/components/commerce/product-card'; import { ProductGrid } from '@core/components/commerce/product-grid'; import { Navbar } from '@core/components/layout/navbar'; import { Footer } from '@core/components/layout/footer'; import { HeroSection } from '@core/components/layout/hero-section'; // Merchant overrides (uncomment to enable) // import { ProductCard } from '@merchant/components/overrides/ProductCard'; export const components = { ProductCard, ProductGrid, Navbar, Footer, HeroSection, } as const; export type Components = typeof components;
-
Update
src/app/layout.tsx:import { components } from '@config/components.config'; const { Navbar, Footer } = components;
-
Update other pages to use registry pattern.
Phase 8: Configuration Files
Goal: Create storefront and theme configuration.
-
Create
src/config/storefront.config.ts:export const storefrontConfig = { store: { name: process.env.NEXT_PUBLIC_SITE_NAME || 'Vendure Store', supportEmail: 'support@example.com', }, features: { wishlist: false, productReviews: false, guestCheckout: true, }, search: { productsPerPage: 12, defaultSort: 'newest' as const, }, };
-
Create
src/config/theme.config.ts:export const themeConfig = { brand: { logo: '/logo.svg', logoAlt: 'Store Logo', }, layout: { maxWidth: '1280px', navbarPosition: 'sticky' as const, }, };
Phase 9: Merchant Override Example
Goal: Create example override to demonstrate the pattern.
-
Create
src/merchant/components/overrides/ProductCard.tsx:- Copy from core, add a small customization (e.g., badge)
- Document as example
-
Enable in
components.config.ts(commented out by default).
Phase 10: Git Configuration & Documentation
Goal: Set up merge strategies and documentation.
-
Create
CUSTOMIZATION.md:- Theme customization guide
- Component override guide
- GraphQL extension guide
-
Create
UPGRADING.md:- Upstream sync workflow
- Conflict resolution guide
Critical Files Modified
| File | Changes |
|---|---|
tsconfig.json |
Add @core/*, @merchant/*, @config/* path aliases |
src/app/globals.css |
Restructure to import layered CSS files |
src/app/layout.tsx |
Use component registry for Navbar/Footer |
src/app/page.tsx |
Use component registry, update imports |
| All route files | Update imports from @/components/* to @core/components/* |
Key Mechanisms
Component Override Pattern
// In components.config.ts, swap the import:
import { ProductCard } from '@merchant/components/overrides/ProductCard';Theme Override Pattern
/* In merchant/theme/tokens.css */
:root {
--primary: oklch(0.65 0.2 145); /* Override to green */
}CSS Component Override Pattern
/* In merchant/theme/components.css */
[data-component="product-card"] {
border-radius: 0;
}Verification
After each phase:
npm run build- Ensure no TypeScript/build errorsnpm run dev- Verify pages render correctly- Test dark/light theme toggle
Final verification:
- Create a sample merchant override
- Enable it in components.config.ts
- Verify the override renders instead of core
- Test git merge simulation with a test branch