Design Principles
Every feature in Codapult is packaged as a self-contained module with its own directories, routes, components, and database tables. Modules follow three rules:
- Independent — each module lives in its own directories and can be deleted without breaking other modules.
- Core-dependent only — modules depend on the Core layer (Auth, Database, Rate Limiting, Validation), not on each other, unless explicitly noted.
- CLI-removable — the interactive setup wizard can strip modules automatically.
Module Map
| Module | Directories | Dependencies | Removable | Env Toggle |
|---|---|---|---|---|
| Auth | src/lib/auth/, src/app/[locale]/(auth)/ | Core (required) | No | |
| Database | src/lib/db/ | Core (required) | No | |
| AI Chat | src/app/[locale]/(dashboard)/dashboard/ai-chat/, src/app/api/chat/, src/components/ai/ | None | Yes | ENABLE_AI_CHAT |
| Billing | src/lib/payments/, src/lib/actions/billing.ts, src/app/api/webhooks/ | None | Yes | |
| Blog | src/app/[locale]/(marketing)/blog/, src/components/blog/, src/lib/blog/, content/blog/ | None | Yes | ENABLE_BLOG |
| Teams | src/app/[locale]/(dashboard)/dashboard/teams/, src/app/[locale]/invite/ | Auth | Yes | ENABLE_TEAMS |
| Notifications | src/lib/notifications/, src/components/dashboard/NotificationBell.tsx | Auth | Yes | |
| Feature Flags | src/lib/feature-flags.ts, src/app/[locale]/admin/feature-flags/ | DB | Yes | |
| File Uploads | src/lib/storage/, src/app/api/upload/ | Auth | Yes | |
| Waitlist | src/app/[locale]/(marketing)/waitlist/ | Yes | ENABLE_WAITLIST | |
| Welcome Page | src/app/[locale]/(marketing)/welcome/ | Billing, Auth | Yes | |
| API Keys | src/lib/api-keys.ts | Auth, DB | Yes | |
| Usage Credits | src/lib/usage.ts | Auth, DB | Yes | |
| Activity Log | src/lib/activity-log.ts, src/app/[locale]/admin/activity/ | DB | Yes | ENABLE_AUDIT_LOG |
| Webhook Log | src/lib/webhook-log.ts, src/app/[locale]/admin/webhooks/ | DB | Yes | |
| Support Widget | src/components/support/SupportWidget.tsx | None | Yes | |
src/lib/email/ | Resend | Yes | ||
| i18n | src/i18n/, messages/ | next-intl | Yes | |
| Analytics (PostHog) | src/components/analytics/ | PostHog | Yes | |
| SEO | src/app/sitemap.ts, src/app/robots.ts | None | Yes | |
| Sentry | src/instrumentation*.ts, src/sentry.*.ts | @sentry/nextjs | Yes | |
| GraphQL API | src/lib/graphql/, src/app/api/graphql/ | graphql-yoga | Yes | |
| Enterprise SSO | src/lib/sso/ | None | Yes | ENABLE_SSO |
| Help Center | src/lib/docs/, src/app/[locale]/(marketing)/docs/, content/docs/ | None | Yes | ENABLE_HELP_CENTER |
| A/B Testing | src/lib/experiments/ | DB | Yes | ENABLE_EXPERIMENTS |
| Feature Requests | src/lib/feature-requests/ | DB | Yes | ENABLE_FEATURE_REQUESTS |
| Stripe Connect | src/lib/payments/connect.ts | Stripe | Yes | |
| Event Store | src/lib/event-store/ | DB | Yes | |
| White-labeling | src/lib/white-label/ | DB | Yes | ENABLE_BRANDING |
| GDPR | src/lib/gdpr/ | DB | Yes | |
| Outgoing Webhooks | src/lib/outgoing-webhooks/ | DB | Yes | ENABLE_WEBHOOKS |
| Drip Campaigns | src/lib/drip-campaigns/ | Email, Jobs | Yes | ENABLE_DRIP_CAMPAIGNS |
| Onboarding Tours | src/lib/onboarding/ | DB | Yes | ENABLE_ONBOARDING |
| Analytics (Self-serve) | src/lib/analytics/ | DB | Yes | ENABLE_ANALYTICS |
| Custom Domains | src/lib/custom-domains/ | DB | Yes | |
| Workflows | src/lib/workflows/ | Yes | ENABLE_WORKFLOWS | |
| Referrals | src/lib/referrals/ | DB | Yes | ENABLE_REFERRALS |
| OpenTelemetry | src/lib/telemetry/ | @opentelemetry/* | Yes | |
| Changelog Widget | src/components/dashboard/ChangelogWidget.tsx | None | Yes | ENABLE_CHANGELOG |
| RAG Pipeline | src/lib/ai/rag.ts, src/lib/ai/embeddings.ts | @ai-sdk/openai | Yes | |
| SCIM Provisioning | src/lib/scim/ | Teams | Yes | |
| Chat Memory | src/lib/ai/conversations.ts | AI Chat, DB | Yes | |
| Scheduled Reports | src/lib/scheduled-reports/ | Email, Jobs | Yes | ENABLE_REPORTS |
| API Versioning | src/lib/api-version.ts | None | Yes | |
| Audit Log (User) | src/app/api/audit-log/ | Activity Log | Yes |
Removal vs. Disabling: Two Different Operations
Codapult has two separate ways to exclude a module from your product. Understanding the difference before setup matters.
Removing a module (CLI or manual, permanent): The module's code is deleted from your repository — files, routes, components, database tables, and imports. The build gets smaller and the codebase stays clean. Removing a module via the CLI wizard cannot be undone through the CLI. If you need the module back later, you add it manually from the Codapult source repository.
Disabling a module (env var, reversible): If a module is present in the codebase but you are not ready to use it, you can hide it via an environment variable. The code stays in the repo; the feature is invisible to users. Flip the variable to re-enable it at any time, with no code changes.
Practical rule: Remove modules you are confident are outside your product's scope. Keep modules you are unsure about — disable them via env var until you need them. The cost of keeping code you do not use yet is low. The cost of manually re-adding removed code is not.
How to Remove a Module
CLI Wizard (Recommended)
Run the interactive setup wizard and deselect the modules you don't need:
npx @codapult/cli setup
The wizard automatically deletes files, removes imports, cleans up navigation, and updates the schema.
This is permanent. The wizard deletes files, imports, and schema tables — it doesn't just hide them. If you're not sure whether you'll need a module later, don't remove it here. Leave it in and turn it off with the matching
ENABLE_*environment variable instead (see the Module Map below or Environment Variables) — that's reversible, the CLI removal isn't.
Manual Removal
For finer control, remove a module by hand:
- Delete the module's directories (see the table above).
- Remove all imports referencing the deleted module.
- Remove database tables from
src/lib/db/schema.tsand regenerate migrations. - Remove navigation links from
src/config/navigation.ts,Sidebar.tsx, admin layout, and marketing navbar. - Uninstall npm dependencies unique to the module.
- Remove environment variables from
.env.example.
Example: Removing AI Chat
# Delete files
rm -rf src/app/\\[locale\\]/\(dashboard\)/dashboard/ai-chat
rm -rf src/app/api/chat
rm -rf src/components/ai
# Remove the AI Chat nav item from Sidebar.tsx
# Edit src/components/dashboard/Sidebar.tsx
# Uninstall dependencies (if not used elsewhere)
pnpm remove @ai-sdk/openai @ai-sdk/anthropic ai @ai-sdk/react
# Remove env vars from .env.example:
# OPENAI_API_KEY, ANTHROPIC_API_KEY, EMBEDDING_PROVIDER,
# VECTOR_STORE_PROVIDER, OLLAMA_BASE_URL, OLLAMA_EMBEDDING_MODEL
Example: Removing Teams
# Delete files
rm -rf src/app/\\[locale\\]/\(dashboard\)/dashboard/teams
rm -rf src/app/\\[locale\\]/invite
rm src/components/dashboard/TeamSwitcher.tsx
rm src/components/dashboard/TeamSettings.tsx
rm src/components/dashboard/AcceptInvitationButton.tsx
rm src/lib/db/organizations.ts
rm src/lib/actions/organizations.ts
# Remove organization tables from src/lib/db/schema.ts:
# organization, organization_member, organization_invitation
# Remove TeamSwitcher from Sidebar.tsx
# Regenerate migrations
pnpm run db:generate
Dependency Boundaries
Modules form a layered dependency graph. The Core layer is required; everything above it is optional and independently removable.
┌───────────────────────────────────────────────┐
│ Core Layer │
│ (Auth, Database, Rate Limiting, Validation) │
└─────────────────────┬─────────────────────────┘
│
┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Billing │ │ Teams │ │ Admin │
└─────────┘ └─────────┘ └─────────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Usage │ │ RBAC │ │ Feature │
│ Credits │ │ │ │ Flags │
└─────────┘ └─────────┘ └─────────┘
Modules only depend on the Core layer. They do not depend on each other unless explicitly noted in the Dependencies column (for example, SCIM Provisioning depends on Teams, and Chat Memory depends on AI Chat).