Folder Structure

A complete walkthrough of CareNova's project directory — what lives where and why it is organized that way.

Written By Dev010

Last updated 20 days ago

CareNova follows a consistent folder structure that mirrors the architecture — every file has a clear home and a clear reason for being there. This guide walks through each directory so you can navigate the codebase confidently from day one.

Root Directory

carenova-app/
├── app/                    # Next.js App Router — all routes and pages
├── components/             # Reusable UI components
├── lib/                    # Shared logic, actions, DB, cache, auth
├── contexts/               # React contexts (preferences, theme)
├── types/                  # Shared TypeScript type definitions
├── messages/               # next-intl translation files
├── docs/                   # Internal documentation
├── migrations/             # SQL migration files
├── scripts/                # Seed and utility scripts
├── public/                 # Static assets served at /
├── INSTALL.sql             # Master database installation SQL
├── middleware.ts            # Next.js middleware (auth, routing, license)
├── next.config.js          # Next.js configuration
├── tailwind.config.ts      # Tailwind CSS configuration
└── tsconfig.json           # TypeScript configuration

app/

The app/ directory contains all routes using the Next.js App Router file-system convention.

app/
├── layout.tsx              # Root layout — fonts, providers, globals
├── page.tsx                # Public landing page (clinic-type branching)
├── fonts.ts                # Font loading configuration
├── globals.css             # Global CSS and design tokens
├── _components/            # App-level shared components (e.g. landing FAQ)
├── api/                    # API route handlers
│   ├── patients/export/    # CSV export for patients
│   ├── appointments/export/# CSV export for appointments
│   ├── teeth-image/        # Teeth image handler for odontogram
│   └── cron/cleanup-auth/  # Auth cleanup cron job endpoint
├── (auth)/                 # Auth route group — no dashboard layout
│   ├── login/
│   ├── signup/
│   └── auth/callback/      # Supabase OAuth callback
├── (dashboard)/            # Dashboard route group — sidebar + header layout
│   └── dashboard/          # All dashboard module pages
├── blog/                   # Public blog index and post detail
├── appointment/            # Public appointment booking page
├── portal/                 # Patient portal (placeholder)
└── policies/[slug]/        # Dynamic policy pages

Route groups in parentheses — (auth) and (dashboard) — are a Next.js convention. The group name does not appear in the URL. They exist purely to apply a shared layout to everything inside them without affecting the route path.

app/(dashboard)/dashboard/

All dashboard module pages live here. Each module is a folder with its own page.tsx and optional sub-routes.

dashboard/
├── layout.tsx              # Dashboard layout — sidebar, header, auth check
├── page.tsx                # Role-specific dashboard home
├── _components/            # Dashboard-wide shared components
│   ├── app-sidebar.tsx     # Sidebar shell
│   ├── nav-main.tsx        # Navigation items with role/permission filters
│   ├── dashboard-header.tsx
│   ├── nav-user.tsx        # User menu in sidebar footer
│   ├── theme-switcher.tsx
│   ├── revenue-chart.tsx
│   ├── activity-chart.tsx
│   └── ...
├── patients/
│   ├── page.tsx            # Patient list
│   ├── new/page.tsx        # Create patient
│   └── [id]/
│       ├── page.tsx        # Patient detail
│       └── edit/page.tsx   # Edit patient
├── appointments/
│   ├── page.tsx
│   └── [id]/edit/page.tsx
├── calendar/page.tsx
├── medical-records/
│   ├── page.tsx
│   ├── vitals/page.tsx
│   ├── clinical-notes/page.tsx
│   ├── diagnoses/page.tsx
│   ├── attachments/page.tsx
│   └── visit-timeline/page.tsx
├── odontograms/page.tsx
├── prescriptions/
│   ├── page.tsx
│   └── new/page.tsx
├── test-reports/
│   ├── page.tsx
│   ├── new/page.tsx
│   ├── tests/page.tsx
│   ├── methodologies/page.tsx
│   ├── turnaround-times/page.tsx
│   ├── sample-types/page.tsx
│   └── categories/page.tsx
├── invoices/
│   ├── page.tsx
│   ├── new/page.tsx
│   └── [id]/page.tsx
├── payments/page.tsx
├── expenses/
│   ├── page.tsx
│   └── new/page.tsx
├── billing/
│   ├── page.tsx
│   └── new/page.tsx
├── services/page.tsx
├── departments/page.tsx
├── inventory/
│   ├── page.tsx
│   ├── new/page.tsx
│   └── [id]/
│       ├── page.tsx
│       └── edit/page.tsx
├── staff/page.tsx
├── lab-vendors/
│   ├── page.tsx
│   └── new/page.tsx
├── blog/
│   ├── page.tsx
│   └── categories/page.tsx
├── permissions/page.tsx
├── landing-settings/page.tsx
├── pending-approval/page.tsx
├── settings/page.tsx
└── coming-soon/page.tsx

components/

Reusable UI components that are referenced across multiple pages or modules.

