> ## Documentation Index
> Fetch the complete documentation index at: https://dos.dzaleka.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Platform Overview

> Technical architecture, content structure, and deployment details for Dzaleka Online Services

# Platform Overview

Dzaleka Online Services is built on a modern, scalable architecture designed to serve the refugee community efficiently while remaining maintainable by non-technical contributors.

## Architecture Overview

### Technology Stack

<CardGroup cols={2}>
  <Card title="Astro 5.x" icon="rocket">
    Static site generator with partial hydration for optimal performance
  </Card>

  <Card title="React 18" icon="react">
    Interactive components for dynamic functionality
  </Card>

  <Card title="Tailwind CSS" icon="palette">
    Utility-first CSS framework with custom design system
  </Card>

  <Card title="MDX" icon="markdown">
    Markdown with JSX for content authoring
  </Card>
</CardGroup>

### Core Dependencies

```json theme={null}
{
  "dependencies": {
    "astro": "^5.16.6",
    "@astrojs/react": "^4.4.2",
    "@astrojs/tailwind": "^6.0.2",
    "@astrojs/mdx": "^4.3.13",
    "@astrojs/netlify": "^6.6.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tailwindcss": "^3.3.3",
    "zod": "^3.22.2",
    "minisearch": "^7.1.1",
    "leaflet": "^1.9.4",
    "date-fns": "^2.30.0",
    "alpinejs": "^3.13.3"
  }
}
```

## Project Structure

```plaintext theme={null}
dzaleka-online-services/
├── src/
│   ├── components/          # Reusable UI components
│   │   ├── ui/             # Base UI components (Button, Card, etc.)
│   │   ├── Header.astro    # Site header
│   │   ├── Footer.astro    # Site footer
│   │   └── ...             # Feature-specific components
│   ├── content/            # Content collections (MDX files)
│   │   ├── services/       # Service directory entries
│   │   ├── events/         # Event listings
│   │   ├── jobs/           # Job postings
│   │   ├── resources/      # Resource library
│   │   ├── news/           # News and announcements
│   │   ├── photos/         # Photo gallery
│   │   ├── stories/        # Community stories
│   │   ├── artists/        # Artist profiles
│   │   ├── dancers/        # Dancer profiles
│   │   ├── poets/          # Poet profiles
│   │   ├── marketplace/    # Marketplace listings
│   │   ├── stores/         # Store profiles
│   │   └── ...             # Additional collections
│   ├── layouts/            # Page layouts
│   │   ├── MainLayout.astro      # Main site layout
│   │   ├── DocsLayout.astro      # Documentation layout
│   │   ├── ServiceLayout.astro   # Service page layout
│   │   └── ...                   # Other layouts
│   ├── pages/              # Route pages
│   │   ├── index.astro           # Homepage
│   │   ├── services/             # Services pages
│   │   ├── events/               # Events pages
│   │   ├── jobs/                 # Jobs pages
│   │   ├── api/                  # API endpoints
│   │   └── ...                   # Other pages
│   ├── styles/             # Global styles
│   ├── utils/              # Utility functions
│   ├── types/              # TypeScript types
│   ├── data/               # Static data files
│   └── content.config.ts   # Content collection schemas
├── public/                 # Static assets
│   ├── images/            # Image files
│   └── ...                # Other static files
├── astro.config.mjs       # Astro configuration
├── tailwind.config.cjs    # Tailwind configuration
├── tsconfig.json          # TypeScript configuration
└── netlify.toml           # Netlify deployment config
```

## Content Collections Architecture

### Content Collection Definition

Content is managed through Astro's Content Collections with Zod schemas for type safety:

```typescript theme={null}
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

// Service schema
const serviceSchema = z.object({
  title: z.string(),
  description: z.string(),
  category: z.string(),
  featured: z.boolean().optional(),
  verified: z.boolean().optional(),
  logo: z.string().optional(),
  image: z.string().optional(),
  contact: z.object({
    email: z.string().optional(),
    phone: z.string().optional(),
    whatsapp: z.string().optional(),
    hours: z.string().optional(),
  }).optional(),
  location: z.object({
    address: z.string(),
    city: z.string(),
    coordinates: z.object({
      lat: z.number(),
      lng: z.number(),
    }).optional(),
  }).optional(),
  socialMedia: z.object({
    website: z.string().optional(),
    facebook: z.string().optional(),
    instagram: z.string().optional(),
    twitter: z.string().optional(),
    linkedin: z.string().optional(),
  }).optional(),
  tags: z.array(z.string()).optional(),
  lastUpdated: z.date().optional(),
  status: z.enum(['active', 'inactive']).optional().default('active'),
});

const servicesCollection = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/content/services" }),
  schema: serviceSchema,
});

export const collections = {
  services: servicesCollection,
  // ... other collections
};
```

