Complete technology stack documentation for Harvous, including versions, dependencies, and deployment configuration.
Production is a React SPA + Hono API:
/spa— React SPA (Vite): the full app users see. Handles all routes (dashboard, threads, notes, spaces, profile, sign-in, shared content, etc.). Built output is copied todist/and served as staticindex.html+ assets./server— Hono API: a single Node server that handles all/api/*requests. Bundled as one Netlify serverless function (netlify/functions/api.cjs). Database access, auth, and business logic live here.
The Netlify build runs npm run build (inject SW + build:api + build:spa). Publish directory is dist-spa/. Database schema lives in server/db/schema.ts (Drizzle + Supabase Postgres).
Netlify routing: public/_redirects sends app paths to /index.html (SPA); /api/* is handled by the SSR function (Hono). Do not add a catch-all that would send API requests to the SPA.
Hono (server/) - Production API: all /api/* in one Netlify function
React 19.2.0 - Full SPA (production frontend)
Vite - SPA build tool
TanStack Router - Client-side routing within the SPA
TanStack Query - Server state management and caching
TypeScript 5.9.2 - Type safety
Vanilla CSS - Semantic CSS classes (migrated from Tailwind)
Drizzle ORM - Schema and Supabase Postgres access (server/db/)
- Purpose: Production API — all
/api/*endpoints, database access, auth, business logic - Deployment: Single Netlify serverless function (
netlify/functions/api.cjs) - Handles: Notes, threads, spaces, user, referral, billing, shared content, invitations, webhooks, etc.
- Dev: Run with
npm run dev:all(API on 3001, SPA on 4322)
- Version: 19.2.0
- Purpose: Full single-page application for the authenticated user experience
- Build Tool: Vite
- Entry:
spa/src/main.tsx→spa/src/App.tsx - Key Features:
- Client-side routing via TanStack Router
- Server state via TanStack Query (with caching and stale-time tuning)
- Persistent navigation state via localStorage
- Route transition animations (CSS
routeFadeIn) app:route-changeevent dispatched on route change so components and scripts can refresh
- Purpose: Client-side routing within the SPA
- Route Definition:
spa/src/router.tsx - Route Tree: Two layout groups —
AppLayout(authenticated) andAuthLayout(sign-in/up) - Pattern: URL slugs are bare IDs (e.g.
/thread/abc123); DB uses prefixed IDs (thread_abc123)
- Purpose: Server state management, caching, and background refetching
- staleTime tuning: Thread queries 60s, note queries 30s — prevents empty-state flash on navigation
- Pattern: Cache hit before network;
prefetchendpoints preload data for instant navigation
- Purpose: Shared React components used by the SPA: editor, navigation, panels
- Location:
src/components/react/ - Note: The SPA imports these directly
- Version: 5.9.2
- Purpose: Type safety and developer experience
- Configuration: Strict mode enabled
- Path Aliases:
@/maps tosrc/
Supabase Postgres - Managed PostgreSQL database (server/db/schema.ts; SUPABASE_* env)
Clerk - Authentication and user management
- Purpose: Managed PostgreSQL database
- Schema:
server/db/schema.ts(Drizzle ORM) - Client:
server/db/client.ts— usespostgres+drizzle-orm/postgres-js - Env:
SUPABASE_DATABASE_URL(pooler) andSUPABASE_DIRECT_URL(direct) - Migrations:
npm run db:push(Drizzle Kit push to Supabase Postgres)
- Purpose: Authentication and user management
- Integration: Middleware-based authentication
- Features:
- User authentication
- Session management
- User profile data (cached in UserMetadata)
- Environment Variables:
PUBLIC_CLERK_PUBLISHABLE_KEYCLERK_SECRET_KEY
Tiptap - Modern rich text editor
Radix UI - Accessible component primitives (dialogs, popovers, etc.)
Vaul - Mobile bottom drawer (Radix Dialog–based); see src/components/ui/drawer.tsx
Sonner - Toast notifications (SPA + shared toast helpers)
Shadcn-style - Component design system
Font Awesome + Lucide - Icons
- Purpose: Rich text editing
- Integration: React components
- Features:
- Bold, italic, underline
- Ordered/unordered lists
- ProseMirror-based
- TypeScript support
- Purpose: Accessible component primitives
- Usage: Base components for complex UI patterns
- Features:
- Accessibility built-in
- Unstyled components
- Keyboard navigation
- Purpose: Slide-up mobile panels (
BottomSheet.tsx,MobileNavigation.tsxspace switcher) - Package:
vaul— built on@radix-ui/react-dialog - Integration:
src/components/ui/drawer.tsxwraps Vaul with Harvous classes (sheet-overlay,bottom-sheet-content,data-side="bottom"). Vaul’sstyle.cssis imported fromspa/src/main.tsx(path resolves vianode_modulesbecause the package does not export./style.cssinexports). - Related CSS:
src/styles/panels.css(.bottom-sheet-content,.bottom-sheet__inner, full-height drawers),src/styles/global.css(overlay z-index / safe area)
- Purpose: In-app toast notifications
- Package:
sonner - SPA:
spa/src/App.tsxmounts<Toaster />and wireswindow.toastto the same Sonner instance (seeSPA_MIGRATION.mdfor the Vite root / module-instance note) - Shared helpers:
src/utils/toast.ts,src/components/react/ToastProvider.tsxwhere used outside the SPA boundary
Harvous’s motion direction for drawers and toasts is inspired by Emil Kowalski. We ship his open-source libraries Vaul (bottom drawer) and Sonner (toast stack) alongside our own styling and layout rules.
- Purpose: Icon system
- Usage: SVG imports from
@fortawesome/fontawesome-free/svgs/solid/ - Pattern: Direct SVG imports for optimal performance
Netlify - Serverless hosting
Output: SPA (Vite) - Static index.html + JS/CSS (production frontend)
Output: Hono (server/)- Single serverless function for all /api/*
- Purpose: Serverless hosting and deployment
- Configuration:
netlify.toml - Features:
- Automatic deployments
- One serverless function for the API (Hono from
server/) - Environment variable management
- Redirect rules send app paths to
/index.html(SPA);/api/*goes to the function
- Build:
npm run build— inject SW version, thenbuild:api(Hono →netlify/functions/api.cjs) andbuild:spa(Vite →dist-spa/). Publish directory isdist-spa/. - SPA: Static
index.html+ hashed JS/CSS fromspa/, served from CDN. - API: Single Netlify function (
netlify/functions/api.cjs) handles all/api/*(Hono app fromserver/).
- Required Version: >=22.0.0 (specified in
package.jsonengines) - Package Manager: npm or pnpm
- Schema Sync:
npm run db:sync- Sync local database schema - Schema Push:
npm run db:push- Push schema to remote - Schema Check:
npm run db:check- Verify database state
- Dev:
npm run dev/npm run dev:all— Hono API (3001) + SPA (4322); full-stack with production parity - SPA only:
npm run dev:spa— Vite SPA (4322); API must be running for/apito work - Production build:
npm run build— inject SW + build:api + build:spa (no Astro) - Preview:
npm run preview— Preview SPA build (port 4322)
PUBLIC_CLERK_PUBLISHABLE_KEY- Clerk publishable key (server/API)VITE_CLERK_PUBLISHABLE_KEY- Clerk publishable key (SPA/Vite build)CLERK_SECRET_KEY- Clerk secret key (server-side API)SUPABASE_DATABASE_URL- Supabase connection string for runtime/API (pooler URL)SUPABASE_DIRECT_URL- Supabase direct connection string for migrations
BIBLE_API_KEY- Bible.org API key for scripture fetchingWEBFLOW_INBOX_API_TOKEN- Webflow CMS integration (for inbox/webhook operations)WEBFLOW_CHANGELOG_API_TOKEN- Webflow CMS integration (for changelog sync, requires cms:write scope)
- Automatic Version Bumps: Via git hooks
feat:→ minor bump (0.10.0 → 0.11.0)fix:→ patch bump (0.10.0 → 0.10.1)BREAKING CHANGE→ major bump (0.10.0 → 1.0.0)
- Manual Bump:
npm run version:bump
- ARCHITECTURE.md - Overall system architecture
- PROJECT_STRUCTURE.md - Project organization
- README.md - Quick start and setup