Use this document when iterating on Devus outside of Lovable (VS Code, Cursor, WebStorm, etc.). It captures every architectural decision so the codebase stays consistent regardless of who — or what — is editing it.
- Quick Start
- Project Architecture
- Tech Stack & Versions
- Design System Rules
- Component Conventions
- Routing & Pages
- State Management
- Backend (Lovable Cloud / Supabase)
- Edge Functions
- Authentication
- Data Layer
- Animation Guidelines
- MCP / Context7 Usage
- Testing
- Do-Not-Touch Files
- Commit & PR Conventions
# Install dependencies (use bun — it's what Lovable uses)
bun install
# Start dev server
bun run dev # http://localhost:8080
# Run tests
bun run test
# Production build
bun run buildEnvironment variables are managed via .env (auto-generated by Lovable Cloud). Never edit .env manually. If you need additional secrets, add them through Lovable's secrets manager or Supabase dashboard.
src/
├── components/ # Reusable UI components
│ ├── ui/ # shadcn/ui primitives (DO NOT customize inline)
│ └── dashboard/ # Dashboard-specific components
├── contexts/ # React contexts (AuthContext)
├── hooks/ # Custom hooks (use-tools, use-ai-search, etc.)
├── integrations/
│ └── supabase/ # Auto-generated client & types — DO NOT EDIT
├── lib/
│ ├── data.ts # Static tool catalog + query helpers
│ ├── types.ts # Shared TypeScript interfaces
│ └── utils.ts # cn() and utility functions
├── pages/ # Route-level page components
├── index.css # Design system tokens (THE source of truth)
└── main.tsx # App entry point
supabase/
├── config.toml # Auto-managed — DO NOT EDIT
└── functions/ # Deno edge functions
├── search-tools/ # AI-powered tool search
└── weekly-tools/ # Weekly tool discovery via Perplexity
| Layer | Technology | Notes |
|---|---|---|
| Framework | React 18 | No Next.js, no SSR |
| Build | Vite 5 | SWC plugin for React |
| Language | TypeScript (strict: false) | noImplicitAny: false for flexibility |
| Styling | Tailwind CSS 3.4 | tailwindcss-animate plugin |
| Components | shadcn/ui (Radix primitives) | Default style, CSS variables enabled |
| Animation | Framer Motion 12 | Primary animation library |
| Routing | React Router DOM 6 | Client-side SPA routing |
| State | React Query 5 + React Context | No Redux, no Zustand |
| Backend | Supabase (via Lovable Cloud) | Auth, DB, Edge Functions, Storage |
| Package Manager | bun | Lockfile: bun.lockb |
When adding packages outside Lovable, use Context7 MCP (see MCP section) to verify correct package names and latest stable versions before installing:
bun add <package>@<version>All colors flow through CSS custom properties defined in src/index.css and mapped in tailwind.config.ts.
index.css (HSL values) → tailwind.config.ts (hsl(var(--token))) → Components (Tailwind classes)
| Token | Purpose | Example Class |
|---|---|---|
--background |
Page background | bg-background |
--foreground |
Primary text | text-foreground |
--primary |
Brand cyan accent | bg-primary, text-primary |
--card |
Card backgrounds | bg-card |
--muted |
Subdued backgrounds | bg-muted |
--muted-foreground |
Secondary text | text-muted-foreground |
--border |
Borders | border-border |
--glow |
Cyan glow effects | text-glow |
--surface |
Elevated surfaces | bg-surface |
--dash-* |
Dashboard-specific tokens | bg-dash-card |
<div className="bg-black text-white border-gray-700"> // ← raw colors
<div className="bg-[#0a0a0f]"> // ← hardcoded hex<div className="bg-background text-foreground border-border">
<div className="bg-surface-elevated">| Font | Variable | Usage |
|---|---|---|
| Sora | font-sans |
Landing page, headings |
| Inter | font-dash |
Dashboard UI |
| JetBrains Mono | font-mono |
Code snippets, badges |
The landing page uses a consistent glass utility. Apply it via:
<div className="glass glass-hover rounded-xl p-5">These classes are defined in index.css under @layer components.
- Components:
PascalCase.tsx(e.g.,ToolStackShowcase.tsx) - Hooks:
use-kebab-case.ts(e.g.,use-tools.ts) - Pages:
PascalCase.tsxinsrc/pages/
// 1. Imports (React, libraries, local)
import { useState } from "react";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
// 2. Interface
interface MyComponentProps {
title: string;
onAction: () => void;
}
// 3. Named export (no default exports for components)
export function MyComponent({ title, onAction }: MyComponentProps) {
// 4. Hooks first
const [state, setState] = useState(false);
// 5. Handlers
const handleClick = () => { ... };
// 6. Render
return ( ... );
}Always use the @/ alias:
import { tools } from "@/lib/data"; // ✅
import { tools } from "../../lib/data"; // ❌- Live in
src/components/ui/ - Customize via variants in the component file, not inline styles
- When adding new shadcn components, use the CLI:
bunx shadcn@latest add <component>
| Route | Page Component | Auth Required |
|---|---|---|
/ |
Index.tsx |
No |
/tool/:id |
ToolDetail.tsx |
No |
/dashboard |
Dashboard.tsx |
Yes |
/submit |
Submit.tsx |
Yes |
/favorites |
Redirects → /dashboard |
— |
* |
NotFound.tsx |
No |
Protected routes redirect unauthenticated users to / with state: { openAuth: true }.
- AuthContext (
src/contexts/AuthContext.tsx): User session, profile, auth actions - Custom hooks (
src/hooks/): Domain-specific logic (favorites, tools, search) - React Query: Server state (weekly tools cache, etc.)
- localStorage: Offline fallback for favorites/upvotes when unauthenticated
- No global state libraries (Redux, Zustand, Jotai)
- Colocate state as close to usage as possible
- Use React Query for anything fetched from Supabase
- Auth state always comes from
useAuth()hook
import { supabase } from "@/integrations/supabase/client";Never create additional Supabase clients. The auto-generated one handles auth tokens automatically.
| Table | Purpose | RLS |
|---|---|---|
profiles |
User profile data (synced from auth) | Yes |
discovered_tools |
AI-discovered tools | Yes |
weekly_tools_cache |
Weekly tool drops cache | Yes |
All schema changes must go through Lovable's migration tool or SQL files in supabase/migrations/. Never alter the schema via direct SQL in production.
Every table has RLS enabled. When adding new tables:
- Always enable RLS
- Create policies for SELECT, INSERT, UPDATE, DELETE as needed
- Use
auth.uid()for user-scoped data
Located in supabase/functions/. Written in Deno (TypeScript).
| Function | Purpose | Required Secrets |
|---|---|---|
search-tools |
Firecrawl-powered tool search | FIRECRAWL_API_KEY |
weekly-tools |
Perplexity + Gemini weekly discovery | PERPLEXITY_API_KEY, LOVABLE_API_KEY |
supabase functions new my-functionStructure:
supabase/functions/my-function/
└── index.ts
Always include CORS headers:
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};- Provider: Supabase Auth (email/password, Google OAuth, GitHub OAuth)
- Context:
AuthProviderwraps the entire app inApp.tsx - Profile sync:
handle_new_user()trigger creates aprofilesrow on signup - Email confirmation: Enabled by default — do NOT auto-confirm unless explicitly required
- No anonymous signups: Always require email + password
User signs up → Supabase creates auth.users row
→ handle_new_user() trigger creates profiles row
→ AuthContext picks up session via onAuthStateChange
→ Profile fetched from profiles table
The primary tool catalog is a static TypeScript array. This is intentional for MVP speed. Tools are defined with full metadata:
interface Tool {
id: string;
name: string;
description: string;
category: Category;
tags: Tag[];
url: string;
// ... see src/lib/types.ts for full shape
}Categories and tags are typed enums in src/lib/types.ts. When adding new ones:
- Add to the
CategoryorTagunion type - Add metadata to the
categoriesortagsarray indata.ts - Ensure consistency across all filter UIs
| Context | Library | Pattern |
|---|---|---|
| Page transitions | Framer Motion | motion.div with initial/animate/exit |
| Scroll reveals | Framer Motion | whileInView with viewport={{ once: true }} |
| Hover effects | Framer Motion | whileHover={{ y: -4 }} |
| Staggered lists | Framer Motion | delay: index * 0.06 |
| Micro-interactions | Tailwind | transition-all duration-200 |
- Use
framer-motionfor anything beyond simple CSS transitions - Keep durations under 400ms for UI interactions
- Use
once: trueon scroll animations to avoid re-triggering - Stagger delays: 40-80ms between items
When working outside Lovable, use Context7 MCP to ensure dependency accuracy.
Context7 resolves library documentation in real-time, ensuring you install correct versions and use up-to-date APIs. This prevents:
- Installing deprecated packages
- Using outdated API patterns
- Version conflicts with existing dependencies
- Install the Context7 MCP server in your IDE's MCP configuration
- When adding a new dependency, query Context7 first:
- "What's the latest stable version of
<package>?" - "Show me the API for
<package>v<version>"
- "What's the latest stable version of
- Cross-reference with the existing
package.jsonto avoid conflicts
1. Need a new package? → Ask Context7 for latest stable version
2. Context7 confirms version + API → bun add <package>@<version>
3. Implement using verified API patterns
4. Ensure import style matches project conventions (@/ aliases, named exports)
| Package | Current Version | Notes |
|---|---|---|
framer-motion |
^12.x | API changed significantly from v10/v11 |
react-router-dom |
^6.x | v7 has breaking changes — stay on v6 |
@tanstack/react-query |
^5.x | v5 has different defaults than v4 |
lucide-react |
^0.462 | Icon names change between versions |
| shadcn/ui | CLI-based | Always use bunx shadcn@latest add |
bun run test # Single run
bun run test:watch # Watch mode- Framework: Vitest + jsdom
- Location:
src/test/or colocated*.test.tsfiles - Setup:
src/test/setup.ts
These are auto-generated and will be overwritten:
| File | Reason |
|---|---|
.env |
Managed by Lovable Cloud |
src/integrations/supabase/client.ts |
Auto-generated Supabase client |
src/integrations/supabase/types.ts |
Auto-generated from DB schema |
supabase/config.toml |
Managed by Lovable Cloud |
bun.lockb |
Generated by bun |
supabase/migrations/* |
Managed via migration tool |
feature/tool-stack-showcase
fix/auth-modal-scroll
refactor/dashboard-sidebar
feat: add ToolStackShowcase with category filtering
fix: make auth modal scrollable on mobile
refactor: extract glass card into shared component
chore: update framer-motion to v12.30
bun run build— ensure no TypeScript errorsbun run test— all tests pass- Verify no raw color values in new components
- Verify all new components use
@/import aliases - Verify design tokens from
index.cssare used (no hardcoded colors)
Follow the build journey on X: @builtbyangelo