# Lesar Consults Website - Technical Documentation Guide

<p align="center"><a href="https://www.lesarconsults.org/"><strong>https://www.lesarconsults.org/</strong></a></p>

## 1. High-Level System Overview

The website code is hosted on GitHub in the repository below. Kindly email <mark style="color:$primary;"><billjmageni@gmail.com></mark> for access to this repository.

{% embed url="<https://github.com/Bjoseph23/lesar-consults-v2>" %}

### 1.1 What the Website Does

Lesar Consults is a professional consultancy firm website serving two primary purposes:

* **Public-facing platform**: Showcases services, team, projects, and resources for potential clients and partners
* **Admin dashboard**: Enables content management, lead tracking, and resource publishing

### 1.2 Core Features

| Feature           | Description                                                                    |
| ----------------- | ------------------------------------------------------------------------------ |
| Service Showcase  | Seven specialized consultancy services with detailed pages                     |
| Team Profiles     | Individual team member profiles with education, expertise, and project history |
| Project Portfolio | Featured and archived projects with metrics and achievements                   |
| Resource Library  | Gated and ungated downloadable resources (reports, tools, case studies)        |
| Contact Wizard    | Multi-step form with file uploads and email notifications                      |
| Admin Dashboard   | Lead management, resource editing, analytics overview                          |

### 1.3 User Flows

**Public Users:**

```markdown
Landing Page -> Browse Services/Team/Projects -> View Resources -> Submit Contact Form -> Receive Confirmation
```

**Admin Users:**

```
Login (/admin/login) -> Dashboard -> Manage Resources -> Review Leads -> Export Data
```

### 1.4 Architecture Diagram

```
+------------------+     +-------------------+     +------------------+
|   React Frontend |<--->| Supabase Backend  |<--->| Edge Functions   |
|   (Vite + TS)    |     | (PostgreSQL + RLS)|     | (Deno Runtime)   |
+------------------+     +-------------------+     +------------------+
        |                        |                        |
        v                        v                        v
   Tailwind CSS            Storage Buckets         Email Webhooks
   shadcn/ui               (leads-uploads,         (n8n/Railway)
   TipTap Editor           resources)
```

***

## 2. Technology Stack

### 2.1 Frontend Framework

| Technology | Version | Purpose                   |
| ---------- | ------- | ------------------------- |
| React      | 18.3.1  | UI component library      |
| TypeScript | 5.x     | Type-safe JavaScript      |
| Vite       | 5.x     | Build tool and dev server |

**Why React + Vite**: Fast development iteration with HMR, excellent TypeScript support, and optimised production builds.

### 2.2 Styling System

| Technology          | Purpose                     |
| ------------------- | --------------------------- |
| Tailwind CSS        | Utility-first styling       |
| tailwindcss-animate | Animation utilities         |
| shadcn/ui           | Pre-built component library |
| CSS Variables       | Design token system         |

**Design System Colors** (from `index.css`):

