dograh/ui/AGENTS.md
Abhishek Kumar 03df5595c3 feat: add worker sync events
Add a worker sync event so that runtime updates on one worker can propagate across other workers using pubsub for multi worker deployments
2026-04-04 14:26:47 +05:30

2.8 KiB

UI - Frontend Application

Next.js 15 frontend for the Dograh voice AI platform.

Project Structure

ui/
├── src/
│   ├── app/          # Next.js App Router pages
│   ├── components/   # React components
│   ├── lib/          # Utilities and configurations
│   ├── client/       # Auto-generated API client
│   ├── context/      # React context providers
│   ├── hooks/        # Custom React hooks
│   ├── constants/    # Application constants
│   └── types/        # TypeScript type definitions
├── public/           # Static assets
└── package.json

Where to Find Things

Looking for... Go to...
Pages/routes src/app/ - Next.js App Router (file-based routing)
Reusable components src/components/ - organized by feature
Base UI primitives src/components/ui/ - shadcn/ui components
Workflow builder src/components/flow/ - React Flow based
API calls src/client/ - auto-generated from OpenAPI spec
Auth utilities src/lib/auth/
Helper functions src/lib/utils.ts
Global state src/context/ - React context providers

Tech Stack

  • Next.js 15 with App Router, React 19, TypeScript
  • Tailwind CSS with shadcn/ui components
  • Zustand for state management
  • @xyflow/react for workflow builder

API Client

The src/client/ directory is auto-generated from the backend OpenAPI spec. Whenever you add a new api route in backend, and wish to use it in the UI, generate the client using below command.

npm run generate-client

Conventions

File Uploads

Always use a hidden <input type="file"> with a visible <Button> that triggers it via fileInputRef.current?.click(). Never use a visible <Input type="file"> — the native file input styling is inconsistent and confusing. Show the selected filename next to or below the button.

Authenticated API Calls

Components that make API calls must wait for auth to be ready before fetching. Use useAuth() and guard the useEffect with authLoading and user:

const { user, loading: authLoading } = useAuth();
const hasFetched = useRef(false);

useEffect(() => {
  if (authLoading || !user || hasFetched.current) return;
  hasFetched.current = true;
  fetchData();
}, [authLoading, user]);

The auth interceptor (which attaches the Bearer token) is only registered once auth is fully loaded. Fetching before that sends unauthenticated requests that silently fail.

Development

npm install
npm run dev    # Runs on port 3000