Skip to content

Overview

Adrian Darian edited this page Oct 19, 2025 · 1 revision

Thrive Developer Documentation

Overview

Thrive is a modern job application tracking system built with React 19, TypeScript, Bun, and Vite. This documentation provides technical details for developers working on or extending Thrive.

Table of Contents

  1. Technology Stack
  2. Project Structure
  3. Setup & Installation
  4. Architecture
  5. State Management
  6. Routing
  7. UI Components
  8. Data Models
  9. Utilities & Helpers
  10. Testing
  11. Build & Deployment
  12. Contributing
  13. API Reference

Technology Stack

Core Technologies

  • React 19: Latest React with concurrent features
  • TypeScript 5.6: Strict mode enabled
  • Bun 1.x: JavaScript runtime and package manager
  • Vite 5.x: Build tool and dev server
  • TanStack Router 1.x: Type-safe routing

UI & Styling

  • Tailwind CSS 3.x: Utility-first CSS framework
  • shadcn/ui: Accessible component library
  • Radix UI: Headless UI primitives
  • Lucide Icons: Icon library

State & Data

  • Zustand 4.x: Lightweight state management
  • Zustand Persist: State persistence middleware
  • Recharts: Charting library for analytics

Development Tools

  • Biome: Linting and formatting
  • TypeScript ESLint: Additional TypeScript rules
  • Vitest: Unit testing framework
  • Testing Library: Component testing utilities

Browser Support

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+

Project Structure