### Content Collections Overview

<Note>
  All content collections use the same pattern: Markdown files with frontmatter validated by Zod schemas.
</Note>

| Collection      | Schema Key Features                      | Example Fields                                               |
| --------------- | ---------------------------------------- | ------------------------------------------------------------ |
| **services**    | Contact info, location, verification     | `title`, `category`, `contact`, `location`, `verified`       |
| **events**      | Date, organizer, panelists, registration | `date`, `location`, `organizer`, `panelists`, `registration` |
| **jobs**        | Job type, skills, deadline, contact      | `type`, `category`, `skills`, `deadline`, `salary`           |
| **resources**   | File metadata, languages, downloads      | `fileType`, `fileSize`, `languages`, `downloadUrl`           |
| **news**        | Category, author, business info          | `category`, `author`, `businessName`, `tags`                 |
| **photos**      | Photographer, date, gallery              | `photographer`, `date`, `tags`, `gallery`                    |
| **marketplace** | Vendor, price, delivery                  | `vendor`, `price`, `priceType`, `deliveryOptions`            |
| **stores**      | Menu, hours, payment methods             | `type`, `menu`, `hours`, `paymentMethods`                    |

### Example Content File

```markdown theme={null}
---
title: BloomBox Design Labs
category: "Education"
description: BloomBox Design Labs is dedicated to the application of sustainable design strategies...
location:
  address: BloomBox, Dzaleka, M16
  city: Dowa
  coordinates:
    lat: -13.6628274
    lng: 33.8704301
contact:
  email: ''
  phone: '+1 236-888-5055'
  hours: 'Monday-Friday, 9:00 AM - 5:00 PM'
socialMedia:
  twitter: 'https://x.com/roux_sofie'
  instagram: 'https://www.instagram.com/bloomboxdesignlabs/'
  website: 'https://www.bloomboxdesignlabs.com/'
featured: true
verified: true
lastUpdated: 2025-03-06
---

## About BloomBox Design Labs

BloomBox Design Labs specializes in design thinking, architecture, and capacity building...
```

## API Architecture

### API Endpoints

The platform provides RESTful API endpoints using Astro's API routes:

```typescript theme={null}
// src/pages/api/events.ts
import type { APIRoute } from 'astro';
import { createGetHandler, createOptionsHandler, createPostHandler } from '../../utils/api-utils';

export const GET: APIRoute = createGetHandler('events');
export const OPTIONS: APIRoute = createOptionsHandler();
export const POST: APIRoute = createPostHandler('events');
```

### API Utilities

```typescript theme={null}
// src/utils/api-utils.ts
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';

export const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
  'Content-Type': 'application/json'
};

// Rate limiting: 60 requests per minute
const RATE_LIMIT_WINDOW = 60 * 1000;
const MAX_REQUESTS_PER_WINDOW = 60;

export function createGetHandler(collectionName: string): APIRoute {
  return async ({ request }) => {
    try {
      const collection = await getCollection(collectionName);
      const processedData = processCollectionData(collection, collectionName);
      
      return new Response(
        JSON.stringify({
          status: 'success',
          count: processedData.length,
          data: { [collectionName]: processedData }
        }),
        { status: 200, headers: corsHeaders }
      );
    } catch (error) {
      return new Response(
        JSON.stringify({
          status: 'error',
          message: `Failed to fetch ${collectionName}`
        }),
        { status: 500, headers: corsHeaders }
      );
    }
  };
}
```

### Available API Endpoints

<CardGroup cols={2}>
  <Card title="/api/services" icon="building">
    GET all services with filtering options
  </Card>

  <Card title="/api/events" icon="calendar">
    GET events with date filtering
  </Card>

  <Card title="/api/jobs" icon="briefcase">
    GET job listings with status filters
  </Card>

  <Card title="/api/resources" icon="book">
    GET resources with category filters
  </Card>

  <Card title="/api/news" icon="newspaper">
    GET news and announcements
  </Card>

  <Card title="/api/photos" icon="camera">
    GET photo gallery metadata
  </Card>
</CardGroup>

### API Response Format

```json theme={null}
{
  "status": "success",
  "count": 42,
  "data": {
    "events": [
      {
        "id": "breaking-myths-about-refugees",
        "collection": "events",
        "title": "Breaking Myths About Refugees",
        "date": "2025-04-15T00:00:00.000Z",
        "location": "Dzaleka Community Center",
        "category": "Educational",
        "organizer": "Dzaleka Connect",
        "status": "upcoming"
      }
    ]
  }
}
```

## Design System

### Tailwind Configuration

