Architecture

Conventions

Code style, naming, and structural conventions across the monorepo

App Structure

Most apps follow the src/ directory convention with a Convex backend:

apps/{app}/
├── src/
│   ├── app/           # Next.js App Router pages
│   ├── components/    # App-specific components
│   │   └── features/  # Feature-based organization
│   ├── hooks/         # App-specific hooks
│   ├── lib/           # App-specific utilities
│   └── types/         # App-specific types
├── convex/            # Convex backend (per-app deployment)
├── e2e/               # Playwright E2E tests
├── tests/             # Vitest unit tests
└── public/            # Static assets

Exception: Qript uses PostgreSQL + Drizzle ORM + better-auth instead of Convex:

apps/qript/
├── src/
│   └── lib/db/        # Drizzle schema
├── drizzle/           # Drizzle migrations
└── drizzle.config.ts  # Drizzle Kit config

Convex Backend Patterns

  • Each app has its own Convex deployment
  • Use convex/model/ for shared business logic helpers
  • Keep public API functions thin — delegate to the model layer
  • Use internal.* for server-to-server calls

Testing Conventions

  • Unit tests: Vitest with @hn-monorepo/testing helpers
  • E2E tests: Playwright with shared fixtures
  • Shared mocks: Available for Next.js, Convex, and i18n
  • Coverage target: 60%+ for shared packages
  • Convex business logic: Unit tests recommended
  • New user flows: E2E test recommended
  • Bug fixes: Regression test required
  • Playwright: Page object model for complex flows, selectors in e2e/selectors/

Code Style

  • Biome for formatting and linting (not ESLint/Prettier)
  • React Compiler enabled — no manual memo/useCallback needed
  • TypeScript strict mode across all apps and packages
  • Server Components preferred — use "use client" only when needed

Naming Conventions

TypeConventionExample
Fileskebab-casevocabulary-set-card.tsx
ComponentsPascalCaseVocabularySetCard
Hooksuse prefix, camelCaseuseVocabularySet
Convex functionscamelCasecreateVocabularySet
TypesPascalCase, no I prefixVocabularySet
ConstantsSCREAMING_SNAKE_CASEMAX_RETRIES
Featuresdirectory-basedcomponents/features/<feature>/

Import Order

Imports should follow this order:

  1. External packages (react, next, convex)
  2. Monorepo packages (@hn-monorepo/*)
  3. Local aliases (@/)

Error Handling

  • Client-side errors: Toast notifications via Sonner
  • Convex mutations: Auth-check first, then validation, then business logic
  • API routes: Structured error responses with status codes
HanseNexus 2026