thrive/
โ”œโ”€โ”€ docs/                          # Documentation
โ”‚   โ”œโ”€โ”€ USER_GUIDE.md             # User documentation
โ”‚   โ”œโ”€โ”€ DEVELOPER_GUIDE.md        # This file
โ”‚   โ”œโ”€โ”€ API_REFERENCE.md          # API documentation
โ”‚   โ”œโ”€โ”€ DEPLOYMENT.md             # Deployment guide
โ”‚   โ”œโ”€โ”€ accessibility-checklist.md
โ”‚   โ”œโ”€โ”€ cross-browser-testing-checklist.md
โ”‚   โ””โ”€โ”€ phase-*.md                # Phase implementation summaries
โ”‚
โ”œโ”€โ”€ public/                        # Static assets
โ”‚   โ””โ”€โ”€ vite.svg
โ”‚
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ components/               # React components
โ”‚   โ”‚   โ”œโ”€โ”€ a11y/                # Accessibility components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FocusTrap.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ LiveRegion.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ SkipNav.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ VisuallyHidden.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ applications/        # Application management
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationBoard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationDetails.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationFilters.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationForm.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationList.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationSearch.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ StatusBadge.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ analytics/           # Analytics components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AnalyticsDashboard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationFunnel.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ApplicationsOverTime.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InterviewSuccessRate.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ MetricCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ResponseRateByCompany.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ StatusDistribution.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ companies/           # Company research
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CompanyCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CompanyDetails.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CompanyForm.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CompanyList.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ CompanySearch.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard/           # Dashboard components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ActivityTimeline.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ QuickActions.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ QuickStats.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ RecentApplications.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ StatsCard.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ UpcomingInterviews.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ documents/           # Document management
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DocumentCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DocumentList.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DocumentUpload.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ DocumentViewer.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ export/              # Data export
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ExportOptions.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ExportPreview.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ExportProgress.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ interviews/          # Interview management
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InterviewCalendar.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InterviewCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InterviewDetails.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InterviewForm.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ InterviewList.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ layout/              # Layout components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Header.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ MainLayout.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Navigation.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ Sidebar.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ prep/                # Interview prep
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ QuestionBank.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ QuestionCard.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ QuestionCategories.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ QuestionSearch.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ”œโ”€โ”€ settings/            # Settings
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AppearanceSettings.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DataSettings.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NotificationSettings.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ProfileSettings.tsx
โ”‚   โ”‚   โ”‚
โ”‚   โ”‚   โ””โ”€โ”€ ui/                  # Shared UI components (shadcn/ui)
โ”‚   โ”‚       โ”œโ”€โ”€ alert.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ avatar.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ badge.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ button.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ card.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ checkbox.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ dialog.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ dropdown-menu.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ empty-state.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ error-state.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ input.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ label.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ loading-skeletons.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ select.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ separator.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ sheet.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ skeleton.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ switch.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ table.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ tabs.tsx
โ”‚   โ”‚       โ”œโ”€โ”€ textarea.tsx
โ”‚   โ”‚       โ””โ”€โ”€ toast.tsx
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ hooks/                   # Custom React hooks
โ”‚   โ”‚   โ”œโ”€โ”€ useApplications.ts
โ”‚   โ”‚   โ”œโ”€โ”€ useCompanies.ts
โ”‚   โ”‚   โ”œโ”€โ”€ useDocuments.ts
โ”‚   โ”‚   โ”œโ”€โ”€ useInterviews.ts
โ”‚   โ”‚   โ”œโ”€โ”€ useLocalStorage.ts
โ”‚   โ”‚   โ”œโ”€โ”€ useNotifications.ts
โ”‚   โ”‚   โ””โ”€โ”€ useTheme.ts
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ lib/                     # Utility libraries
โ”‚   โ”‚   โ”œโ”€โ”€ accessibility.ts     # Accessibility helpers
โ”‚   โ”‚   โ”œโ”€โ”€ browser-detection.ts # Browser detection
โ”‚   โ”‚   โ”œโ”€โ”€ constants.ts         # App constants
โ”‚   โ”‚   โ”œโ”€โ”€ export.ts            # Data export utilities
โ”‚   โ”‚   โ”œโ”€โ”€ keyboard.ts          # Keyboard navigation
โ”‚   โ”‚   โ”œโ”€โ”€ responsive-testing.ts # Responsive utilities
โ”‚   โ”‚   โ””โ”€โ”€ utils.ts             # General utilities
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ routes/                  # Route components
โ”‚   โ”‚   โ”œโ”€โ”€ __root.tsx           # Root layout
โ”‚   โ”‚   โ”œโ”€โ”€ analytics.tsx        # Analytics page
โ”‚   โ”‚   โ”œโ”€โ”€ applications.tsx     # Applications page
โ”‚   โ”‚   โ”œโ”€โ”€ companies.tsx        # Companies page
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard.tsx        # Dashboard page
โ”‚   โ”‚   โ”œโ”€โ”€ documents.tsx        # Documents page
โ”‚   โ”‚   โ”œโ”€โ”€ export.tsx           # Export page
โ”‚   โ”‚   โ”œโ”€โ”€ index.tsx            # Home page
โ”‚   โ”‚   โ”œโ”€โ”€ interviews.tsx       # Interviews page
โ”‚   โ”‚   โ”œโ”€โ”€ prep.tsx             # Interview prep page
โ”‚   โ”‚   โ””โ”€โ”€ settings.tsx         # Settings page
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ store/                   # Zustand stores
โ”‚   โ”‚   โ”œโ”€โ”€ applicationStore.ts  # Application state
โ”‚   โ”‚   โ”œโ”€โ”€ companyStore.ts      # Company state
โ”‚   โ”‚   โ”œโ”€โ”€ documentStore.ts     # Document state
โ”‚   โ”‚   โ”œโ”€โ”€ interviewStore.ts    # Interview state
โ”‚   โ”‚   โ”œโ”€โ”€ notificationStore.ts # Notification state
โ”‚   โ”‚   โ””โ”€โ”€ settingsStore.ts     # Settings state
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ styles/                  # Global styles
โ”‚   โ”‚   โ”œโ”€โ”€ browser-fixes.css    # Browser-specific fixes
โ”‚   โ”‚   โ””โ”€โ”€ globals.css          # Global CSS + Tailwind
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ types/                   # TypeScript type definitions
โ”‚   โ”‚   โ”œโ”€โ”€ application.ts       # Application types
โ”‚   โ”‚   โ”œโ”€โ”€ company.ts           # Company types
โ”‚   โ”‚   โ”œโ”€โ”€ document.ts          # Document types
โ”‚   โ”‚   โ”œโ”€โ”€ interview.ts         # Interview types
โ”‚   โ”‚   โ”œโ”€โ”€ interviewPrep.ts     # Interview prep types
โ”‚   โ”‚   โ””โ”€โ”€ notification.ts      # Notification types
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ main.tsx                 # App entry point
โ”‚   โ””โ”€โ”€ routeTree.gen.ts         # Generated route tree
โ”‚
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ biome.json                   # Biome configuration
โ”œโ”€โ”€ components.json              # shadcn/ui configuration
โ”œโ”€โ”€ index.html
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ postcss.config.js            # PostCSS configuration
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ tailwind.config.js           # Tailwind configuration
โ”œโ”€โ”€ tsconfig.json                # TypeScript configuration
โ”œโ”€โ”€ tsconfig.node.json
โ””โ”€โ”€ vite.config.ts               # Vite configuration

