Skip to main content

System Architecture

Concordia is built as a server-side rendered (SSR) web application using modern web technologies. This document provides an overview of the system architecture, domain model, and core technical layers.

High-Level Architecture

Concordia follows a layered architecture pattern with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│                    Presentation Layer                       │
│                  (Astro SSR + Components)                   │
├─────────────────────────────────────────────────────────────┤
│                     Application Layer                       │
│              (Actions, API Routes, Loaders)                 │
├─────────────────────────────────────────────────────────────┤
│                      Domain Layer                           │
│        (Business Logic, Services, Permissions)              │
├─────────────────────────────────────────────────────────────┤
│                    Persistence Layer                        │
│           (Drizzle ORM + PostgreSQL Database)               │
└─────────────────────────────────────────────────────────────┘

SSR Architecture (Astro)

Concordia uses Astro 5.18.0 as its SSR framework, providing:
  • Server-Side Rendering: Pages are rendered on the server for optimal SEO and performance
  • Static Site Generation: Static pages can be pre-rendered at build time
  • API Routes: Server-side API endpoints for data mutations and complex operations
  • File-based Routing: Intuitive page routing based on file structure
  • Component Islands: Interactive client-side components embedded in SSR pages

Request Flow

Client Request

Astro Router

Page Component (.astro)

Data Loader (getDrizzle)

Database Query (Drizzle ORM)

HTML Response (SSR)

Domain Model

The Concordia platform is organized around several core domains:

Core Entities

Authentication & Users
  • user - User accounts (Better Auth)
  • profile - Public user profiles
  • user_role - Role assignments (citizen, owner, author, mediator, admin)
  • organization - Organizational structures
  • member - Organization membership
Content Management
  • blog_posts - Blog articles
  • blog_translations - Multi-language content
  • blog_categories - Content categorization
  • blog_comments - User discussions
  • blog_media - Media assets
Services
  • services_listings - Service offerings
  • services_bookings - Reservations
  • services_availability - Time slots
  • services_reviews - User ratings
  • services_categories - Service taxonomy
Platform Features
  • notification - User notifications
  • audit_log - System audit trail

Entity Relationships

user (1) ──→ (N) profile
     (1) ──→ (N) user_role
     (1) ──→ (N) blog_posts (as author)
     (1) ──→ (N) blog_comments
     (1) ──→ (N) services_bookings
     (1) ──→ (N) services_reviews

blog_posts (1) ──→ (N) blog_translations
           (1) ──→ (N) blog_comments
           (N) ──→ (N) blog_categories
           (N) ──→ (N) blog_media

services_listings (1) ──→ (N) services_translations
                  (1) ──→ (N) services_bookings
                  (1) ──→ (N) services_availability
                  (1) ──→ (N) services_reviews

Database Layer

Drizzle ORM + PostgreSQL

Concordia uses Drizzle ORM 0.45.1 with PostgreSQL (via pg 8.18.0) for data persistence. Key Features:
  • Type-safe database queries
  • Schema-first approach with TypeScript definitions
  • Migration management
  • Connection pooling
  • Multi-environment support (local, test, production)
Database Configuration (src/database/drizzle.ts):
// Dynamic database selection based on environment
if (process.env.USE_PROD_DB === 'true') {
  url = process.env.DATABASE_URL_PROD;
} else if (process.env.USE_DB_TEST === 'true') {
  url = process.env.DATABASE_URL_TEST;
} else {
  url = process.env.DATABASE_URL_LOCAL;
}

// Connection pooling
const pool = new Pool({
  connectionString: url,
  ssl: url.includes('sslmode=require') ? { rejectUnauthorized: false } : undefined,
  max: 5,
  idleTimeoutMillis: 10000,
});

const db = drizzle(pool, { schema });
Schema Organization:
  • Schemas defined in /src/database/schemas/
  • One schema file per domain entity
  • Centralized exports via schemas.ts
  • Migrations stored in /src/database/migrations/

Authentication Layer

Concordia uses Better Auth 1.4.18 for authentication and authorization.

