Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ashcroft08/provesa-web/llms.txt

Use this file to discover all available pages before exploring further.

Overview

PROVESA Web is built as a modern, full-stack web application using SvelteKit with a clean, layered architecture that emphasizes separation of concerns, maintainability, and scalability.

Technology Stack

Frontend

  • SvelteKit - Full-stack framework with file-based routing
  • Svelte - Reactive component framework
  • Tailwind CSS - Utility-first CSS framework
  • Dynamic Theming - CSS variables for real-time color customization

Backend

  • SvelteKit Server - Server-side rendering and API routes
  • Drizzle ORM - TypeScript ORM for database operations
  • PostgreSQL - Primary database
  • Better Auth - Authentication and session management
  • Cloudinary - Image upload and management

Architectural Patterns

Layered Architecture

The application follows a strict three-layer architecture:
┌─────────────────────────────────────┐
│         Routes Layer                │
│  (+page.svelte, +page.server.js)   │
│  - User interface                   │
│  - Form actions                     │
│  - Data loading                     │
└──────────────┬──────────────────────┘

┌──────────────▼──────────────────────┐
│        Services Layer               │
│     (src/lib/server/services/)      │
│  - Business logic                   │
│  - Data transformation              │
│  - File upload handling             │
│  - Validation                       │
└──────────────┬──────────────────────┘

┌──────────────▼──────────────────────┐
│      Repositories Layer             │
│   (src/lib/server/repositories/)    │
│  - Database queries                 │
│  - CRUD operations                  │
│  - Data access abstraction          │
└──────────────┬──────────────────────┘

┌──────────────▼──────────────────────┐
│         Database Layer              │
│      (PostgreSQL + Drizzle)         │
│  - Schema definitions               │
│  - Relations                        │
│  - Type safety                      │
└─────────────────────────────────────┘

Key Principles

1. Separation of Concerns

Each layer has a specific responsibility:
  • Routes handle HTTP requests/responses and user interactions
  • Services contain business logic and orchestrate operations
  • Repositories abstract database access
  • Schemas define data structure

2. Dependency Flow

Data flows unidirectionally:
RouteServiceRepositoryDatabase
Example from /src/routes/admin/+page.server.js:24:
productsService.getAllProducts()
Which calls /src/lib/server/services/products.service.js:5:
async getAllProducts() {
    return await productsRepository.getAll();
}
Which executes /src/lib/server/repositories/products.repository.js:7:
async getAll() {
    return await db.select().from(products).orderBy(asc(products.sortOrder));
}

3. Single Responsibility

Each service/repository handles one domain:
  • products.service.js - Product management
  • concursos.service.js - Contest management
  • footer.service.js - Footer configuration
  • auth.js - Authentication

4. Type Safety

Drizzle ORM provides end-to-end type safety:
// Schema defines types
export const products = pgTable('products', {
    id: serial('id').primaryKey(),
    name: text('name').notNull().default(''),
    // ...
});

// Types flow through repository → service → route

Authentication & Authorization

Better Auth Integration

Authentication is handled via Better Auth with session-based security:
  1. Session Hook (/src/hooks.server.js:5):
const session = await auth.api.getSession({ headers: event.request.headers });
if (session) {
    event.locals.session = session.session;
    event.locals.user = session.user;
}
  1. Protected Routes:
export const load = async (event) => {
    if (!event.locals.session) {
        throw redirect(302, '/login');
    }
    // ...
};
  1. User Schema (/src/lib/server/db/schemas/auth.schema.js):
  • user - User accounts
  • session - Active sessions
  • account - OAuth providers and credentials
  • verification - Email verification tokens

Data Management

Database Access Pattern

All database operations use Drizzle ORM:
// src/lib/server/db/index.js
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';

const client = postgres(env.DATABASE_URL);
export const db = drizzle(client, { schema });

Schema Organization

Schemas are modular and exported from a central location:
// src/lib/server/db/schema.js
export * from './schemas/auth.schema';
export * from './schemas/products.schema';
export * from './schemas/concursos.schema';
// ...

File Upload Strategy

Cloudinary Integration

Image uploads are handled through a dedicated repository:
// Services handle file validation
const imageFile = formData.get('image');
if (imageFile && imageFile.size > 0) {
    const result = await uploadRepository.uploadImage(imageFile, {
        folder: 'provesa/concursos'
    });
    imageUrl = result.secure_url;
}
Benefits:
  • Centralized upload logic
  • Automatic optimization
  • CDN distribution
  • Organized folder structure

Configuration Management

Dynamic Configuration

Several aspects of the site are dynamically configurable:
  1. Theme Colors - Stored in CSS file, managed via service
  2. Site Config - Key-value pairs in database
  3. Feature Toggles - Boolean flags (e.g., isActive on contests)
  4. Singleton Configs - Single-row tables (footer, nosotros)

Environment Variables

import { env } from '$env/dynamic/private';

if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');

Admin Architecture

Admin Panel Structure

The admin panel (/src/routes/admin/) uses:
  • Tab-based UI - Each feature in a separate component
  • Form Actions - SvelteKit actions for CRUD operations
  • Server-side validation - All validation in services
  • Optimistic loading - Parallel data fetching with Promise.all
Example from /src/routes/admin/+page.server.js:19:
const [footer, legal, slides, products, /*...*/] = await Promise.all([
    footerService.getFooterData(),
    legalService.getLegalPages(),
    slidesService.getAllSlides(),
    productsService.getAllProducts(),
    // ...
]);

Public Site Architecture

Homepage Data Loading

The homepage efficiently loads all necessary data in parallel:
// /src/routes/+page.server.js:8
const [slides, productsList, nosotros, sugConfig, footer] = await Promise.all([
    slidesService.getAllSlides(),
    productsService.getAllProducts(),
    nosotrosService.getConfig(),
    sugerenciasService.getConfig(),
    footerRepository.getInfo()
]);

Error Handling

Error handling follows SvelteKit conventions:
try {
    await service.performOperation(data);
    return { success: true };
} catch (e) {
    console.error('Error description:', e);
    return fail(500, { error: 'User-friendly message' });
}

Performance Considerations

Optimization Strategies

  1. Parallel Data Fetching - Use Promise.all() for independent queries
  2. Database Indexing - Indexes on foreign keys and frequently queried fields
  3. Sorted Results - sortOrder field for consistent ordering
  4. Cloudinary CDN - Images served from CDN
  5. Server-side Rendering - SEO-friendly, fast initial load

Best Practices

Code Organization

src/
├── lib/
│   ├── components/          # Reusable UI components
│   │   └── admin/           # Admin-specific components
│   ├── server/              # Server-side code
│   │   ├── db/
│   │   │   ├── schemas/     # Database schemas
│   │   │   ├── seeds/       # Seed data
│   │   │   ├── index.js     # DB connection
│   │   │   └── schema.js    # Schema exports
│   │   ├── services/        # Business logic
│   │   ├── repositories/    # Data access
│   │   ├── auth.js          # Authentication
│   │   └── cloudinary.js    # File uploads
│   └── utils/               # Shared utilities
└── routes/                  # SvelteKit routes
    ├── +layout.server.js    # Root layout
    ├── +page.server.js      # Homepage
    ├── admin/               # Admin panel
    └── [feature]/           # Feature routes

Naming Conventions

  • Services: {domain}.service.js
  • Repositories: {domain}.repository.js
  • Schemas: {domain}.schema.js
  • Components: PascalCase (e.g., ProductSection.svelte)
  • Database Tables: snake_case (e.g., hero_slides)

Next Steps

Build docs developers (and LLMs) love