Setup & Installation

Prerequisites

  • Bun: v1.0.0 or higher
  • Node.js: v18.0.0 or higher (for compatibility)
  • Git: For version control

Installation Steps

# Clone the repository
git clone https://github.com/yourusername/thrive.git
cd thrive

# Install dependencies
bun install

# Start development server
bun run dev

# Open in browser
# Navigate to http://localhost:5173

Available Scripts

# Development
bun run dev          # Start dev server with hot reload
bun run build        # Build for production
bun run preview      # Preview production build
bun run lint         # Run Biome linter
bun run format       # Format code with Biome
bun run type-check   # TypeScript type checking

# Testing (when implemented)
bun test             # Run unit tests
bun test:watch       # Run tests in watch mode
bun test:coverage    # Generate coverage report

Environment Variables

Create a .env file in the root directory:

# API Configuration (if backend is added)
VITE_API_URL=http://localhost:3000/api

# Feature Flags
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_NOTIFICATIONS=true

# Build Configuration
VITE_APP_VERSION=1.0.0

Architecture

Design Principles

  1. Component-Based: Modular, reusable components
  2. Type-Safe: Strict TypeScript throughout
  3. Accessible: WCAG 2.1 AA compliance
  4. Performant: Code splitting, lazy loading, memoization
  5. Maintainable: Clear structure, documentation, conventions

Data Flow

User Action
    โ†“
Component Event Handler
    โ†“
Zustand Store Action
    โ†“
State Update
    โ†“
Component Re-render
    โ†“
LocalStorage Persistence (via middleware)

Folder-by-Feature Structure

Components are organized by feature (applications, interviews, etc.) rather than by type (containers, presentational). This makes it easier to find related code and manage features independently.

Code Splitting

Routes are automatically code-split by TanStack Router. Additional components can be lazy-loaded:

import { lazy } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

State Management

Zustand Store Pattern

All stores follow a consistent pattern:

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface StoreState {
  // State
  items: Item[];
  
  // Actions
  addItem: (item: Item) => void;
  updateItem: (id: string, updates: Partial<Item>) => void;
  deleteItem: (id: string) => void;
}

export const useStore = create<StoreState>()(
  persist(
    (set, get) => ({
      // Initial state
      items: [],
      
      // Actions
      addItem: (item) => 
        set((state) => ({ items: [...state.items, item] })),
      
      updateItem: (id, updates) =>
        set((state) => ({
          items: state.items.map((item) =>
            item.id === id ? { ...item, ...updates } : item
          ),
        })),
      
      deleteItem: (id) =>
        set((state) => ({
          items: state.items.filter((item) => item.id !== id),
        })),
    }),
    {
      name: 'store-name',
      version: 1,
    }
  )
);