components/
├── ui/                     # shadcn/ui primitives
│   ├── button.tsx
│   ├── card.tsx
│   ├── dialog.tsx
│   ├── input.tsx
│   ├── select.tsx
│   ├── sheet.tsx
│   ├── table.tsx
│   └── ...                 # All shadcn components
├── landing/                # Public landing page components
│   ├── dental/             # DentalHero, DentalServices, DentalFooter, etc.
│   ├── ophthalmology/      # OphthalmologyHero, OphthalmologyServices, etc.
│   └── general/            # GeneralHero, GeneralServices, etc.
├── dashboard/              # Shared dashboard components
│   ├── full-profile-button.tsx
│   └── ...
└── settings/               # Settings UI components
    └── landing/
        ├── landing-page-settings.tsx
        ├── colors-tab.tsx
        └── content-tab.tsx

Components specific to a single module live inside that module's folder under app/(dashboard)/dashboard/{module}/_components/ rather than in the top-level components/ directory. Only genuinely shared components belong at the top level.

lib/

The core of the application logic — server actions, database access, auth helpers, caching, validation schemas, and constants.

lib/
├── actions/                # Server Actions ("use server")
│   ├── patient-actions.ts
│   ├── appointment-actions.ts
│   ├── invoice-actions.ts
│   ├── payment-actions.ts
│   ├── expense-actions.ts
│   ├── medical-records-actions.ts
│   ├── prescription-actions.ts
│   ├── lab-test-actions.ts
│   ├── staff-actions.ts
│   ├── inventory-actions.ts
│   ├── service-actions.ts
│   ├── department-actions.ts
│   ├── odontogram-actions.ts
│   ├── permission-actions.ts
│   ├── auth-actions.ts
│   ├── clinic-actions.ts
│   ├── landing-settings-actions.ts
│   ├── blog-actions.ts
│   ├── blog-category-actions.ts
│   └── notification-actions.ts
├── auth/                   # Auth utilities
│   ├── index.ts            # getAuthUser, getCurrentUser, requireRole
│   ├── require-permission.ts # requirePermission, checkPermission
│   ├── audit.ts            # Auth audit log, rate limiting
│   ├── session-tracking.ts # Session create, revoke, cleanup
│   └── password-policy.ts  # Password validation rules
├── cache/                  # Caching helpers
│   ├── index.ts            # getCachedCurrentUser, getCachedClinic, etc.
│   └── invalidators.ts     # Cache invalidation functions
├── constants/              # Shared constants
│   ├── permissions.ts      # PERMISSION_KEYS, DEFAULT_ROLE_PERMISSIONS
│   ├── expenses.ts         # Expense category constants
│   └── landing-defaults.ts # Default settings per clinic type
├── data/                   # Static default data
│   └── landing-defaults/
│       ├── dental.json
│       ├── ophthalmology.json
│       └── general.json
├── db/                     # Database layer
│   ├── index.ts            # Drizzle client instance
│   ├── schema.ts           # All table definitions (single source of truth)
│   └── seed.ts             # Seed script
├── supabase/               # Supabase client helpers
│   ├── server.ts           # createClient() for server components/actions
│   ├── middleware.ts       # updateSession() for middleware
│   └── admin.ts            # getSupabaseAdmin() using service role key
├── validations/            # Zod schemas
│   ├── patient.ts
│   ├── appointment.ts
│   ├── invoice.ts
│   └── ...
├── preferences/            # User/clinic preference constants
│   └── constants.ts        # Cookie names, locale options, etc.
├── utils/                  # General utility functions
│   └── safe-async.ts       # Background task error wrapper
├── config.ts               # siteConfig (debug flag, site URL, etc.)
├── debug.ts                # Conditional debug logger
└── i18n.ts                 # next-intl i18n configuration

Key Files to Know

These files have outsized importance in the codebase — understanding them makes everything else easier to navigate.

File

Why It Matters

lib/db/schema.ts

Every table, column, and relationship defined in one place — the source of truth for the entire data model

lib/constants/permissions.ts

All permission keys and default role assignments — edit this when adding new permissions

lib/auth/index.ts

requireRole() and getCurrentUser() — called at the top of every server action

middleware.ts

First code that runs on every request — auth, routing, license, and demo cookie logic

app/(dashboard)/dashboard/layout.tsx

Wraps every dashboard page — sidebar, header, and top-level auth check

app/(dashboard)/dashboard/_components/nav-main.tsx

Sidebar navigation — add new module nav items here

INSTALL.sql

Master SQL file — run this in Supabase to create all tables from scratch

messages/

Translation files for next-intl. Organized by locale at the top level for dashboard strings, and by clinic type and locale for landing page strings.

messages/
├── en.json                 # Dashboard translations — English
├── fr.json                 # Dashboard translations — French
├── es.json                 # Dashboard translations — Spanish
├── ar.json                 # Dashboard translations — Arabic
└── landing/
    ├── dental/
    │   ├── en.json
    │   ├── fr.json
    │   ├── es.json
    │   └── ar.json
    ├── general/
    │   └── ...
    └── ophthalmology/
        └── ...

public/

Static assets served directly by the web server at the root URL.

public/
├── landing/
│   ├── dental/             # Default dental landing images
│   ├── ophthalmology/      # Default ophthalmology landing images
│   └── general/            # Default general landing images
├── teeth/                  # Teeth images for odontogram
│   └── ...                 # Populated by npm run download-teeth
└── ...                     # Favicons, og images, etc.

Landing images in public/landing/ are the fallback defaults. When a clinic uploads custom images via Landing Settings, those Supabase Storage URLs are used instead.