# Customizing the Varity SaaS Template ## Template Structure ``` src/ ├── app/ # Next.js pages │ ├── page.tsx # Landing page │ ├── login/page.tsx # Login page │ └── dashboard/ │ ├── layout.tsx # Dashboard layout (sidebar + mobile nav) │ ├── page.tsx # Dashboard home │ ├── projects/ # Projects CRUD │ ├── tasks/ # Tasks CRUD │ ├── team/ # Team management │ └── settings/ # Settings ├── lib/ │ ├── varity.ts # SDK import (1 line: export { db } from '@varity-labs/sdk') │ ├── database.ts # Collection helpers │ ├── hooks.ts # React hooks for data │ └── constants.ts # App name, navigation items ├── types/ │ └── index.ts # TypeScript interfaces └── components/ui/ # Shared UI components ``` ## Change Branding ### 1. Update app name and metadata Edit `src/lib/constants.ts`: ```typescript export const APP_NAME = 'YourAppName'; export const APP_DESCRIPTION = 'Your app description'; ``` ### 2. Update colors Edit `src/app/globals.css` -- change the CSS variables in `:root`: ```css :root { --color-primary-50: #f5f3ff; --color-primary-100: #ede9fe; --color-primary-200: #ddd6fe; --color-primary-300: #c4b5fd; --color-primary-400: #a78bfa; --color-primary-500: #8b5cf6; /* Main brand color */ --color-primary-600: #7c3aed; --color-primary-700: #6d28d9; --color-primary-800: #5b21b6; --color-primary-900: #4c1d95; } ``` Tailwind references these CSS variables automatically, so all components update. ### 3. Update landing page Edit `src/app/page.tsx` to change headlines, feature descriptions, and CTAs. ## Add a New Page ### 1. Create the page file ```tsx // src/app/dashboard/workflows/page.tsx 'use client'; import { useWorkflows } from '../../../lib/hooks'; export default function WorkflowsPage() { const { data, loading, error, create, remove } = useWorkflows(); if (loading) return

Loading...

; if (error) return

Error: {error}

; return (

Workflows

{data.map(w => (
{w.name} - {w.status}
))}
); } ``` ### 2. Add to navigation Edit `src/lib/constants.ts`: ```typescript export const NAVIGATION_ITEMS = [ { label: 'Dashboard', icon: 'dashboard', path: '/dashboard' }, { label: 'Workflows', icon: 'list', path: '/dashboard/workflows' }, { label: 'Team', icon: 'people', path: '/dashboard/team' }, { label: 'Settings', icon: 'settings', path: '/dashboard/settings' }, ]; ``` Available icons: dashboard, folder, list, people, settings, star ## Add a New Data Model Follow the Type -> Collection -> Hook -> Page pattern: ### 1. Define the interface ```typescript // src/types/index.ts export interface Workflow { id?: string; name: string; description: string; status: 'draft' | 'active' | 'paused' | 'completed'; ownerId: string; createdAt: string; } ``` ### 2. Add collection accessor ```typescript // src/lib/database.ts import { db } from '@varity-labs/sdk'; import type { Workflow } from '../types'; export const workflows = () => db.collection('workflows'); ``` ### 3. Create the hook ```typescript // src/lib/hooks.ts import { workflows } from './database'; import type { Workflow } from '../types'; export function useWorkflows() { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const refresh = useCallback(async () => { try { setLoading(true); setError(null); const result = await workflows().get(); setData(result as Workflow[]); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load'); } finally { setLoading(false); } }, []); useEffect(() => { refresh(); }, [refresh]); const create = async (input: Omit) => { const optimistic = { ...input, id: `temp-${Date.now()}`, createdAt: new Date().toISOString() }; setData(prev => [optimistic, ...prev]); try { await workflows().add({ ...input, createdAt: optimistic.createdAt }); await refresh(); } catch (err) { setData(prev => prev.filter(w => w.id !== optimistic.id)); throw err; } }; const update = async (id: string, changes: Partial) => { const prev = data; setData(d => d.map(w => w.id === id ? { ...w, ...changes } : w)); try { await workflows().update(id, changes); } catch (err) { setData(prev); throw err; } }; const remove = async (id: string) => { const prev = data; setData(d => d.filter(w => w.id !== id)); try { await workflows().delete(id); } catch (err) { setData(prev); throw err; } }; return { data, loading, error, create, update, remove, refresh }; } ``` ### 4. Build the page (see "Add a New Page" above) ## Replace an Existing Feature To replace "Projects" with "Workflows": 1. Update `src/types/index.ts` -- replace `Project` interface with `Workflow` 2. Update `src/lib/database.ts` -- replace `projects()` with `workflows()` 3. Update `src/lib/hooks.ts` -- replace `useProjects()` with `useWorkflows()` 4. Rename `src/app/dashboard/projects/` to `src/app/dashboard/workflows/` 5. Update the page component to use `useWorkflows()` 6. Update `NAVIGATION_ITEMS` in `src/lib/constants.ts` ## Auth Components Available ```tsx import { PrivyStack, // Auth provider (wrap app root) PrivyLoginButton, // Drop-in login button PrivyProtectedRoute, // Route protection wrapper PrivyUserProfile, // User profile display DashboardLayout, // Sidebar layout } from '@varity-labs/ui-kit'; import { usePrivy } from '@varity-labs/ui-kit'; const { user, authenticated, logout, ready } = usePrivy(); ``` ## Rules - Always use `'use client'` directive for pages with hooks or interactivity - Follow the Type -> Collection -> Hook -> Page pattern for all data models - Keep collection names snake_case plural (workflows, team_members) - Use optimistic updates in all hooks - DashboardLayout has no mobile support -- implement mobile nav manually - Use `output: 'export'` in next.config.js (static hosting) - No dynamic routes ([id]) -- use client-side state for detail views