Available Stores

Application Store (store/applicationStore.ts)

interface ApplicationStore {
  applications: Application[];
  addApplication: (app: Application) => void;
  updateApplication: (id: string, updates: Partial<Application>) => void;
  deleteApplication: (id: string) => void;
  getApplicationById: (id: string) => Application | undefined;
  getApplicationsByStatus: (status: ApplicationStatus) => Application[];
}

Interview Store (store/interviewStore.ts)

interface InterviewStore {
  interviews: Interview[];
  addInterview: (interview: Interview) => void;
  updateInterview: (id: string, updates: Partial<Interview>) => void;
  deleteInterview: (id: string) => void;
  getInterviewsByApplication: (appId: string) => Interview[];
  getUpcomingInterviews: () => Interview[];
}

Company Store (store/companyStore.ts)

interface CompanyStore {
  companies: Company[];
  addCompany: (company: Company) => void;
  updateCompany: (id: string, updates: Partial<Company>) => void;
  deleteCompany: (id: string) => void;
  getCompanyById: (id: string) => Company | undefined;
}

Store Usage in Components

function MyComponent() {
  // Select specific state
  const applications = useApplicationStore((state) => state.applications);
  const addApplication = useApplicationStore((state) => state.addApplication);
  
  // Or select multiple
  const { applications, addApplication } = useApplicationStore();
  
  // Derived state (memoized automatically)
  const activeApps = useApplicationStore((state) =>
    state.applications.filter((app) => app.status === 'active')
  );
  
  return (
    <button onClick={() => addApplication(newApp)}>
      Add Application
    </button>
  );
}

Routing

TanStack Router

Thrive uses file-based routing with TanStack Router for type-safe navigation.

Route Structure

routes/
โ”œโ”€โ”€ __root.tsx           # Root layout (wraps all routes)
โ”œโ”€โ”€ index.tsx            # / (home/dashboard)
โ”œโ”€โ”€ applications.tsx     # /applications
โ”œโ”€โ”€ interviews.tsx       # /interviews
โ”œโ”€โ”€ companies.tsx        # /companies
โ”œโ”€โ”€ documents.tsx        # /documents
โ”œโ”€โ”€ analytics.tsx        # /analytics
โ”œโ”€โ”€ prep.tsx             # /prep
โ”œโ”€โ”€ export.tsx           # /export
โ””โ”€โ”€ settings.tsx         # /settings

Creating a New Route

  1. Create route file in src/routes/:
// src/routes/new-page.tsx
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/new-page')({
  component: NewPageComponent,
});

function NewPageComponent() {
  return (
    <div>
      <h1>New Page</h1>
    </div>
  );
}
  1. Router automatically picks it up (no manual registration needed)

  2. Navigate to /new-page

Navigation

import { Link, useNavigate } from '@tanstack/react-router';

function MyComponent() {
  const navigate = useNavigate();
  
  return (
    <>
      {/* Declarative navigation */}
      <Link to="/applications">Applications</Link>
      
      {/* Programmatic navigation */}
      <button onClick={() => navigate({ to: '/interviews' })}>
        Go to Interviews
      </button>
    </>
  );
}

Route Parameters

// Route with parameter
export const Route = createFileRoute('/applications/$appId')({
  component: ApplicationDetailsComponent,
});

function ApplicationDetailsComponent() {
  const { appId } = Route.useParams();
  
  return <div>Application ID: {appId}</div>;
}

Search Params

export const Route = createFileRoute('/applications')({
  component: ApplicationsComponent,
  validateSearch: (search) => ({
    status: search.status as string | undefined,
    page: Number(search.page ?? 1),
  }),
});

function ApplicationsComponent() {
  const { status, page } = Route.useSearch();
  
  return <div>Status: {status}, Page: {page}</div>;
}

UI Components

shadcn/ui Components

