Levandor CRM - Agent Quick Context

Agent Onboarding

Read this first when working on the Levandor CRM project.

What is it?

Personal business management CRM. React 19 SPA → Supabase (no custom backend). Monorepo with pnpm workspaces.

Critical Knowledge

Data Layer Pattern

Component → useMutation/useQuery hook → supabaseQuery<T>() → Supabase client → Postgres
                                              ↓
                                    TanStack Query cache invalidation
  • All queries go through supabaseQuery() at web/src/lib/query.ts - wraps Supabase {data, error} and throws errors
  • 80+ hooks in web/src/lib/hooks/ with barrel export
  • Query hooks: useSupabase() + useQuery() + supabaseQuery<ViewType>()
  • Mutation hooks: useMutation() + queryClient.invalidateQueries() in onSuccess

Auth Flow

Clerk manages sessions/JWTs → Supabase receives Clerk tokens via custom template → RLS enforces access

TypeScript Strictness

  • tsc -b (project build mode) in CI - stricter than tsc --noEmit
  • verbatimModuleSyntax: true - explicit type keyword for type imports
  • Always verify: cd web && npx tsc -b before pushing

Bilingual

  • EN + HU required for all UI strings
  • useTranslation() hook from i18next
  • Locale files: web/src/locales/en.json and hu.json

Architecture Quick Ref

ComponentLocationNotes
Admin CRMweb/React 19, main SPA
Client portaluserspace/Planned, separate Clerk instance
UI primitivespackages/ui/shadcn/Radix, CLI-managed, don’t edit
Shared typespackages/shared/src/db-mappings.tsDomain type aliases
Generated typespackages/shared/src/database.types.ts~2400 lines, auto-generated
Edge functionsweb/supabase/functions/Deno, 7+ functions
Migrationsweb/supabase/migrations/SQL, sequential

Code Conventions

ConventionRule
File namingPascalCase .tsx components, camelCase use*.ts hooks, kebab-case utils
ExportsNamed exports for components/hooks, default for pages
ImportsReact first → third-party → internal → hooks → type-only last
StylingTailwind + cn() utility, dark theme, semantic tokens
GitConventional commits: feat(scope):, fix(scope):, chore:
PushDirect to origin/master (no PR workflow, solo dev)
DnDNever put dnd-kit refs on Radix ScrollArea - use plain div wrapper

Key Domain Types

TypeSourceNotes
TaskViewdb-mappings.tsTask with relations
ProjectViewdb-mappings.tsProject with details
InvoiceViewdb-mappings.tsHas name field, NOT description
WorkflowStatusdb-mappings.tsHas category field, NOT is_closed
DayPlanBlockViewdb-mappings.tsIncludes joined task/project/related_tasks
BudgetEnvelopedb-mappings.tsFour types: BUDGET, SAVINGS_GOAL, SAVINGS_TARGET, TRACKING

Edge Functions

FunctionPurpose
billingo-sync-statusesInvoice status sync from Billingo
billingo-sync-inboundVendor bill sync from Billingo
sync-outboundOutbound data sync
rss-fetchRSS feed ingestion
notifyNotifications
market-dataMarket/exchange rate data
service-healthHealth checks
ingest-emailEmail ingestion (via CF Worker)

Context Providers

  • SupabaseProvider - Authenticated Supabase client
  • CurrentPersonProvider - Logged-in person context
  • CurrencyProvider - HUF/EUR with live exchange rates
  • SidebarProvider - UI collapse state

Common Commands

cd web && pnpm dev          # Dev server
cd web && npx tsc -b        # Type check (CI-equivalent)
cd web && pnpm build        # Production build
pnpm install                # Install deps
# After schema changes:
npx supabase gen types      # Regenerate database.types.ts

Deeper Reading