Skip to content

Code Structure

This page is a tour of the codebase with a focus on the frontend app under src/. It’s meant to answer: “Where do I put new code?” and “Where do I look to understand X?”


Top-level overview (src/)

Under src/:

  • main.tsx – React entrypoint. Mounts <App /> and wraps it in ErrorBoundary and HelmetProvider.
  • App.tsx – Core app composition:
    • Sets up providers: QueryClientProvider, AuthProvider, ThemeProvider, TooltipProvider, Toaster.
    • Declares all routes using React Router (BrowserRouter, Routes, Route).
  • components/ – Reusable components and feature-level UI.
  • pages/ – Route-level screens (one file or folder per route or feature area).
  • contexts/ – Application-wide React contexts (auth, theme, etc.).
  • hooks/ – Custom hooks (data fetching, domain logic, UI behavior).
  • integrations/ – External service clients (Supabase, etc.).
  • lib/ – Domain logic, constants, subscription helpers, calculations.
  • types/ – Shared TypeScript types.
  • utils/ – Generic utilities that don’t belong to a specific domain.

Pages vs components

src/pages/ – route-level screens

Role: High-level containers tied directly to routes.

Examples:

  • pages/Dashboard.tsx – main dashboard.
  • pages/Inventory.tsx – inventory screen (list + create/edit).
  • pages/Orders.tsx – orders board/list.
  • pages/Clients.tsx, pages/clients/CRM.tsx, pages/clients/AppointmentsCalendar.tsx.
  • pages/design/CADFileLibrary.tsx, pages/Library.tsx.
  • pages/payments/InvoiceCreation.tsx, pages/payments/PayLinkCreation.tsx.
  • pages/auth/Login.tsx, pages/auth/Signup.tsx, pages/auth/AuthCallback.tsx, pages/auth/ClearSession.tsx.
  • pages/repairs/*.tsx – repair calculators.

Typical responsibilities:

  • Compose feature-level components from src/components/**.
  • Wire hooks (useInventory, useOrders, useClients, etc.) into UI.
  • Handle route params and navigation (useNavigate, useSearchParams).
  • Provide layout via DashboardLayout or public layout.

Guideline:

  • Keep logic in pages thin when possible; move reusable logic into hooks and lib.
  • If a page becomes large (hundreds of lines), consider extracting subcomponents into src/components/<feature>/.

src/components/ – reusable UI & feature components

Role: Building blocks used by pages and sometimes other components.

Pattern:

  • Grouped by domain or function, e.g.:
    • components/inventory/*InventoryTable, InventoryForm, ProductEditModal, etc.
    • components/orders/*OrderBoard, OrdersListView, OrderDetailsModal.
    • components/clients/*ClientSelect, client stats and tables.
    • components/invoice/*InvoiceItemAutocomplete and related UI.
    • components/library/*FolderSidebar, LibraryGallery, FileUploader, FilePreviewModal.
    • components/owner/*, components/billing/*, etc.

Shared layout & scaffolding:

  • DashboardLayout.tsx – main app shell (sidebar, top bar, content area).
  • Sidebar.tsx, MobileSidebar.tsx, UserMenu.tsx – navigation & user controls.
  • ErrorBoundary.tsx – error boundary around the app.

Guideline:

  • If a piece of UI is used in more than one page, it likely belongs in components/ under an appropriate feature folder.
  • Keep components focused: one clear responsibility, props-driven, minimal side effects. Push data fetching into hooks where feasible.

UI primitives: shadcn/ui

src/components/ui/

This folder contains shadcn/ui-style primitives and wrappers around Radix UI.

Examples:

  • Inputs & forms: input.tsx, textarea.tsx, form.tsx, label.tsx, checkbox.tsx, radio-group.tsx.
  • Buttons & toggles: button.tsx, toggle.tsx, toggle-group.tsx, button-variants.ts, toggle-variants.ts.
  • Layout & surface: card.tsx, dialog.tsx, drawer.tsx, sheet.tsx, accordion.tsx, tabs.tsx, table.tsx.
  • Navigation & overlays: dropdown-menu.tsx, navigation-menu.tsx, popover.tsx, tooltip.tsx, hover-card.tsx, context-menu.tsx, sidebar.tsx.
  • Feedback: alert.tsx, toast.tsx, toaster.tsx, progress.tsx, skeleton.tsx.
  • Misc: calendar.tsx, chart.tsx, avatar.tsx, badge.tsx, pagination.tsx, etc.

Guideline for new UI primitives:

  • Add new primitives in components/ui/ when they are generic and re-used across features.
  • Keep API consistent with existing shadcn patterns (props, variants, className merging).
  • If a component is domain-specific (e.g., RepairSummaryCard), put it under a feature folder instead.

Contexts

src/contexts/

Contexts provide app-wide state and services.

Key files:

  • AuthContext.tsx / auth-context.ts – authentication, user, role, tenant data.
  • ThemeContext.tsx / theme-context.ts – light/dark theme & toggling.
  • useAuth.ts / useTheme.ts – hook wrappers for contexts.

Guideline:

  • Contexts are reserved for global concerns (auth, theme, maybe feature flags), not arbitrary state.
  • For feature-scoped state (e.g. active tab in Inventory), prefer hooks + component state.

Hooks

src/hooks/

Hooks fall roughly into three categories:

  1. Domain/data hooks – talk to Supabase or other APIs.
  2. UI/behavior hooks – keyboard shortcuts, mobile optimizations, etc.
  3. Integration hooks – wrappers around external services (Stripe, Rewardful, etc.).

Examples (non-exhaustive):

  • Domain/data:

    • useInventory, useInventoryItems, useInventoryPhotos.
    • useOrders, useOrderColumns.
    • useClients.
    • useRepairSettings, useRepairSettingsForm.
    • useLibrary.
    • useSubscriptions, useSubscription.
    • useInvoices, usePayLinks.
    • useAnalytics, useDashboardAnalytics.
  • UI/behavior:

    • useKeyboardShortcuts – global keyboard handlers.
    • use-mobile-optimizations.tsx, use-mobile.tsx – viewport and mobile tweaks.
    • useUndoRedo – undo/redo stacks.
    • use-toast – toast API wrapper.
  • Integration:

    • useStripeCheckout, useStripePortal.
    • useRewardful – affiliate tracking.
    • useSignup, useSignupSession, useCheckout – join auth + Stripe flows.

Guideline:

  • Data fetching + mutations should live in hooks not in components when:
    • They are shared between multiple components, or
    • The logic is non-trivial (retry, error states, derived data).
  • Keep hooks composable: small hooks can be combined into larger facades (useInventory combines many smaller hooks).

lib & utils

src/lib/

Domain logic and configuration.

Notable files/folders:

  • subscription-utils.ts – plan logic, limits, lockout reasons.
  • repair-calculations.ts – all repair pricing formulas.
  • constants/ – shared constants.
  • validations/ – validation schemas (often zod).
  • featuresData.tsx, featuresTabData.tsx – marketing/feature config.
  • generateCertificatePDF.ts, generateInvoicePDF.ts – document generation.
  • seo.ts – SEO helpers.

Guideline:

  • Put pure domain logic here, especially when it doesn’t depend on React.
  • Prefer small, testable functions that can be used by hooks and components.

src/utils/

Generic helper functions that are not tied to a particular domain.

  • utils.ts – core helpers (formatters, type guards, small helpers).
  • utils/ – submodules if you need to group helpers (dates, numbers, etc.).

Guideline:

  • If code is domain-specific (e.g., trial day calculation with Stripe semantics), use lib/.
  • If it’s general-purpose (e.g., formatCurrency), use utils/.

Types

src/types/

Central location for TypeScript types used across the app.

Examples:

  • clients.tsClient, OrderWithClient, etc.
  • inventory.tsInventoryItem, ProductVariation.
  • invoices.ts, payLinks.ts.
  • owner.ts – owner/plan-related types.
  • library.tsLibraryItem, LibraryFile, LibraryFolder.

Guideline:

  • If multiple hooks/components share the same shape, define it in types/.
  • Keep types in sync with Supabase types and migrations (see supabase-types and supabase-tables.md).

Adding a new feature: checklist

When you add a new feature or flow, treat it as a first-class citizen in this structure.

1. Decide on the route and page

  • Add a route in App.tsx under the appropriate section (public vs protected, owner vs tenant).
  • Create a page under src/pages/<feature>/ or a top-level file if it’s a single screen.
    • Example: src/pages/tools/NewTool.tsx.

2. Design the data model (if needed)

  • If new tables are required:
    • Add migrations under supabase/migrations/.
    • Document them in api/supabase-tables.md.
  • If existing tables are sufficient, reuse them and document any new fields.

3. Add hooks

  • For Supabase access, create use<Feature> hooks in src/hooks/.
    • Example: useNewFeature.ts for queries/mutations.
  • Keep the hook API small and task-oriented (e.g., fetchItems, createItem, updateItem).

4. Build components

  • Put reusable pieces in src/components/<feature>/.
  • Use components/ui/ primitives for layout and controls.
  • Keep business logic in hooks/lib; components should focus on rendering and event handling.

5. Wire into providers & routes

  • If the feature depends on auth/role/plan:
    • Wrap the route with ProtectedRoute and pass requiredRole, feature, requiredPlan as needed.
  • If you need global state, consider whether it belongs in a new context or can live inside hooks.

6. Update docs

  • Add/extend entries in:
    • docs-site/docs/flows/<feature>.md – end-to-end flow.
    • docs-site/docs/api/supabase-tables.md – new tables/columns.
    • docs-site/docs/dev/conventions.md – if you introduce new patterns.

Where to go next