* `--navy: 227 57% 19%` (#162356) - Primary brand color
* `--cream: 37 65% 91%` (#FAEED4) - Secondary background
* `--dark-red: 0 50% 33%` (#8B1E1E) - Accent color

### 2.3 Routing

| Package          | Purpose             |
| ---------------- | ------------------- |
| react-router-dom | Client-side routing |

Routes are defined in `App.tsx` with protected routes using `ProtectedRoute` component.

### 2.4 Backend Services (Supabase)

| Service             | Usage                                           |
| ------------------- | ----------------------------------------------- |
| PostgreSQL Database | Leads, resources, profiles tables               |
| Supabase Auth       | Admin authentication                            |
| Storage             | File uploads (leads-uploads, resources buckets) |
| Edge Functions      | Signed URLs, email forwarding                   |

### 2.5 Email System

* Edge function `send-lead-email` forwards lead data to an external webhook (n8n on Railway)
* Non-blocking: Email failures don't prevent form submission

### 2.6 Deployment

| Platform       | Purpose                         |
| -------------- | ------------------------------- |
| Vercel         | Frontend hosting with analytics |
| Supabase Cloud | Backend hosting                 |

Configuration files: `vercel.json`, `public/_redirects`

***

## 3. Frontend Architecture

### 3.1 Folder Structure

```
src/
├── components/           # Reusable UI components
│   ├── admin/           # Admin-specific components
│   │   ├── AdminLayout.tsx
│   │   ├── ProtectedRoute.tsx
│   │   └── ResourceEditor/
│   ├── contact/         # Contact form components
│   │   ├── ContactWizard.tsx
│   │   ├── ProgressBar.tsx
│   │   ├── SuccessOptions.tsx
│   │   └── steps/       # Form step components
│   ├── resources/       # Resource library components
│   ├── team/            # Team page components
│   └── ui/              # shadcn/ui primitives
├── contexts/            # React contexts
│   └── AuthContext.tsx  # Authentication state
├── data/                # Static JSON data files
│   ├── about.json
│   ├── services.json
│   ├── projects.json
│   └── team.json
├── hooks/               # Custom React hooks
├── integrations/        # External service clients
│   └── supabase/
├── lib/                 # Utility functions
├── pages/               # Route components
│   ├── admin/           # Admin pages
│   └── ...              # Public pages
└── index.css            # Global styles + design system
```

### 3.2 Component Categories

**Page Components** (`src/pages/`):

* Full-page layouts with SEO metadata
* Compose multiple UI components
* Handle data fetching

**Layout Components**:

* `Navbar.tsx`: Responsive navigation with dropdown menus
* `Footer.tsx`: Site footer with newsletter signup
* `AdminLayout.tsx`: Admin sidebar and header

**Feature Components**:

* `ContactWizard.tsx`: Multi-step form orchestrator
* `ResourceEditor/index.tsx`: Rich text editor for resources

**UI Primitives** (`src/components/ui/`):

* Button, Card, Dialog, Input, etc.
* Built on Radix UI primitives
* Styled with Tailwind CSS

### 3.3 Styling Conventions

```css
/* Button variants (index.css) */
.btn-primary   /* Navy background, white text */
.btn-secondary /* Cream background, navy text */
.btn-accent    /* Dark red background */

/* Animation classes */
.animate-fade-in
.animate-slide-up
.cta-glisten   /* Shimmer effect on CTA buttons */

/* Card variants */
.card-elevated
.card-service
```

***

## 4. Page-by-Page Breakdown

### 4.1 Home Page (`/`)

**File**: `src/pages/Index.tsx`

**Components**:

* `Hero`: Full-width hero with CTA buttons
* `PartnersMarquee`: Animated logo carousel
* `ServicesStrip`: Service overview cards
* `Counters`: Animated impact statistics
* `FeaturedCase`: Highlighted project
* `ResourcesGrid`: Latest resources preview
* `WhyChoose`: Value propositions

**Data Source**: Static imports, Supabase for resources

### 4.2 About Page (`/about`)

**File**: `src/pages/About.tsx`

**Components**:

* `AboutHero`: Hero with headline from JSON
* `ValuesGrid`: Company values cards
* `ApproachTimeline`: Methodology steps
* `Image3DCarousel`: Work showcase
* `QASection`: Quality assurance points
* `PartnersMarquee`: Client logos

**Data Source**: `src/data/about.json`

### 4.3 Services Page (`/services`)

**File**: `src/pages/Services.tsx`

**Features**:

* Service grid with alternating layouts
* Icon mapping for each service type
* Links to individual service detail pages

**Data Source**: `src/data/services.json`

### 4.4 Team Page (`/team`)

**File**: `src/pages/Team.tsx`

**Components**:

* `TeamGrid`: Grid of team member cards
* `Timeline`: Company milestones
* Links to individual member profiles

**Data Source**: `src/data/team.json`, `src/data/milestones.json`

### 4.5 Projects Page (`/projects`)

**File**: `src/pages/Projects.tsx`

**Features**:

* Featured projects with full details
* Additional projects in card grid
* Metrics and achievements display
* Download button for certain projects

**Data Source**: `src/data/projects.json`

### 4.6 Resources Page (`/resources`)

**File**: `src/pages/Resources.tsx`

**Features**:

* Search and filter functionality
* Category scroller
* Type and year filters
* Resource cards with thumbnails

**Data Source**: Supabase `resources` table

### 4.7 Contact Page (`/contact`)

**File**: `src/pages/Contact.tsx`

Contains `ContactWizard` component (detailed in Section 5).

### 4.8 Admin Dashboard (`/admin/dashboard`)

**File**: `src/pages/admin/AdminDashboard.tsx`

**Features**:

* Statistics cards (resources, leads, downloads)
* Recent activity feed
* Quick action links

**Data Source**: Supabase queries on mount

### 4.9 Admin Leads (`/admin/leads`)

**File**: `src/pages/admin/AdminLeads.tsx`

**Features**:

* Lead table with search/filter
* Export to PDF, CSV, Excel
* Lead detail modal with file attachments
* Delete with cascade (files + records)

***

## 5. Contact Wizard (Detailed)

### 5.1 Wizard Structure

**Main Component**: `src/components/contact/ContactWizard.tsx`

```
ContactWizard
├── ProgressBar         # Visual step indicator
├── Step Components     # 6 individual form steps
├── Navigation          # Back/Next/Submit buttons
└── handleSubmit()      # Submission logic
```

**Step Components** (`src/components/contact/steps/`):

| Step | Component     | Purpose                                   |
| ---- | ------------- | ----------------------------------------- |
| 1    | StepOne.tsx   | Full name collection                      |
| 2    | StepTwo.tsx   | Organization and role                     |
| 3    | StepThree.tsx | Email and phone with country code         |
| 4    | StepFour.tsx  | Service selection and project description |
| 5    | StepFive.tsx  | Budget, timeframe, file uploads           |
| 6    | StepSix.tsx   | Privacy consent                           |

### 5.2 State and Validation

**Form State Shape** (TypeScript interface):

```typescript
interface FormData {
  fullName: string;
  organization: string;
  role: string;
  email: string;
  phone: string;
  countryCode: string;
  services: string[];
  otherService: string;
  description: string;
  budget: string;
  customBudget: string;
  timeframe: string;
  files: File[];
  consent: boolean;
}
```

**Validation Rules** (`isStepValid()` function):

| Step | Validation                                |
| ---- | ----------------------------------------- |
| 1    | `fullName.length > 0`                     |
| 2    | `organization.length > 0`                 |
| 3    | Valid email regex + phone length > 0      |
| 4    | At least one service + description filled |
| 5    | Timeframe selected                        |
| 6    | Consent checkbox checked                  |

**Submission Guards**:

* `isSubmitting` state prevents double-submission
* `isSubmitted` flag disables button after success

### 5.3 Submission Flow (End-to-End)

{% stepper %}
{% step %}

### Submit Request: create lead record

1. User clicks "Submit Request".
2. Generate client-side UUID for `lead_id`.
3. INSERT into `leads` table (lead record stored).
   {% endstep %}

{% step %}

### Upload files (for each file)

1. Request signed upload URL from Edge Function (`create-signed-url`).
2. PUT file directly to the signed upload URL.
3. Request signed download URL from Edge Function (`get-signed-download-url`).
4. INSERT a record into `leads_uploads` with `file_path` (and store signed URL as `file_url` if needed).
   {% endstep %}

{% step %}

### Post-submit notifications and UX

1. Invoke `send-lead-email` Edge Function (non-blocking).
2. Show success toast to user.
3. Navigate to `SuccessOptions` component.
   {% endstep %}
   {% endstepper %}

**Error Handling**:

* File upload failures are logged but don't block submission.
* Email failures are caught and logged silently.
* Database errors show a user-friendly toast.

***

## 6. Supabase Database Schema

### 6.1 Tables

**`leads`** - Contact form submissions

| Column         | Type        | Purpose                |
| -------------- | ----------- | ---------------------- |
| id             | UUID (PK)   | Unique identifier      |
| name           | TEXT        | Contact name           |
| email          | TEXT        | Email address          |
| organization   | TEXT        | Company/institution    |
| role           | TEXT        | Job title              |
| phone          | TEXT        | Phone number           |
| country\_code  | TEXT        | Phone country code     |
| interested\_in | TEXT        | Selected services      |
| other\_service | TEXT        | Custom service input   |
| message        | TEXT        | Project description    |
| budget         | TEXT        | Budget range           |
| timeframe      | TEXT        | Project timeline       |
| resource\_id   | UUID (FK)   | If download-gated lead |
| consent        | BOOLEAN     | Privacy consent        |
| created\_at    | TIMESTAMPTZ | Submission timestamp   |

**`leads_uploads`** - File attachments

| Column      | Type        | Purpose                   |
| ----------- | ----------- | ------------------------- |
| id          | UUID (PK)   | Unique identifier         |
| lead\_id    | UUID (FK)   | Parent lead reference     |
| file\_url   | TEXT        | Signed download URL       |
| file\_path  | TEXT        | Storage path for deletion |
| created\_at | TIMESTAMPTZ | Upload timestamp          |

**`resources`** - Content items

| Column         | Type        | Purpose                                  |
| -------------- | ----------- | ---------------------------------------- |
| id             | TEXT (PK)   | Slug-based identifier                    |
| slug           | TEXT        | URL-friendly identifier                  |
| title          | TEXT        | Resource title                           |
| summary        | TEXT        | Short description                        |
| content\_html  | TEXT        | Rich text content                        |
| categories     | TEXT\[]     | Category array                           |
| tags           | TEXT\[]     | Tag array                                |
| type           | TEXT        | article/case\_study/report/tool/download |
| thumbnail\_url | TEXT        | Cover image URL                          |
| file\_url      | TEXT        | Downloadable file URL                    |
| author         | TEXT        | Content author                           |
| published\_at  | TIMESTAMPTZ | Publication date                         |
| year           | INTEGER     | Publication year                         |
| featured       | BOOLEAN     | Featured flag                            |
| seo            | JSONB       | SEO metadata                             |

**`profiles`** - Admin users

| Column    | Type                        | Purpose              |
| --------- | --------------------------- | -------------------- |
| id        | UUID (PK, FK to auth.users) | User ID              |
| is\_admin | BOOLEAN                     | Admin privilege flag |

### 6.2 Relationships

```
leads ──1:N──> leads_uploads (lead_id FK)
profiles ──1:1──> auth.users (id FK)
leads ──N:1──> resources (resource_id FK, optional)
```

***

## 7. Supabase Storage and Signed URLs

### 7.1 Why Signed URLs

* **Security**: Prevent direct bucket access
* **Expiration**: URLs expire after 1 hour
* **Audit Trail**: Track who requested access
* **RLS Bypass**: Service role generates URLs server-side

### 7.2 Upload Flow

{% stepper %}
{% step %}

### Request signed upload URL

Client: POST /functions/v1/create-signed-url\
Body: { bucket: "leads-uploads", filename: "doc.pdf" }
{% endstep %}

{% step %}

### Edge Function generates upload URL

Edge Function: `createSignedUploadUrl(object_path, 3600)` (service role). Response: { upload\_url: "...", object\_path: "leads/12345\_doc.pdf" }
{% endstep %}

{% step %}

### Client uploads file

Client: PUT file directly to `upload_url`.\
Storage: File saved to bucket at returned `object_path`.
{% endstep %}
{% endstepper %}

### 7.3 Download Flow

{% stepper %}
{% step %}

### Request signed download URL

Client: POST /functions/v1/get-signed-download-url\
Body: { bucket: "leads-uploads", object\_path: "leads/12345\_doc.pdf" }
{% endstep %}

{% step %}

### Edge Function returns signed URL

Edge Function: `createSignedUrl(object_path, 3600)`\
Response: { signed\_download\_url: "..." }
{% endstep %}

{% step %}

### Client uses signed URL

Client: Open `signed_download_url` in new tab (or link for admin).
{% endstep %}
{% endstepper %}

### 7.4 File Path Generation

```javascript
const filenameSafe = `${Date.now()}_${file.name.replace(/\s+/g, "_")}`;
const object_path = `leads/${filenameSafe}`;
```

***

## 8. Supabase Edge Functions

### 8.1 `create-signed-url`

**Purpose**: Generate pre-signed upload URL\
**Location**: `supabase/functions/create-signed-url/index.ts`

**Input**:

```json
{ "bucket": "leads-uploads", "filename": "document.pdf" }
```

**Output**:

```json
{ "upload_url": "https://...", "object_path": "leads/1234_document.pdf" }
```

**Called**: During ContactWizard file upload step

### 8.2 `get-signed-download-url`

**Purpose**: Generate pre-signed download URL\
**Location**: `supabase/functions/get-signed-download-url/index.ts`

**Input**:

```json
{ "bucket": "leads-uploads", "object_path": "leads/1234_document.pdf" }
```

**Output**:

```json
{ "signed_download_url": "https://..." }
```

**Called**: During file upload (for record) and admin file viewing

### 8.3 `send-lead-email`

**Purpose**: Forward lead data to email notification service\
**Location**: `supabase/functions/send-lead-email/index.tsx`<br>

Flow:

{% stepper %}
{% step %}

1. Receive lead payload from client.
   {% endstep %}

{% step %}
2\. Forward to `RAILWAY_WEBHOOK_URL` (n8n) for processing.
{% endstep %}

{% step %}
3\. n8n sends email via configured provider.
{% endstep %}
{% endstepper %}

**Called**: After successful lead insert (non-blocking)

***

## 9. Email System

### 9.1 Architecture

```
ContactWizard -> Edge Function -> n8n Webhook -> Email Provider
                 (send-lead-email)
```

### 9.2 Template Mapping

The lead data object passed to the webhook contains:

* name, email, organization, role
* phone, country\_code
* interested\_in, other\_service
* message, budget, timeframe
* consent, id

n8n transforms this into email templates.

### 9.3 Error Handling

```javascript
try {
  const { error: fnError } = await supabase.functions.invoke("send-lead-email", {
    body: leadData,
  });
  if (fnError) {
    console.warn("Failed to invoke send-lead-email function:", fnError);
  }
} catch (err) {
  console.warn("Exception invoking send-lead-email function:", err);
}
// Form submission continues regardless of email status
```

### 9.4 Non-Blocking Design

Email failures are logged and follow best-effort, they don't prevent:

* Lead database record creation
* File uploads
* User success feedback

***

## 10. Admin Dashboard

### 10.1 Route Protection

**File**: `src/components/admin/ProtectedRoute.tsx`

Logic (stepper):

{% stepper %}
{% step %}

1. Check `AuthContext` loading state.
   {% endstep %}

{% step %}
2\. If loading > 200ms, show skeleton/loading UI.
{% endstep %}

{% step %}
3\. If not loading and no user, redirect to `/admin/login`.
{% endstep %}

{% step %}
4\. If `requireAdmin` prop is true and `!isAdmin`, show "Access Denied".
{% endstep %}

{% step %}
5\. Otherwise, render children.
{% endstep %}
{% endstepper %}

### 10.2 Authentication Flow

**File**: `src/contexts/AuthContext.tsx`

Flow (stepper):

{% stepper %}
{% step %}

1. On mount: `supabase.auth.getSession()` to initialize session.
   {% endstep %}

{% step %}
2\. Listen to `onAuthStateChange()` for auth updates.
{% endstep %}

{% step %}
3\. On user change: call `checkAdminStatus(userId)` which queries `profiles` table for `is_admin` flag.
{% endstep %}

{% step %}
4\. Expose context values: `user`, `session`, `isAdmin`, `signIn`, `signOut`.
{% endstep %}
{% endstepper %}

### 10.3 Lead Data Access

**AdminLeads.tsx**:

```javascript
const { data, error } = await supabase
  .from('leads')
  .select('*')
  .order('created_at', { ascending: false });
```

**File Attachment Access**:

```javascript
const { data: uploads } = await supabase
  .from('leads_uploads')
  .select('*')
  .eq('lead_id', leadId);
```

### 10.4 Export Features

| Format | Library |
| ------ | ------- |
| PDF    | jsPDF   |
| CSV    | XLSX    |
| Excel  | XLSX    |

***

## 11. JSON-Driven Content

### 11.1 Team Page

**File**: `src/data/team.json`

**Structure**:

```json
[
  {
    "slug": "eliud-khayo",
    "name": "Eliud Khayo",
    "title": "Co-Founder & CEO",
    "photo": "/Eliud-Khayo.jpg",
    "expertise": "Health Economics",
    "summary": "...",
    "education": [{ "degree": "...", "description": "..." }],
    "competencies": ["..."],
    "contributions": ["..."],
    "projects": [{ "title": "...", "year": "...", "slug": "...", "impact": "..." }],
    "linkedin": "...",
    "cv": "..."
  }
]
```

**Rendering**:

```tsx
import rawTeamData from "@/data/team.json";
const teamData = rawTeamData as TeamMember[];
// TeamGrid component maps over teamData
```

### 11.2 Services Page

**File**: `src/data/services.json`

**Structure**:

```json
{
  "services": [
    {
      "id": "health-systems-strengthening",
      "slug": "health-systems-strengthening",
      "title": "Health Systems Strengthening",
      "overview": "...",
      "description": "...",
      "challenge": ["..."],
      "approach": ["..."],
      "outcomes": ["..."],
      "miniServices": ["..."],
      "keywords": ["..."],
      "testimonials": [{ "text": "...", "author": "...", "organization": "..." }],
      "metrics": { "value": "28%", "description": "..." }
    }
  ]
}
```

### 11.3 Projects Page

**File**: `src/data/projects.json`

**Rendering**:

```tsx
import projectsData from "@/data/projects.json";
const featuredProjects = projectsData.projects.filter(p => p.featured);
```

### 11.4 About Page

**File**: `src/data/about.json`

Contains: hero content, whoWeAre paragraphs, values, approach steps, qualityAssurance, carousel slides.

### 11.5 Benefits of JSON-Driven Content

* No database dependency for static content
* Version controlled content changes
* Fast build-time imports
* Easy content updates without code changes
* Type-safe with TypeScript interfaces

***

## 12. Routing and Access Control

### 12.1 Route Definitions

**File**: `src/App.tsx`

```tsx
// Public Routes
} />
} />
} />
} />
} />
} />
} />
} />
} />
} />

// Admin Routes (Protected)
} />
} />
} />
} />
} />
} />

// Catch-all
} />
```

### 12.2 Authentication Checks

* `ProtectedRoute` wraps admin pages
* `requireAdmin` prop enforces `is_admin` flag check
* Unauthenticated users redirect to `/admin/login`
* Non-admin authenticated users see "Access Denied"

### 12.3 Redirect Behavior

| Condition                      | Behavior                     |
| ------------------------------ | ---------------------------- |
| Unauthenticated + admin route  | Redirect to /admin/login     |
| Authenticated + /admin/login   | Redirect to /admin/dashboard |
| Not admin + requireAdmin route | Show "Access Denied"         |

***

## 13. Environment Configuration

### 13.1 Frontend Variables (Vite)

| Variable                       | Purpose                 |
| ------------------------------ | ----------------------- |
| VITE\_SUPABASE\_URL            | Supabase project URL    |
| VITE\_SUPABASE\_ANON\_KEY      | Public anonymous key    |
| VITE\_SUPABASE\_FUNCTIONS\_URL | Edge functions base URL |

**Usage**: `import.meta.env.VITE_SUPABASE_URL`

### 13.2 Backend Secrets (Edge Functions)

| Variable                     | Purpose                        |
| ---------------------------- | ------------------------------ |
| SUPABASE\_URL                | Auto-injected Supabase URL     |
| SUPABASE\_SERVICE\_ROLE\_KEY | Auto-injected service role key |
| RAILWAY\_WEBHOOK\_URL        | n8n email webhook endpoint     |

**Usage**: `Deno.env.get("RAILWAY_WEBHOOK_URL")`

### 13.3 Client Configuration

**File**: `src/integrations/supabase/client.ts`

```typescript
const SUPABASE_URL = "https://tfqwiwdjjflzezzrxqbn.supabase.co";
const SUPABASE_PUBLISHABLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";

export const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, {
  auth: {
    storage: localStorage,
    persistSession: true,
    autoRefreshToken: true,
  }
});
```

***

## 14. Error Handling and UX Safeguards

### 14.1 Client-Side Validation

* Per-step validation in ContactWizard
* Email regex validation
* Required field checks
* Inline error messages

### 14.2 Backend Error Handling

```typescript
// Supabase query pattern
const { data, error } = await supabase.from('leads').insert([leadData]);
if (error) {
  console.error("Supabase insert error:", error);
  toast.error("Failed to save request. Please try again.");
  return;
}
```

### 14.3 Graceful Failure Strategies

* File upload failures don't block form submission
* Email failures are logged but silent to user
* Network errors show retry-friendly messages
* 404 pages for missing resources/team members

### 14.4 User Feedback Mechanisms

| Scenario       | Feedback                    |
| -------------- | --------------------------- |
| Form success   | Toast + success modal       |
| Form error     | Toast with error message    |
| Loading states | Spinner animations          |
| Empty states   | "No results found" messages |

***

## 15. Maintenance and Extensibility

### 15.1 Adding New Pages

1. Create page component in `src/pages/`
2. Add route in `App.tsx`
3. Add to navigation in `Navbar.tsx` and `Footer.tsx`
4. Include SEO metadata with react-helmet-async

### 15.2 Adding New Services

1. Add entry to `src/data/services.json`
2. ServiceDetail page auto-renders based on slug
3. Update Navbar dropdown if needed

### 15.3 Extending Contact Wizard

1. Create new step component in `src/components/contact/steps/`
2. Add to step renderer in ContactWizard
3. Update `totalSteps` constant
4. Add validation logic to `isStepValid()`
5. Update `FormData` interface

### 15.4 Updating JSON Content

1. Edit relevant JSON file in `src/data/`
2. TypeScript will catch schema mismatches
3. Changes take effect on next build/deploy

### 15.5 Adding Database Tables

1. Create migration in `supabase/migrations/`
2. Update TypeScript types in `src/integrations/supabase/types.ts`
3. Add RLS policies for security
4. Test locally before deploying

### 15.6 Code Quality Guidelines

* Run `npm run lint` before committing
* Run `npm run typecheck` for type safety
* Follow existing component patterns
* Use shadcn/ui components when possible
* Keep components under 300 lines

***

## Appendix A: Key File Reference

<table><thead><tr><th width="153.66156005859375">Purpose</th><th width="362.99993896484375">File</th></tr></thead><tbody><tr><td>Route definitions and provider setup</td><td><code>src/App.tsx</code></td></tr><tr><td>Authentication state management</td><td><code>src/contexts/AuthContext.tsx</code></td></tr><tr><td>Supabase client configuration</td><td><code>src/integrations/supabase/client.ts</code></td></tr><tr><td>Database TypeScript types</td><td><code>src/integrations/supabase/types.ts</code></td></tr><tr><td>Multi-step form logic</td><td><code>src/components/contact/ContactWizard.tsx</code></td></tr><tr><td>Route protection HOC</td><td><code>src/components/admin/ProtectedRoute.tsx</code></td></tr><tr><td>Design system and global styles</td><td><code>src/index.css</code></td></tr><tr><td>Tailwind configuration</td><td><code>tailwind.config.ts</code></td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.lesarconsults.org/lesar-consults-website-technical-documentation-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
