====== Frontend Documentation ======
Full reference documentation for the Next.js 15 frontend of the Attorney Vendor Portal.
For the backend documentation, see ''attorney-vendor-portal-backend/docs/start.txt'' (portal index) and ''attorney-vendor-portal-backend/docs/backend.txt'' (backend reference).
----
===== Tech Stack =====
^ Component ^ Technology ^
| Framework | Next.js 15.5.3 (App Router, standalone output) |
| Language | TypeScript 5 (strict mode) |
| UI Library | React 19.1.0 |
| Styling | Tailwind CSS 4 |
| Component Library | shadcn/ui (New York style), Radix UI primitives |
| Icons | Lucide React |
| Data Fetching | TanStack React Query (''@tanstack/react-query'') |
| Tables | TanStack Table (''@tanstack/react-table'') |
| Forms | React Hook Form + Zod validation |
| Rich Text Editor | Tiptap (''@tiptap/react'', ''@tiptap/starter-kit'') |
| Charts | Recharts |
| Date Utilities | date-fns |
| PDF Generation | jsPDF |
| Excel Export | xlsx |
| Unit Testing | Vitest + React Testing Library |
| E2E Testing | Playwright |
| Package Manager | npm |
| Node Version | 20 (Docker) |
----
===== Directory Structure =====
app/
(auth)/ Public authentication pages (no login required)
login/ Login page
registration/ Registration via invitation token
forgot-password/ Password reset request
password-reset/[token]/ Password reset with token
verify-email/ Email verification page
(dashboard)/ Protected pages (wrapped by RouteGuard + DashboardLayout)
cases/ Cases list page
cases/[caseId]/ Case detail page (tabs: details, notes, hearings, related, assignments)
dashboard/ Dashboard page (Phase 1: hidden)
hearings/[hearingId]/ Hearing detail page
settings/ User settings page
users/ Users list page (requires canManageUsers)
users/[id]/ User detail page
api/ Next.js API routes
cases/ Cases API (mock support)
cases/[caseId]/ Case detail API
health/ Health check endpoint
logs/ Log forwarding endpoint
logs/batch/ Batch log forwarding endpoint
warmup/ Warmup endpoint (cold start prevention)
service-unavailable/ Backend-down error page
not-found/ 404 error page
layout.tsx Root layout (providers, fonts, metadata)
page.tsx Root page (redirects to /login)
components/
cases/ Case-related components
hearings/ Hearing components
notes/ Note/rich-text components
users/ User components
ui/ shadcn/ui base components
contexts/ React context providers
hooks/
api/ API data-fetching hooks (React Query)
lib/ Utilities and API client
types/ TypeScript type definitions
----
===== Route Structure =====
==== Public Routes (No Authentication) ====
^ Route ^ Page Component ^ Description ^
| ''/login'' | ''login/page.tsx'' | Username + password login form |
| ''/registration'' | ''registration/page.tsx'' | Invitation-based registration |
| ''/forgot-password'' | ''forgot-password/page.tsx'' | Request password reset email |
| ''/password-reset/[token]'' | ''password-reset/[token]/page.tsx'' | Set new password with token |
| ''/verify-email'' | ''verify-email/page.tsx'' | Email verification status page |
| ''/service-unavailable'' | ''service-unavailable/page.tsx'' | Backend unreachable error page |
| ''/not-found'' | ''not-found/page.tsx'' | 404 error page |
==== Protected Routes (Authentication Required) ====
All wrapped by ''RouteGuard'' and ''DashboardLayout'' (sidebar + header).
^ Route ^ Page Component ^ Description ^
| ''/cases'' | ''cases/page.tsx'' | Case list with search, filters, pagination |
| ''/cases/[caseId]'' | ''cases/[caseId]/page.tsx'' | Case detail with tabbed view |
| ''/dashboard'' | ''dashboard/page.tsx'' | Dashboard (Phase 1: hidden in nav) |
| ''/hearings/[hearingId]'' | ''hearings/[hearingId]/page.tsx'' | Hearing detail |
| ''/settings'' | ''settings/page.tsx'' | User settings |
| ''/users'' | ''users/page.tsx'' | User list (admin/manager only) |
| ''/users/[id]'' | ''users/[id]/page.tsx'' | User detail |
==== Next.js API Routes ====
^ Route ^ Purpose ^
| ''/api/cases'' | Proxies to backend or returns mock data (when ''NEXT_PUBLIC_USE_CASES_MOCK=1'') |
| ''/api/cases/[caseId]'' | Case detail proxy/mock |
| ''/api/health'' | Frontend health check (returns 200) |
| ''/api/logs'' | Forwards frontend log entries to backend |
| ''/api/logs/batch'' | Forwards batched log entries to backend |
| ''/api/warmup'' | Warmup endpoint to prevent cold starts |
----
===== Components =====
==== Core Components ====
^ Component ^ File ^ Description ^
| ''RouteGuard'' | ''components/RouteGuard.tsx'' | Wraps protected routes; checks auth, redirects to /login |
| ''DashboardLayout'' | ''components/DashboardLayout.tsx'' | Main layout with sidebar navigation, header, breadcrumbs |
| ''QueryProvider'' | ''components/QueryProvider.tsx'' | Wraps app with React Query ''QueryClientProvider'' |
| ''BackendHealthBanner'' | ''components/BackendHealthBanner.tsx'' | Shows warning banner when backend is unreachable |
| ''BackendHealthGuard'' | ''components/BackendHealthGuard.tsx'' | Redirects to /service-unavailable when backend is down |
| ''RestrictedAccess'' | ''components/RestrictedAccess.tsx'' | 403 forbidden page component |
| ''DataTable'' | ''components/DataTable.tsx'' | Reusable data table built on TanStack Table |
| ''FeedbackDialog'' | ''components/FeedbackDialog.tsx'' | Modal dialog for submitting user feedback |
| ''ThemeToggle'' | ''components/ThemeToggle.tsx'' | Light/dark/system theme switcher |
==== Case Components ====
Located in ''components/cases/'':
^ Component ^ Description ^
| ''BasicFilters'' | Basic filter UI (status, vendor, date range, etc.) |
| ''BasicFilterSection'' | Filter section wrapper with collapsible groups |
| ''CaseBasicSearch'' | Case search input with debounce |
| ''CaseDetailsTab'' | Case detail tab (client info, debt info, case metadata) |
| ''CaseHearingsTab'' | Hearings tab within case detail |
| ''CaseNotesTab'' | Notes tab within case detail |
| ''CaseRelatedCasesTab'' | Related cases tab within case detail |
| ''CaseSearchMention'' | Case search with @-mention support |
| ''CaseSearchTabs'' | Tab container for case search modes |
| ''CaseUserAssignmentsTab'' | User assignments tab within case detail |
| ''FilterButtonGroup'' | Group of filter toggle buttons |
| ''FilterDateRange'' | Date range picker filter |
| ''FilterRangeSlider'' | Numeric range slider filter |
==== Hearing Components ====
Located in ''components/hearings/'':
^ Component ^ Description ^
| ''AssignAttorneysModal'' | Modal for assigning attorneys to a hearing |
==== Note Components ====
Located in ''components/notes/'':
^ Component ^ Description ^
| ''NotePreviewCard'' | Card preview of a note with truncated content |
| ''RichTextEditor'' | Full Tiptap rich text editor for creating/editing notes |
| ''SimpleTextEditor'' | Simplified plain text editor alternative |
==== User Components ====
Located in ''components/users/'':
^ Component ^ Description ^
| ''UserFilters'' | Filter controls for the users list |
==== UI Components (shadcn/ui) ====
Located in ''components/ui/''. These are base components from the shadcn/ui library:
''alert'', ''avatar'', ''badge'', ''button'', ''calendar'', ''card'', ''checkbox'', ''collapsible'', ''command'', ''confirm-modal'', ''dialog'', ''dialog-simple'', ''dropdown-menu'', ''dropdown-menu-simple'', ''dynamic-charts'', ''form'', ''input'', ''label'', ''loading'', ''popover'', ''progress'', ''scroll-area'', ''select'', ''select-simple'', ''separator'', ''sheet'', ''skeleton'', ''slider'', ''switch'', ''table'', ''tabs'', ''tabs-simple'', ''textarea''
----
===== API Client =====
**File:** ''lib/api-client.ts''
The API client is the single point of contact between the frontend and the Laravel backend.
==== Configuration ====
* **Base URL:** ''NEXT_PUBLIC_API_URL'' environment variable
* **Timeout:** 75 seconds
* **Content type:** ''application/json'' (default)
==== Authentication ====
* Reads token from ''localStorage'' under key ''auth_token''
* Attaches ''Authorization: Bearer '' header to every request
* On **401 response**: clears token, sets global ''has401Error'' flag, redirects to ''/login''
==== Features ====
* **Request deduplication:** GET requests to the same URL are deduplicated (only one in-flight request per URL)
* **Backend health tracking:** Detects 502/503/504 and network errors, notifies ''BackendHealthContext''
* **Error sanitization:** Wraps errors into structured ''ApiError'' objects
* **Abort support:** Requests can be cancelled via ''AbortController''
==== Helper Functions ====
^ Function ^ Description ^
| ''get(url, params?)'' | GET request with optional query parameters |
| ''post(url, data?)'' | POST request with JSON body |
| ''put(url, data?)'' | PUT request with JSON body |
| ''patch(url, data?)'' | PATCH request with JSON body |
| ''del(url)'' | DELETE request |
| ''postFormUrlEncoded(url, data)'' | POST with ''application/x-www-form-urlencoded'' |
| ''postForm(url, formData)'' | POST with ''multipart/form-data'' |
| ''deduplicatedGet(url, params?)'' | GET with in-flight request deduplication |
----
===== Custom Hooks =====
==== API Hooks ====
Located in ''hooks/api/''. All hooks use TanStack React Query for caching, background refetch, and optimistic updates.
=== useCases (hooks/api/useCases.ts) ===
^ Hook ^ Type ^ Description ^
| ''useCases(filters)'' | Query | Fetch paginated, filtered case list |
| ''useCaseDetail(id)'' | Query | Fetch single case detail |
| ''useRelatedCases(id)'' | Query | Fetch related cases for a given case |
| ''useCreateCase()'' | Mutation | Create a new case |
| ''useUpdateCase()'' | Mutation | Update an existing case |
| ''useDeleteCase()'' | Mutation | Delete a case |
=== useHearings (hooks/api/useHearings.ts) ===
^ Hook ^ Type ^ Description ^
| ''useHearings(filters)'' | Query | Fetch paginated hearing list |
| ''useHearingAttorneys(id)'' | Query | Fetch attorneys for a hearing |
| ''useHearingDetail(id)'' | Query | Fetch hearing detail |
| ''useAssignHearingAttorneys()'' | Mutation | Assign attorneys to a hearing |
| ''useSetMainAttorney()'' | Mutation | Set the main attorney for a hearing |
| ''useCancelHearing()'' | Mutation | Cancel a hearing |
| ''useDeleteHearing()'' | Mutation | Delete a hearing |
| ''useUpdateHearingOptions()'' | Mutation | Update hearing options |
=== useUsers (hooks/api/useUsers.ts) ===
^ Hook ^ Type ^ Description ^
| ''useUsers(filters)'' | Query | Fetch paginated user list |
| ''useUser(id)'' | Query | Fetch single user detail |
=== useNotes (hooks/api/useNotes.ts) ===
^ Hook ^ Type ^ Description ^
| ''useCaseNotes(caseId)'' | Query | Fetch notes for a case |
| ''useCreateNote()'' | Mutation | Create a note on a case |
| ''useUpdateNote()'' | Mutation | Update a note |
| ''useDeleteNote()'' | Mutation | Delete a note |
=== useRoles (hooks/api/useRoles.ts) ===
^ Hook ^ Type ^ Description ^
| ''useRoles()'' | Query | Fetch available roles |
| ''useMyVendors()'' | Query | Fetch user's accessible vendors |
| ''useCheckPermission()'' | Mutation | Check if user has a permission |
| ''useAssignRole()'' | Mutation | Assign a role to a user |
| ''useRemoveAccess()'' | Mutation | Remove user's vendor access |
=== useMe (hooks/api/useMe.ts) ===
^ Hook ^ Type ^ Description ^
| ''useMe()'' | Query | Fetch authenticated user's profile via ''/api/me'' |
=== useRegistration (hooks/api/useRegistration.ts) ===
^ Hook ^ Type ^ Description ^
| ''useVerifyToken()'' | Mutation | Verify an invitation token |
| ''useCompleteRegistration()'' | Mutation | Complete registration with password |
| ''useResendVerification()'' | Mutation | Resend email verification |
=== useInvitations (hooks/api/useInvitations.ts) ===
^ Hook ^ Type ^ Description ^
| ''useInviteUser()'' | Mutation | Send invitation to a new user |
| ''useResendInvitation()'' | Mutation | Resend invitation email |
| ''useGenerateInviteLink()'' | Mutation | Generate a one-time invite link |
=== useUserAssignments (hooks/api/useUserAssignments.ts) ===
^ Hook ^ Type ^ Description ^
| ''useUserAssignments(filters)'' | Query | Fetch user assignments |
| ''useCaseUserAssignments(caseId)'' | Query | Fetch assignments for a specific case |
=== useUserLookup (hooks/api/useUserLookup.ts) ===
^ Hook ^ Type ^ Description ^
| ''useUserLookup(query)'' | Query | Search/lookup users by name or email |
=== useFeedback (hooks/api/useFeedback.ts) ===
^ Hook ^ Type ^ Description ^
| ''useSubmitFeedback()'' | Mutation | Submit user feedback |
==== Utility Hooks ====
^ Hook ^ File ^ Description ^
| ''useRole()'' | ''hooks/useRole.ts'' | Returns current user's role info and permission helpers |
| ''useVendorPermission()'' | ''hooks/useRole.ts'' | Checks if user has a specific permission for a vendor |
| ''useDataTable()'' | ''hooks/useDataTable.ts'' | Manages TanStack Table state (sorting, filtering, pagination) |
----
===== State Management =====
The frontend uses React Context for global state and TanStack React Query for server state.
==== AuthContext ====
**File:** ''contexts/AuthContext.tsx''
Manages authentication state across the app.
^ Property / Method ^ Description ^
| ''user'' | Current user object (or ''null'') |
| ''isAuthenticated'' | Boolean -- whether user has a valid token |
| ''isLoading'' | Boolean -- whether auth state is being determined |
| ''login(credentials)'' | Sends login request, stores token, loads profile |
| ''logout()'' | Clears token, clears cache, redirects to /login |
| ''setAuthToken(token)'' | Stores token in localStorage |
| ''clearAuthToken()'' | Removes token from localStorage |
Internally uses a React Query ''profileQuery'' to fetch ''/api/me'' and keep user data fresh. The query is disabled when no token is present, on public routes, or after a 401 error.
==== BackendHealthContext ====
**File:** ''contexts/BackendHealthContext.tsx''
Tracks whether the backend API is reachable.
^ Property / Method ^ Description ^
| ''isBackendDown'' | Boolean -- true after 2 consecutive failures |
| ''reportFailure()'' | Called by API client on 502/503/504 or network error |
| ''reportSuccess()'' | Called by API client on successful response |
* **Failure threshold:** 2 consecutive failures before marking backend as down
* **Auto-reset:** Clears ''isBackendDown'' after 30 seconds to allow retry
* **Global handlers:** Exposes functions for non-React code (API client)
==== ErrorContext ====
**File:** ''contexts/ErrorContext.tsx''
Manages restricted access (403) state.
^ Property / Method ^ Description ^
| ''isRestricted'' | Boolean -- true when user lacks permission |
| ''setRestricted(bool)'' | Set restricted state |
| ''restrictedMessage'' | Optional message to display |
==== ThemeContext ====
**File:** ''contexts/ThemeContext.tsx''
Manages light/dark/system theme preference.
^ Property / Method ^ Description ^
| ''theme'' | Current theme: ''light'', ''dark'', or ''system'' |
| ''setTheme(theme)'' | Updates theme and persists to localStorage |
| ''resolvedTheme'' | Actual applied theme (resolves ''system'' to light/dark) |
* Persists to ''localStorage'' under a theme key
* Detects system preference via ''prefers-color-scheme'' media query
* Applies theme class to '''' element for Tailwind dark mode
----
===== TypeScript Types =====
**File:** ''types/api.ts''
All API request/response types are centralized in this file.
==== Authentication Types ====
* ''User'' -- User object with vendor accesses
* ''LoginRequest'', ''LoginResponse''
* ''SignupRequest'', ''SignupResponse''
* ''ForgotPasswordRequest''
* ''ResetPasswordRequest''
* ''ChangePasswordRequest''
* ''CompleteRegistrationRequest'', ''CompleteRegistrationResponse''
==== Case Types ====
* ''CaseRecord'' -- Case with visible/hidden field groups
* ''CasesPagination'', ''CasesPaginationLink''
* ''CasesApiResponse''
* ''CaseDetailResponse''
* ''CasesFilters'' -- Query parameters for case search
* ''BasicFilters'' -- Simplified filter set
==== Hearing Types ====
* ''Hearing'', ''HearingsApiResponse''
* ''HearingDetail'', ''HearingDetailResponse''
* ''HearingDetailCase'', ''HearingDetailClient'', ''HearingDetailAttorney''
* ''AssignHearingAttorneysResponse'', ''SetMainAttorneyResponse''
* ''CancelHearingResponse'', ''DeleteHearingResponse''
* ''UpdateHearingOptionsResponse'', ''UpdateHearingOptionsVariables''
==== Role & Permission Types ====
* ''Role'', ''RoleHierarchy''
* ''RolesResponse''
* ''VendorInfo'', ''VendorAccess''
* ''MyVendorsResponse''
* ''CheckPermissionRequest'', ''CheckPermissionResponse''
* ''AssignRoleRequest'', ''AssignRoleResponse''
* ''RemoveAccessResponse''
==== Note Types ====
* ''Note'', ''NotesPagination''
* ''NotesListResponse''
* ''CreateNoteRequest'', ''UpdateNoteRequest''
* ''NoteMutationResponse'', ''DeleteNoteResponse''
==== User Types ====
* ''UserRecord'', ''UsersPagination'', ''UsersApiResponse''
* ''UsersFilters''
==== Invitation Types ====
* ''InviteUserRequest'', ''InviteUserResponse''
* ''VerifyTokenRequest'', ''VerifyTokenResponse''
==== User Assignment Types ====
* ''UserAssignment'', ''UserAssignmentsPagination''
* ''UserAssignmentsApiResponse'', ''UserAssignmentsFilters''
==== Preset Types ====
* ''PresetApiRecord'', ''PresetApiResponse''
* ''CreatePresetRequest''
==== Feedback Types ====
* ''FeedbackRequest'', ''FeedbackResponse''
==== Error Types ====
* ''ApiError'' -- Structured API error with status, message, and optional field errors
* ''ApiResponse'' -- Generic wrapper for API responses
----
===== Route Protection =====
The frontend uses a **deny-by-default** approach with three layers of protection.
==== Layer 1: Next.js Middleware ====
**File:** ''middleware.ts''
* Runs on every request before rendering
* Maintains a whitelist of public routes: ''/login'', ''/registration'', ''/forgot-password'', ''/password-reset'', ''/verify-email'', ''/not-found'', ''/service-unavailable'', ''/health'', ''/api/health'', ''/api/warmup''
* Redirects root (''/'') to ''/login''
* Excludes: API routes, Next.js internals (''/_next/''), static assets, favicon
* **Limitation:** Cannot access ''localStorage'' (server-side), so token validation happens in Layer 2
==== Layer 2: RouteGuard Component ====
**File:** ''components/RouteGuard.tsx''
* Wraps all ''(dashboard)'' routes
* Checks ''isAuthenticated'' from ''AuthContext''
* Shows loading spinner while auth state is being determined
* Redirects unauthenticated users to ''/login?redirect=''
* Redirects authenticated users away from ''/login'' to ''/cases''
==== Layer 3: Permission-Based UI ====
* Individual pages and components check permissions via ''useRole()'' and ''useVendorPermission()''
* Example: ''/users'' page only accessible to users with ''canManageUsers'' permission
* UI elements hidden/disabled based on role level
----
===== Authentication Flow (Detailed) =====
==== Login ====
- User enters username and password on ''/login''
- ''AuthContext.login()'' calls ''POST /api/login'' with credentials
- Backend validates credentials, returns ''{ token, user }''
- Frontend stores token via ''setAuthToken()'' in ''localStorage''
- ''AuthContext'' updates user state
- ''profileQuery'' refetches ''/api/me'' for complete user profile (with vendor accesses)
- Redirect to ''/cases'' (or URL from ''redirect'' query parameter)
==== 401 Handling ====
- API client receives 401 response from any endpoint
- Sets global ''has401Error'' flag
- Clears token from ''localStorage''
- Prevents further React Query requests
- Redirects to ''/login'' (if not already on a public route)
==== Logout ====
- ''AuthContext.logout()'' calls ''POST /api/logout'' to invalidate server token
- Clears token and user state
- Clears all React Query cache
- Full page redirect to ''/login'' via ''window.location.replace()'' (avoids stale state)
==== Registration ====
- Admin creates invitation via ''POST /api/user/invitation''
- User receives email with invitation link containing token
- User navigates to ''/registration?token=''
- ''useVerifyToken()'' validates the token against backend
- User sets password and submits registration form
- ''useCompleteRegistration()'' calls ''POST /api/register''
- User must verify email before logging in
==== Password Reset ====
- User requests reset on ''/forgot-password'' page
- ''POST /api/forgot-password'' sends reset email via SendGrid
- User clicks link in email, arrives at ''/password-reset/[token]''
- User enters new password
- ''POST /api/reset-password'' validates token and updates password
- Backend may return a token (auto-login) or redirect to login
----
===== Next.js Configuration =====
**File:** ''next.config.ts''
^ Setting ^ Value ^
| ''output'' | ''standalone'' (optimized for Docker deployment) |
| ''compress'' | ''true'' |
| ''poweredByHeader'' | ''false'' (security: hides X-Powered-By) |
| ''eslint.ignoreDuringBuilds'' | ''true'' |
==== Security Headers ====
Applied to all routes via ''headers()'' config:
^ Header ^ Value ^
| Strict-Transport-Security | ''max-age=31536000; includeSubDomains'' |
| Content-Security-Policy | Default ''self'', restricted script/style sources |
| X-Content-Type-Options | ''nosniff'' |
| X-Frame-Options | ''DENY'' |
| X-XSS-Protection | ''1; mode=block'' |
----
===== Deployment =====
==== Docker Configuration ====
**Dockerfile** (multi-stage build):
- **Stage 1 (deps):** Install Node 20 dependencies
- **Stage 2 (builder):** Build Next.js (''npm run build'')
- **Stage 3 (runner):** Production image with standalone output, non-root user (''nextjs:nodejs''), health checks
**Docker Compose** (''docker-compose.yml''):
services:
web-frontend:
build: .
image: attorney-vendor-portal-frontend
ports: "3000:3000"
environment:
- PORT=3000
- HOSTNAME=0.0.0.0
==== AWS Deployment ====
* Deployed as a container on AWS ECS / Fargate
* Behind an Application Load Balancer (ALB)
* Health checks on ''/api/health''
* Warmup endpoint at ''/api/warmup'' to prevent cold starts
----
===== Local Development =====
==== With Docker ====
cd attorney-vendor-portal-frontend
docker compose build
docker compose up
# Available at http://localhost:3000
==== Without Docker ====
cd attorney-vendor-portal-frontend
npm install
npm run dev
# Available at http://localhost:3000
Requires the backend to be running at the URL specified by ''NEXT_PUBLIC_API_URL''.
==== Mock Mode ====
Run the frontend without a backend using mock case data:
NEXT_PUBLIC_USE_CASES_MOCK=1 npm run dev
This enables the mock API at ''/api/cases'' which returns static case data for development and testing.
----
===== Testing =====
==== Unit Tests (Vitest) ====
npm run test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage report
* Uses Vitest as the test runner
* React Testing Library for component testing
* MSW (Mock Service Worker) for API mocking in tests
==== E2E Tests (Playwright) ====
npx playwright test # Run all E2E tests
npx playwright test --ui # Interactive UI mode
npx playwright show-report # View test report
* Tests run against a running frontend instance
* Covers critical user flows (login, case search, navigation)
For more details, see ''tests/README.md'' in the frontend directory.
----
===== Environment Variables =====
^ Variable ^ Description ^
| ''NEXT_PUBLIC_API_URL'' | Backend API base URL (e.g., ''http://localhost:8000'') |
| ''NEXT_PUBLIC_USE_CASES_MOCK'' | Set to ''1'' to enable mock case data |
| ''PORT'' | Server port (default: ''3000'') |
| ''HOSTNAME'' | Server hostname (default: ''0.0.0.0'' in Docker) |
----
===== Related Documentation =====
* **Portal Index** -- ''attorney-vendor-portal-backend/docs/start.txt''
* **Backend Documentation** -- ''attorney-vendor-portal-backend/docs/backend.txt''
* **Backend API Reference** -- ''attorney-vendor-portal-backend/docs/index.txt'' (per-endpoint docs with request/response examples)