Staff App Routes & Behaviors¶
Reference documentation for all routes, components, and behaviors.
Route Summary¶
| Path | Component | Auth | Description |
|---|---|---|---|
/login |
LoginPage | No | Email/password or magic link login |
/auth/verify |
VerifyPage | No | Magic link verification |
/splash |
SplashPage | No | Animated branding splash for recordings |
/ |
DashboardPage | Yes | Overview stats, recent clients |
/clients |
ClientsPage | Yes | Client list with search, aggregated status |
/clients/new |
CreateClientPage | Yes | New client form |
/pending-uploads |
PendingUploadsPage | Yes | Upload docs first, then create client |
/clients/:clientId |
ClientDetailPage | Yes | Client info, returns list, actions |
/clients/:clientId/returns/:returnId/upload |
DocumentUploadPage | Yes | Drag-drop document upload |
/returns/:returnId/analysis |
AnalysisDashboardPage | Yes | 3-panel workspace (main review interface) |
/queue |
QueuePage | Yes | Review workflow queue |
/review/:returnId |
Redirects | Yes | Legacy route - redirects to /returns/:id/analysis |
Public Routes¶
/login -> LoginPage¶
File: frontend/apps/staff-app/src/pages/LoginPage.tsx
Layout: Centered card with logo
Behavior:
- Two login modes: Magic link (default) or password
- Toggle between modes via footer button
- Magic link: Enter email -> sends link -> shows confirmation
- Dev mode: Shows clickable magic link for testing
- Password: Enter email + password -> redirects to /
- Preserves ?demo= param through login
State:
- email, password - form inputs
- usePassword - toggle between login modes
- magicLinkSent - shows confirmation screen
- devMagicLink - dev mode quick link
API calls:
- useAuth().requestMagicLink(email)
- useAuth().login(email, password)
/auth/verify -> VerifyPage¶
File: frontend/apps/staff-app/src/pages/VerifyPage.tsx
Layout: Centered card with status icon
Behavior:
- Reads ?token= from URL
- Calls verifyMagicLink(token) on mount
- Shows loading -> success -> redirects to /
- Or shows error with "Back to login" button
State:
- status: "loading" | "success" | "error"
- error: error message if failed
API calls:
- useAuth().verifyMagicLink(token)
/splash -> SplashPage¶
File: frontend/apps/staff-app/src/pages/SplashPage.tsx
Layout: Full-screen dark gradient with centered branding
Behavior:
- Staggered fade-in animation (logo -> title -> subtitle -> footer)
- Auto-advances to / after 5 seconds (configurable via ?delay=)
- Click anywhere or press any key to skip
- ?delay=0 disables auto-advance
State:
- showLogo, showTitle, showSubtitle, showFooter - animation states
URL params:
- ?delay=3000 - custom auto-advance delay in ms
- ?delay=0 - no auto-advance
Protected Routes (require authentication)¶
/ -> DashboardPage¶
File: frontend/apps/staff-app/src/pages/DashboardPage.tsx
Layout: Header + 3 stat cards + recent clients list
Behavior:
- Shows total clients, returns in progress (placeholder), pending actions
- Lists 5 most recent clients with status badge
- Click client -> navigates to /clients/:id
- "New Client" button -> /clients/new
- "View all" link -> /clients
API calls:
- api.getClients() - fetches all clients for stats
Data displayed: - Total clients count - Active/pending breakdown - Recent client list with avatar, name, email, status
/clients -> ClientsPage¶
File: frontend/apps/staff-app/src/pages/ClientsPage.tsx
Layout: Header + search bar + clients table
Behavior:
- Search filters by name, email, account number (client-side)
- Table shows: Client name, Account #, Email, Phone, Status, Created date
- Status shows aggregated return status (not client.status)
- Also shows return count and latest year under status
- Click "View" -> navigates to /clients/:id
- "New Client" button -> /clients/new
State:
- searchQuery - search input value
API calls:
- api.getClients() - fetches all clients
Status display logic:
- in_review, ready_for_review, etc -> warning (yellow)
- intake, documents_pending -> secondary (gray)
- filed, accepted, complete -> success (green)
- rejected -> destructive (red)
- no_returns -> default
/clients/new -> CreateClientPage¶
File: frontend/apps/staff-app/src/pages/CreateClientPage.tsx
Layout: Centered form card
Behavior:
- Form fields: First name, Last name, Email*, Phone (optional)
- Checkbox: Send welcome email (default: checked)
- Validates required fields on submit
- Creates client -> redirects to /clients/:newId
- Cancel -> back to /clients
State:
- formData - form field values
- error - validation/API error message
API calls:
- api.createClient(formData) - creates new client
/pending-uploads -> PendingUploadsPage¶
File: frontend/apps/staff-app/src/pages/PendingUploadsPage.tsx
Layout: Header + upload zone + current upload batch + empty state
Behavior:
- Upload documents without assigning to a client first
- Large drag-drop zone for files
- "Browse Files" button for file picker
- "Import Folder" button for folder upload (webkitdirectory)
- Shows upload progress with spinner
- Documents grouped by batch (current session only)
- Current upload shows: file icon, filename, type/classifying status, size, tax year badge
- "Create Client" button opens CreateClientFromDocumentsDialog:
- Pre-populates client info from AI extraction (if available)
- Creates client, return, and assigns documents in one operation
- Navigates to /clients/:newId on success
- Empty state shown when no uploads present
State:
- currentBatchId - unique batch ID for current session
- uploadedDocs - documents uploaded in current session
- uploading - upload in progress
- isDragOver - drag hover state
- dialogOpen - create client dialog visibility
- selectedBatch - batch passed to create client dialog
API calls:
- api.uploadPendingDocument(file, batchId) - uploads to pending storage
- api.getPendingBatches() - fetches existing batches (disabled, future use)
Related Component:
- CreateClientFromDocumentsDialog - dialog for creating client from batch
- Calls POST /v1/batch/:batchId/create-client
- Creates client + return + moves documents in one transaction
/clients/:clientId -> ClientDetailPage¶
File: frontend/apps/staff-app/src/pages/ClientDetailPage.tsx
Layout: Client header + 2-column info cards + returns table + actions card
Behavior:
- Shows client info: name, account number, email, phone, dates
- Tax Returns table with: Year, Type, Status, Documents, Updated, Actions
- "New Return" button opens dialog:
- Select tax year (2024, 2023, 2022)
- Select return type (1040, 1120, 1120S, 1065, 990)
- Creates return -> navigates to /clients/:id/returns/:newReturnId/upload
- Return row actions:
- Upload icon -> /clients/:id/returns/:rid/upload
- Chart icon -> /returns/:rid/analysis
- "Review" link -> /review/:rid
- Actions card (disabled): Edit Client, Send Portal Invite, Create Engagement Letter
- ChatDrawer floating in bottom-right
State:
- isNewReturnOpen - dialog visibility
- newReturnYear, newReturnType - dialog form values
API calls:
- api.getClient(clientId)
- api.getClientReturns(clientId)
- api.createReturn(clientId, { tax_year, return_type })
/clients/:clientId/returns/:returnId/upload -> DocumentUploadPage¶
File: frontend/apps/staff-app/src/pages/DocumentUploadPage.tsx
Layout: Header + upload zone + document list
Behavior:
- Large drag-drop zone for files
- "Browse Files" button for file picker
- "Import Folder" button for folder upload (webkitdirectory)
- Shows upload progress with spinner
- Document list shows: icon, filename, type, size, status badge
- Status: "Processed" (green check) or "Processing" (spinner)
- Duplicate detection (DUP-001): On upload, if file hash matches existing:
- Same client: Shows "Duplicate Document" dialog with "View Original" / "Cancel"
- Different client: Shows "Document Belongs to Another Client" dialog with "View in [Client]" / "Cancel"
- "Continue to Analysis" -> /returns/:rid/analysis
- "Save & Return to Client" -> /clients/:cid
State:
- documents - newly uploaded docs (local state)
- uploading - upload in progress
- isDragOver - drag hover state
- duplicateInfo - duplicate detection response from API (DuplicateInfo | null)
- duplicateFilename - filename that triggered duplicate detection
API calls:
- api.getClient(clientId)
- api.getReturn(returnId)
- api.getReturnDocuments(returnId) - existing docs
- api.uploadDocument(returnId, file) - per file
- Returns 201 on success
- Returns 409 on duplicate with { error, is_same_client, existing_document }
/returns/:returnId/analysis -> AnalysisDashboardPage¶
File: frontend/apps/staff-app/src/pages/AnalysisDashboardPage.tsx
Layout: 3-panel workspace
┌──────────────────┬──────────────────────┬──────────────────────┐
│ PDF Viewer │ Documents & Info │ AI Chat │
│ (40%) │ (35%) │ (25%) │
└──────────────────┴──────────────────────┴──────────────────────┘
Behavior:
- Header: Back button, client name, return info, panel toggle buttons
- Left panel: PDF viewer (iframe)
- Shows selected document
- Auto-selects first document on load
- Center panel: Document list with actions
- AI analysis banner (blue) with "Run AI Analysis" button
- AI insights summary when analysis complete (questions, missing docs, anomalies, recommendations counts)
- Drag-drop zone: Entire document list area accepts file drops
- Visual feedback: Blue ring and background tint on drag-over
- Drop hint appears when dragging or when list is empty
- Document list with: icon, filename, type, size, status, action buttons
- Click document -> loads in PDF viewer
- "Upload" button opens file picker (no longer navigates away)
- Action buttons per document:
- Tag icon: Reclassify (dropdown menu with document types)
- Arrow icon: Move to another client (dialog with client/return selectors)
- Trash icon: Delete (confirmation dialog)
- Duplicate detection (DUP-001): On upload, if file hash matches existing:
- Same client: Shows "Duplicate Document" dialog with "View Original" / "Cancel"
- Different client: Shows "Document Belongs to Another Client" dialog with "View in [Client]" / "Cancel"
- Right panel: AI Chat sidebar
- Uses useChat hook
- ChatHistory + ChatInput components
- Panel toggle buttons in header to show/hide left/right panels
State:
- leftPanelOpen, rightPanelOpen - panel visibility
- selectedDocId - document shown in PDF viewer
- analysisRequested - triggers AI analysis fetch
- showReclassifyMenu, showMoveDialog, showDeleteConfirm - action dialogs
- moveTargetClientId, moveTargetReturnId - move dialog selections
- isDragOver, uploading - drag-drop upload state
- duplicateInfo, duplicateFilename - duplicate detection dialog state
API calls:
- api.getReturn(returnId)
- api.getReturnDocuments(returnId)
- api.getClient(clientId)
- api.getAIAnalysis(returnId) - lazy loaded on button click
- api.deleteDocument(docId)
- api.reclassifyDocument(docId, type)
- Chat: useChat({ clientId, taxReturnId })
/queue -> QueuePage¶
File: frontend/apps/staff-app/src/pages/QueuePage.tsx
Layout: Header + 4 stat cards + filter tabs + returns list
Behavior:
- Stats: Total in queue, In Preparation, Ready for Review, AI Analysis Ready
- Filter tabs: All Returns, Preparation, Review
- Returns list shows: Client name, status badge, AI Ready badge, return type/year, doc count, updated date
- Click return -> navigates to /review/:returnId
State:
- returns - fetched queue data
- loading - loading state
- filter - "all" | "prep" | "review"
API calls:
- api.getReviewQueue() - fetches returns in queue
/review/:returnId -> Redirect (DEPRECATED)¶
Status: DEPRECATED - Redirects to /returns/:returnId/analysis
This legacy route now redirects to the new 3-panel workspace. The ReviewPage component is no longer used but kept for reference.
All navigation has been updated:
- ClientDetailPage "Open" button -> /returns/:id/analysis
- QueuePage row click -> /returns/:id/analysis
- Direct URL /review/:id -> redirects to /returns/:id/analysis
User Flows¶
New Client Flow¶
New Return Flow¶
Document Upload Flow¶
Document Review Flow¶
/clients/:id -> click return -> /returns/:rid/analysis
-> view PDFs, ask AI questions, manage documents
Queue Review Flow¶
Upload-First Flow (Documents Before Client)¶
Component Dependencies¶
Shared Components¶
MainLayout- wraps all protected routes, provides navigation sidebarChatDrawer- floating chat button (ClientDetailPage)ChatHistory+ChatInput- embedded chat (AnalysisDashboardPage, ReviewPage)
Shared Hooks¶
useAuth- authentication state and methodsuseChat- chat session management
UI Library¶
- All routes use components from
@tax-practice/ui: - Card, Button, Badge, Input, Label, Table, Dialog, Select
- api client for backend calls
API Endpoints Used¶
| Endpoint | Method | Used By |
|---|---|---|
/v1/clients |
GET | DashboardPage, ClientsPage |
/v1/clients |
POST | CreateClientPage |
/v1/clients/:id |
GET | ClientDetailPage, DocumentUploadPage, AnalysisDashboardPage |
/v1/clients/:id/returns |
GET | ClientDetailPage |
/v1/clients/:id/returns |
POST | ClientDetailPage |
/v1/returns/:id |
GET | DocumentUploadPage, AnalysisDashboardPage, ReviewPage |
/v1/returns/:id/documents |
GET | DocumentUploadPage, AnalysisDashboardPage, ReviewPage |
/v1/returns/:id/documents |
POST | DocumentUploadPage, AnalysisDashboardPage, ReviewPage |
/v1/returns/:id/ai/analysis |
GET | AnalysisDashboardPage, ReviewPage |
/v1/returns/:id/ai/chat |
GET | DEPRECATED - use /chat/sessions/* |
/v1/returns/:id/status |
PATCH | ReviewPage |
/v1/documents/:id |
DELETE | AnalysisDashboardPage |
/v1/documents/:id/content |
GET | AnalysisDashboardPage (PDF viewer) |
/v1/documents/:id/move |
POST | AnalysisDashboardPage |
/v1/documents/:id/reclassify |
POST | AnalysisDashboardPage |
/v1/chat/sessions |
POST | useChat hook |
/v1/chat/sessions/:id |
GET | useChat hook |
/v1/chat/sessions/:id/messages |
POST | useChat hook |
/v1/queue |
GET | QueuePage |
/v1/pending-documents |
POST | PendingUploadsPage (upload) |
/v1/pending-documents/batches |
GET | PendingUploadsPage (future) |
/v1/batch/:batchId/create-client |
POST | CreateClientFromDocumentsDialog |
Last updated: 2025-12-28