Features

  • Multiple Authentication Methods:
    • Email/password with verification
    • OAuth providers (configurable)
    • Magic link authentication
  • Session Management:
    • Secure session tokens
    • Session persistence
    • Automatic session refresh
  • Role-Based Access Control (RBAC):
    • Multiple roles per user
    • Granular permissions
    • Organization-level access control
  • Security Features:
    • Rate limiting
    • CSRF protection
    • Password hashing (bcrypt)
    • Email verification

Authentication Schema

Better Auth provides the following core tables:
  • user - User accounts
  • session - Active sessions
  • account - OAuth provider links
  • verification - Email verification tokens
  • rate_limit - Rate limiting counters
  • invitation - Organization invitations

Authorization Model

Roles are managed via the user_role table:
enum app_role {
  citizen      // Default user
  owner        // Business owner
  author       // Content creator
  mediator     // Conflict mediator
  educator     // Education module manager
  moderator    // Content moderator
  admin        // Platform administrator
}
Permissions are checked via:
  • Middleware for route protection
  • Action-level authorization
  • Row-level security policies (RLS)

Multi-Language Routing

Concordia supports 4 locales: French (fr), English (en), Arabic (ar), Spanish (es).

URL Structure

/{lang}/                 - Homepage
/{lang}/blog/            - Blog listing
/{lang}/blog/{slug}      - Blog post
/{lang}/services/        - Services listing
/{lang}/auth/sign-in     - Authentication

Implementation

  • Route Pattern: /[lang]/... dynamic parameter
  • Locale Detection: Browser preferences, URL parameter, user profile
  • Content Translation:
    • UI translations: /src/i18n/ JSON files
    • Database translations: *_translations tables
  • Locale Helper: locale-url.ts for URL generation

Translation Tables

Content with translations:
  • blog_translations - Blog post content
  • services_translations - Service descriptions
  • Future: place_translation, article_content

Key Architectural Patterns

1. Server Actions

Server actions encapsulate business logic:
// src/actions/blog.ts
export const actions = {
  createPost: async (data) => {
    // Validate permissions
    // Validate data
    // Perform database operations
    // Return result
  }
}

2. Data Loaders

Loaders fetch data for page rendering:
// src/database/loaders/blog.ts
export async function loadBlogPost(slug: string, lang: string) {
  const db = await getDrizzle();
  return await db.query.blogPosts.findFirst({
    where: eq(blogPosts.slug, slug),
    with: {
      translations: { where: eq(translations.language, lang) },
      author: true,
      categories: true
    }
  });
}

3. Component Modules

Components organized by domain:
src/components/
  modules/
    blog/
      cards/      - PostCard, AuthorCard
      lists/      - PostGrid, FeaturedGrid
      single/     - PostHeader, PostContent
      ui/         - CategoryBadge, ShareButtons
    services/
      cards/      - ServiceCard
      single/     - ServiceHeader, ServiceBooking

4. Type Safety

End-to-end type safety:
  • Database schema → TypeScript types (Drizzle)
  • API contracts with typed responses
  • Component props with TypeScript interfaces

Performance Optimizations

  • Connection Pooling: Reused database connections (max: 5)
  • Cached Drizzle Instance: Single database client per process
  • SSR Caching: Static page generation where appropriate
  • Image Optimization: Astro’s built-in image optimization
  • Lazy Loading: Dynamic imports for large components

Security Architecture

  • Input Validation: Server-side validation for all inputs
  • SQL Injection Prevention: Parameterized queries via Drizzle ORM
  • XSS Protection: Automatic escaping in Astro templates
  • CSRF Protection: Built into Better Auth
  • Rate Limiting: Request throttling per user/IP
  • Audit Logging: All admin actions logged to audit_log

Deployment Architecture

Concordia supports multiple deployment targets:
  • Node.js: Full SSR with @astrojs/node adapter
  • Vercel: Optimized for Vercel platform with @astrojs/vercel
  • Static: Pre-rendered static site for CDN deployment

Environment Configuration

DATABASE_URL_LOCAL=postgresql://...
DATABASE_URL_TEST=postgresql://...
DATABASE_URL_PROD=postgresql://...
USE_PROD_DB=false
USE_DB_TEST=false

Next Steps