```javascript theme={null}
// tailwind.config.cjs
module.exports = {
  content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          // ... full color scale
        },
        sand: {
          50: '#faf9f7',
          100: '#f5f3f0',
          // ... earth tones
        },
        terracotta: {
          // ... warm accent colors
        },
        earth: {
          // ... natural tones
        },
        ochre: {
          // ... golden yellows
        },
        vibrant: {
          // ... bright accents
        }
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
    },
  },
  plugins: [
    require('@tailwindcss/typography'),
    require('@tailwindcss/forms'),
    require('@tailwindcss/aspect-ratio'),
  ],
};
```

### Component Library

#### Base UI Components

```astro theme={null}
<!-- src/components/ui/Button.astro -->
---
interface Props {
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'sm' | 'md' | 'lg';
  href?: string;
}

const { variant = 'primary', size = 'md', href } = Astro.props;
---

<a href={href} class="btn btn-{variant} btn-{size}">
  <slot />
</a>
```

#### Feature Components

* **Header**: Site navigation with mobile menu
* **Footer**: Links, contact info, social media
* **ServiceCard**: Display service information
* **EventCard**: Show event details with date badges
* **JobCard**: Job listing with metadata
* **SearchBar**: Real-time search with MiniSearch
* **Pagination**: Navigate through content pages
* **CategoryFilter**: Filter content by categories

## Search Implementation

### MiniSearch Integration

```typescript theme={null}
// Search index generation
import MiniSearch from 'minisearch';

const miniSearch = new MiniSearch({
  fields: ['title', 'description', 'category', 'tags'],
  storeFields: ['title', 'description', 'category', 'id'],
  searchOptions: {
    boost: { title: 2 },
    fuzzy: 0.2,
    prefix: true
  }
});

// Add documents from all collections
const services = await getCollection('services');
const events = await getCollection('events');
const jobs = await getCollection('jobs');

miniSearch.addAll([
  ...services.map(s => ({ id: s.id, ...s.data, type: 'service' })),
  ...events.map(e => ({ id: e.id, ...e.data, type: 'event' })),
  ...jobs.map(j => ({ id: j.id, ...j.data, type: 'job' }))
]);

// Search
const results = miniSearch.search('education', { fuzzy: 0.2 });
```

## Deployment Architecture

### Netlify Configuration

```toml theme={null}
# netlify.toml
[build]
  publish = "dist"
  command = "npm run build"

[functions]
  directory = "netlify/functions"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

[[headers]]
  for = "/api/*"
  [headers.values]
    Access-Control-Allow-Origin = "*"
    Access-Control-Allow-Methods = "GET, POST, OPTIONS"
    Access-Control-Allow-Headers = "Content-Type"

[build.environment]
  NODE_VERSION = "20"
```

### Build Process

<Steps>
  <Step title="Content Processing">
    Astro loads all MDX files from content collections and validates them against Zod schemas
  </Step>

  <Step title="Static Generation">
    Pages are pre-rendered to static HTML with minimal JavaScript
  </Step>

  <Step title="Asset Optimization">
    Images are optimized, CSS is minified, JavaScript is bundled
  </Step>

  <Step title="API Routes">
    Serverless functions are generated for API endpoints
  </Step>

  <Step title="Deployment">
    Static files are deployed to Netlify CDN, functions to AWS Lambda
  </Step>
</Steps>

### Performance Optimizations

* **Partial Hydration**: Only interactive components load JavaScript
* **Image Optimization**: Automatic responsive images with lazy loading
* **Code Splitting**: Per-page JavaScript bundles
* **CDN Caching**: Static assets cached globally
* **Prerendering**: Most pages generated at build time

## Data Flow

```mermaid theme={null}
graph TD
    A[Content Authors] -->|Write MDX| B[Content Collections]
    B -->|Validated by| C[Zod Schemas]
    C -->|Loaded by| D[Astro Build]
    D -->|Generates| E[Static HTML]
    D -->|Creates| F[API Endpoints]
    E -->|Deployed to| G[Netlify CDN]
    F -->|Deployed to| H[Serverless Functions]
    I[Users] -->|Request| G
    I -->|API Call| H
```

## Content Management Workflow

<Steps>
  <Step title="Content Creation">
    Authors create/edit MDX files in `src/content/` directories
  </Step>

  <Step title="Schema Validation">
    Frontmatter is validated against Zod schemas during development
  </Step>

  <Step title="Local Preview">
    Changes are visible immediately in development server
  </Step>

  <Step title="Git Commit">
    Content is committed to Git repository
  </Step>

  <Step title="Automated Build">
    Netlify detects changes and triggers build process
  </Step>

  <Step title="Deploy">
    New version is deployed to production automatically
  </Step>
</Steps>

## Security Features

### API Security

* **Rate Limiting**: 60 requests per minute per IP
* **CORS Headers**: Configured for safe cross-origin access
* **Input Validation**: All API inputs validated with Zod
* **Error Handling**: Safe error messages without exposing internals