Thrive uses shadcn/ui components, which are customizable and accessible. Components are copied into src/components/ui/ for full control.

Adding a New shadcn Component

# Add a component
bunx shadcn@latest add button

# Add multiple components
bunx shadcn@latest add card dialog input

Component Patterns

Compound Components

// Card with subcomponents
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';

function MyCard() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Title</CardTitle>
      </CardHeader>
      <CardContent>Content</CardContent>
    </Card>
  );
}

Controlled vs Uncontrolled

// Controlled
function ControlledInput() {
  const [value, setValue] = useState('');
  
  return (
    <Input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

// Uncontrolled (with ref)
function UncontrolledInput() {
  const inputRef = useRef<HTMLInputElement>(null);
  
  const handleSubmit = () => {
    console.log(inputRef.current?.value);
  };
  
  return <Input ref={inputRef} />;
}

Composition

// Compose smaller components
function ApplicationCard({ application }: Props) {
  return (
    <Card>
      <CardHeader>
        <StatusBadge status={application.status} />
        <CardTitle>{application.position}</CardTitle>
      </CardHeader>
      <CardContent>
        <CompanyInfo company={application.company} />
        <DateInfo date={application.appliedDate} />
      </CardContent>
    </Card>
  );
}

Custom Hooks

Create reusable logic with custom hooks:

// useApplications.ts
export function useApplications() {
  const applications = useApplicationStore((state) => state.applications);
  const addApplication = useApplicationStore((state) => state.addApplication);
  
  const activeApplications = useMemo(
    () => applications.filter((app) => app.status !== 'rejected'),
    [applications]
  );
  
  return {
    applications,
    activeApplications,
    addApplication,
  };
}

// Usage in component
function MyComponent() {
  const { activeApplications, addApplication } = useApplications();
  
  return <div>{activeApplications.length} active</div>;
}

Data Models

Application

interface Application {
  id: string;
  position: string;
  company: string;
  status: ApplicationStatus;
  appliedDate: string;
  location?: string;
  jobType?: 'remote' | 'hybrid' | 'onsite';
  salaryRange?: {
    min: number;
    max: number;
    currency: string;
  };
  description?: string;
  url?: string;
  notes?: Note[];
  documents?: string[]; // Document IDs
  contacts?: Contact[];
  createdAt: string;
  updatedAt: string;
}

type ApplicationStatus =
  | 'wishlist'
  | 'applied'
  | 'screening'
  | 'phone-interview'
  | 'interview'
  | 'assessment'
  | 'offer'
  | 'accepted'
  | 'rejected'
  | 'withdrawn';

Interview

interface Interview {
  id: string;
  applicationId: string;
  type: InterviewType;
  date: string;
  duration: number; // minutes
  location?: string;
  isRemote: boolean;
  meetingLink?: string;
  interviewers?: Interviewer[];
  notes?: string;
  preparation?: string;
  followUpDate?: string;
  status: 'scheduled' | 'completed' | 'cancelled';
  createdAt: string;
  updatedAt: string;
}

type InterviewType =
  | 'phone-screen'
  | 'video-call'
  | 'onsite'
  | 'technical'
  | 'behavioral'
  | 'panel'
  | 'final';

Company

interface Company {
  id: string;
  name: string;
  website?: string;
  industry?: string;
  size?: string;
  location?: string;
  description?: string;
  culture?: string;
  benefits?: string[];
  techStack?: string[];
  interviewProcess?: string;
  notes?: string;
  rating?: number;
  createdAt: string;
  updatedAt: string;
}

Document

interface Document {
  id: string;
  name: string;
  type: DocumentType;
  fileType: string;
  size: number;
  url: string;
  applicationIds?: string[];
  tags?: string[];
  version: number;
  uploadedAt: string;
  updatedAt: string;
}

type DocumentType =
  | 'resume'
  | 'cover-letter'
  | 'portfolio'
  | 'certification'
  | 'reference'
  | 'other';

Utilities & Helpers

General Utilities (lib/utils.ts)

// Class name utility (for Tailwind)
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

// Date formatting
export function formatDate(date: string | Date): string {
  return new Date(date).toLocaleDateString();
}

// ID generation
export function generateId(): string {
  return crypto.randomUUID();
}

// Debounce
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timeout: NodeJS.Timeout;
  return (...args: Parameters<T>) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => func(...args), wait);
  };
}

