This is a monorepo with the following structure:
apps/dash/- Main dashboard application (Next.js)apps/status-page/- Public status page application (Next.js)apps/docs/- Documentation site (Next.js)
packages/api/- Shared API logic and types (oRPC)packages/auth/- Authentication logic and utilities (Better Auth)packages/db/- Database schema and utilities (Drizzle ORM)packages/config/- Shared configurationpackages/scheduler/- Job scheduling utilities
pnpm run dev- Start all apps in development mode
All database operations should be run from the web workspace:
pnpm run db:push- Push schema changes to databasepnpm run db:studio- Open database studiopnpm run db:generate- Generate Drizzle filespnpm run db:migrate- Run database migrations
Database schema files are located in packages/db/src/schema/
Schema includes:
auth.ts- User authentication and session managementmonitors.ts- Monitor configurationsstatus-pages.ts- Status page definitionsincidents.ts- Incident trackingmaintenance.ts- Scheduled maintenancestatus-updates.ts- Status update entriesintegrations.ts- Third-party integrations (Discord, Slack, etc.)workers.ts- Worker configurationsssl-notifications.ts- SSL certificate expiry notificationsconfiguration.ts- Global configuration settings
- oRPC endpoints are in
packages/api/src/api/ - Client-side API utils are in
apps/web/src/utils/api.ts
Authentication is enabled in this project:
- Server auth logic is in
packages/auth/src/lib/auth.ts - Web app auth client is in
apps/web/src/lib/auth-client.ts
- This is a Turborepo monorepo using pnpm workspaces
- Each app has its own
package.jsonand dependencies - Run commands from the root to execute across all workspaces
- Run workspace-specific commands with
pnpm run command-name - Turborepo handles build caching and parallel execution
- Consistency: Rely on Prettier and ESLint to enforce standard formatting.
- Imports: Organize imports logically (External packages -> Internal monorepo packages -> Relative imports).
- Naming: Use
camelCasefor functions/variables andPascalCasefor components/interfaces. Make names descriptive (e.g.,fetchUserDatainstead ofgetData).
- Single Responsibility: Functions should aim to do one thing well.
- Guard Clauses: Use early returns to reduce nesting and cognitive load.
- Size: Keep functions small. distinct logic blocks should often be extracted into helper functions.
- Parameters: Limit the number of arguments (max ~3). Use a configuration object for more complex signatures.
- Self-Documenting Code First: Write code that is self-explanatory through clear function names, variable names, and structure. If your function name and code clearly describe what it does, do not add unnecessary comments.
- Explain "Why", Not "What": The code itself explains what is happening. Use comments to explain the intent, business logic, or complex decisions behind the code.
- Avoid Clutter: Do not comment obvious logic (e.g.,
// Update countabovecount++). Unnecessary comments add noise and maintenance burden. - Function headers: Use JSDoc/TSDoc for public-facing utilities to document params and return values, but only when the signature isn't self-evident.
- TODOs: Use
// TODO:to mark areas for improvement, but address them sooner rather than later.
- App has two variants, self-hosted and cloud-hosted. We define if this instance is self-hosted with NEXT_PUBLIC_SELF_HOSTED environment variable.
- Some features are only available in cloud-hosted variant, or look different in self-hosted variant.