### Content Security

* **Schema Validation**: All content validated before build
* **Sanitization**: HTML and user inputs sanitized
* **HTTPS Only**: All connections encrypted
* **CSP Headers**: Content Security Policy headers configured

## Monitoring & Analytics

### Built-in Analytics

```astro theme={null}
<!-- src/pages/analytics.astro -->
---
import { getCollection } from 'astro:content';

const services = await getCollection('services');
const events = await getCollection('events');
const jobs = await getCollection('jobs');

const stats = {
  totalServices: services.length,
  totalEvents: events.length,
  totalJobs: jobs.filter(j => j.data.status === 'open').length,
  // ... more statistics
};
---
```

### Metrics Tracked

* Total content items by collection
* Active vs inactive services
* Open vs closed job postings
* Upcoming vs past events
* Featured content counts
* API usage statistics

## Development Setup

### Local Development

```bash theme={null}
# Clone repository
git clone https://github.com/your-org/dzaleka-online-services.git
cd dzaleka-online-services

# Install dependencies
npm install

# Start development server
npm run dev
# Server runs at http://localhost:4321

# Build for production
npm run build

# Preview production build
npm run preview
```

### Environment Variables

```env theme={null}
# .env
PUBLIC_SITE_URL=https://services.dzaleka.com
FORMSPREE_ENDPOINT=https://formspree.io/f/your-form-id
RESEND_API_KEY=your-resend-api-key
```

## Extending the Platform

### Adding a New Content Collection

<Steps>
  <Step title="Define Schema">
    Add schema to `src/content.config.ts`:

    ```typescript theme={null}
    const myCollectionSchema = z.object({
      title: z.string(),
      description: z.string(),
      // ... other fields
    });
    ```
  </Step>

  <Step title="Create Collection">
    ```typescript theme={null}
    const myCollection = defineCollection({
      loader: glob({ pattern: "**/*.md", base: "./src/content/mycollection" }),
      schema: myCollectionSchema,
    });
    ```
  </Step>

  <Step title="Export Collection">
    ```typescript theme={null}
    export const collections = {
      mycollection: myCollection,
      // ... existing collections
    };
    ```
  </Step>

  <Step title="Create Content Directory">
    Create `src/content/mycollection/` directory
  </Step>

  <Step title="Add Pages">
    Create listing and detail pages in `src/pages/mycollection/`
  </Step>
</Steps>

### Adding a New API Endpoint

```typescript theme={null}
// src/pages/api/mycollection.ts
import type { APIRoute } from 'astro';
import { createGetHandler, createOptionsHandler } from '../../utils/api-utils';

export const GET: APIRoute = createGetHandler('mycollection');
export const OPTIONS: APIRoute = createOptionsHandler();
```

## Best Practices

### Content Authoring

* Use descriptive filenames (lowercase, hyphens for spaces)
* Include all required frontmatter fields
* Optimize images before uploading (max 1MB)
* Use relative paths for internal links
* Test content locally before committing

### Component Development

* Keep components small and focused
* Use TypeScript for type safety
* Follow Astro's component patterns
* Minimize client-side JavaScript
* Use semantic HTML

### Performance

* Lazy load images and heavy components
* Minimize bundle sizes
* Use partial hydration strategically
* Optimize database queries in API routes
* Cache API responses when appropriate

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion title="Build fails with schema validation error">
    Check that all MDX files have required frontmatter fields and correct data types. Review `src/content.config.ts` for schema requirements.
  </Accordion>

  <Accordion title="API returns 429 rate limit error">
    You've exceeded 60 requests per minute. Wait for the rate limit window to reset or implement request throttling.
  </Accordion>

  <Accordion title="Images not loading">
    Ensure images are in the `public/images/` directory and paths start with `/images/`. Check file permissions and extensions.
  </Accordion>

  <Accordion title="Search not returning results">
    Verify search index is built correctly. Check that documents have searchable fields (title, description, tags).
  </Accordion>
</AccordionGroup>

## Resources

<CardGroup cols={2}>
  <Card title="Astro Documentation" icon="book" href="https://docs.astro.build">
    Official Astro framework documentation
  </Card>

  <Card title="Tailwind CSS" icon="palette" href="https://tailwindcss.com">
    Tailwind CSS documentation and guides
  </Card>

  <Card title="MDX" icon="markdown" href="https://mdxjs.com">
    MDX syntax and component usage
  </Card>

  <Card title="Netlify Docs" icon="cloud" href="https://docs.netlify.com">
    Netlify deployment and configuration
  </Card>
</CardGroup>

***

*For technical support or questions, contact the development team at [dzalekaconnect@gmail.com](mailto:dzalekaconnect@gmail.com)*