Accessibility Utilities (lib/accessibility.ts)

// Screen reader announcements
export function announceToScreenReader(message: string): void {
  const announcement = document.createElement('div');
  announcement.setAttribute('role', 'status');
  announcement.setAttribute('aria-live', 'polite');
  announcement.className = 'sr-only';
  announcement.textContent = message;
  document.body.appendChild(announcement);
  setTimeout(() => document.body.removeChild(announcement), 1000);
}

// Generate accessible labels
export function getStatusAriaLabel(status: ApplicationStatus): string {
  const labels: Record<ApplicationStatus, string> = {
    wishlist: 'On wishlist',
    applied: 'Application submitted',
    screening: 'In screening process',
    // ... etc
  };
  return labels[status];
}

Export Utilities (lib/export.ts)

// Export to CSV
export function exportToCSV(data: Application[]): void {
  const csv = convertToCSV(data);
  downloadFile(csv, 'applications.csv', 'text/csv');
}

// Export to JSON
export function exportToJSON(data: any): void {
  const json = JSON.stringify(data, null, 2);
  downloadFile(json, 'applications.json', 'application/json');
}

// Export to PDF
export function exportToPDF(data: Application[]): Promise<void> {
  // PDF generation logic
}

Browser Detection (lib/browser-detection.ts)

// Detect browser
export function detectBrowser(): BrowserInfo {
  // Returns browser name, version, OS, device type
}

// Check if browser is supported
export function isBrowserSupported(): boolean {
  const browser = detectBrowser();
  const minVersions = {
    chrome: 90,
    firefox: 88,
    safari: 14,
    edge: 90,
  };
  return browser.majorVersion >= minVersions[browser.name];
}

Testing

Testing Setup

# Install testing dependencies (if not already installed)
bun add -d vitest @testing-library/react @testing-library/jest-dom
bun add -d @testing-library/user-event happy-dom

Unit Testing

// ApplicationCard.test.tsx
import { render, screen } from '@testing-library/react';
import { ApplicationCard } from './ApplicationCard';

describe('ApplicationCard', () => {
  const mockApplication = {
    id: '1',
    position: 'Software Engineer',
    company: 'Test Company',
    status: 'applied',
    appliedDate: '2025-10-01',
  };
  
  it('renders application details', () => {
    render(<ApplicationCard application={mockApplication} />);
    
    expect(screen.getByText('Software Engineer')).toBeInTheDocument();
    expect(screen.getByText('Test Company')).toBeInTheDocument();
  });
  
  it('shows correct status badge', () => {
    render(<ApplicationCard application={mockApplication} />);
    
    expect(screen.getByText('Applied')).toBeInTheDocument();
  });
});

Integration Testing

// ApplicationList.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ApplicationList } from './ApplicationList';

describe('ApplicationList', () => {
  it('filters applications by status', async () => {
    const user = userEvent.setup();
    render(<ApplicationList />);
    
    const filterButton = screen.getByRole('button', { name: /filter/i });
    await user.click(filterButton);
    
    const appliedFilter = screen.getByRole('checkbox', { name: /applied/i });
    await user.click(appliedFilter);
    
    // Assert filtered results
  });
});

Store Testing

// applicationStore.test.ts
import { renderHook, act } from '@testing-library/react';
import { useApplicationStore } from './applicationStore';

describe('Application Store', () => {
  it('adds an application', () => {
    const { result } = renderHook(() => useApplicationStore());
    
    const newApp = {
      id: '1',
      position: 'Developer',
      company: 'Test Corp',
      status: 'applied',
      appliedDate: '2025-10-01',
    };
    
    act(() => {
      result.current.addApplication(newApp);
    });
    
    expect(result.current.applications).toHaveLength(1);
    expect(result.current.applications[0]).toEqual(newApp);
  });
});

Build & Deployment

Production Build

# Build for production
bun run build

# Preview production build locally
bun run preview

Build Output

dist/
โ”œโ”€โ”€ assets/
โ”‚   โ”œโ”€โ”€ index-[hash].js
โ”‚   โ”œโ”€โ”€ index-[hash].css
โ”‚   โ””โ”€โ”€ [other chunks]
โ”œโ”€โ”€ index.html
โ””โ”€โ”€ vite.svg

Build Optimization

Automatic Optimizations:

  • Code splitting by route
  • Tree shaking
  • Minification
  • Asset optimization
  • CSS purging (unused Tailwind classes)

Manual Optimizations:

  • Lazy load heavy components
  • Use React.memo for expensive renders
  • Implement virtualization for long lists
  • Optimize images (WebP format)

Deployment

See DEPLOYMENT.md for detailed deployment instructions.

Quick Deploy to Vercel:

# Install Vercel CLI
bun add -g vercel

# Deploy
vercel

Contributing

Code Style

  • TypeScript: Strict mode, explicit types
  • Formatting: Biome (runs on commit)
  • Naming: camelCase for variables, PascalCase for components
  • Files: kebab-case for files, PascalCase for components

Git Workflow

# Create feature branch
git checkout -b feature/my-feature

# Make changes and commit
git add .
git commit -m "feat: add new feature"

# Push and create PR
git push origin feature/my-feature

Commit Messages

Follow Conventional Commits:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting)
  • refactor: Code refactoring
  • test: Adding tests
  • chore: Build process or auxiliary tools

Pull Request Process

  1. Create a feature branch
  2. Make your changes
  3. Add tests if applicable
  4. Update documentation
  5. Run bun run lint and bun run type-check
  6. Create PR with clear description
  7. Wait for review and approval

API Reference

See API_REFERENCE.md for detailed API documentation of all components, hooks, stores, and utilities.


Performance Tips

Optimization Strategies

  1. Memoization:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  1. Callback Memoization:
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);
  1. Component Memoization:
const MemoizedComponent = React.memo(MyComponent);
  1. Virtualization (for long lists):
import { useVirtualizer } from '@tanstack/react-virtual';
  1. Code Splitting:
const HeavyComponent = lazy(() => import('./HeavyComponent'));

Performance Monitoring

Use React DevTools Profiler to identify performance bottlenecks:

  1. Open React DevTools
  2. Go to Profiler tab
  3. Start recording
  4. Perform actions
  5. Stop recording
  6. Analyze render times

Troubleshooting

Common Issues

Build fails with TypeScript errors:

  • Run bun run type-check to see errors
  • Fix type errors before building

Hot reload not working:

  • Check Vite config
  • Restart dev server
  • Clear .vite cache

Store not persisting:

  • Check localStorage is enabled
  • Check store configuration
  • Verify persist middleware setup

Route not found:

  • Ensure route file is in src/routes/
  • Check route file naming
  • Restart dev server

Resources

Documentation

Tools


Last Updated: October 18, 2025 Version: 1.0.0

๐Ÿ“š Documentation

๐Ÿ  Home

๐Ÿš€ Getting Started

๐Ÿ‘ฅ User Guide

๐Ÿ’ป Developer Guide

๐Ÿ“– API Reference

๐Ÿš€ Deployment

๐Ÿงช Testing

๐Ÿ”ง Troubleshooting

๐Ÿ“œ History

๐Ÿ”ฎ Future Enhancements


๐Ÿ”— Quick Links

Clone this wiki locally