Skip to main content

Technology Stack

Concordia is built with modern, production-ready technologies carefully selected for performance, developer experience, and maintainability.

Core Framework

Astro 5.18.0

Purpose: Meta-framework for building fast, content-focused websites Why Astro?
  • Zero JavaScript by Default: Ships only the JavaScript you need
  • Server-Side Rendering: Optimal SEO and initial page load
  • Component Islands: Selective hydration for interactivity
  • Framework Agnostic: Can integrate React, Vue, Svelte components
  • File-based Routing: Intuitive URL structure based on file system
  • Built-in Optimizations: Image optimization, CSS minification, asset bundling
Key Features Used:
  • SSR mode for dynamic content
  • MDX support for content-rich pages
  • API routes for server-side operations
  • Content collections for type-safe content
Configuration:
// astro.config.mjs
export default defineConfig({
  output: 'server',
  adapter: node({ mode: 'standalone' }),
  integrations: [mdx()],
});

Authentication & Authorization

Better Auth 1.4.18

Purpose: Modern authentication library for TypeScript Why Better Auth?
  • Type-Safe: Full TypeScript support with inferred types
  • Flexible: Email/password, OAuth, magic links, and more
  • Secure by Default: Built-in CSRF, rate limiting, secure password hashing
  • Multi-tenancy: Organization and member management
  • Database Agnostic: Works with any SQL database via adapters
Features in Use:
  • Email/password authentication with verification
  • Session management with secure cookies
  • Organization and team management
  • Role-based access control (RBAC)
  • Audit logging
  • Rate limiting
  • Account verification workflows
Schema Tables:
  • user - User accounts
  • session - Active sessions
  • account - OAuth provider accounts
  • verification - Email verification tokens
  • organization - Multi-tenant organizations
  • member - Organization membership
  • invitation - Pending organization invitations
  • rate_limit - Rate limiting counters
Integration:
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: 'pg' }),
  emailAndPassword: { enabled: true },
  socialProviders: { /* OAuth config */ },
});

Database & ORM

Drizzle ORM 0.45.1

Purpose: TypeScript ORM for SQL databases Why Drizzle?
  • Type Safety: End-to-end type inference from schema to queries
  • Performance: Lightweight with minimal overhead, no lazy loading traps
  • SQL-like Syntax: Familiar query builder close to raw SQL
  • Schema-first: Define schema in TypeScript, generate migrations
  • Zero Dependencies: Minimal bundle size
  • Great DX: Excellent autocomplete and error messages
Key Features:
  • Declarative schema definitions
  • Automatic type inference
  • Relation queries with eager loading
  • Migration management
  • Query builder with joins, aggregations, subqueries
Example Schema:
export const blogPosts = pgTable('blog_posts', {
  id: uuid('id').defaultRandom().primaryKey(),
  slug: text('slug').notNull().unique(),
  authorId: uuid('author_id').references(() => user.id),
  status: text('status').$type<'draft' | 'published'>().default('draft'),
  createdAt: timestamp('created_at').defaultNow(),
});
Example Query:
const posts = await db.query.blogPosts.findMany({
  where: eq(blogPosts.status, 'published'),
  with: {
    author: true,
    translations: { where: eq(translations.language, 'fr') },
    categories: true,
  },
  orderBy: desc(blogPosts.createdAt),
  limit: 10,
});

PostgreSQL (pg 8.18.0)

Purpose: Relational database driver for Node.js Why PostgreSQL?
  • Reliability: ACID compliant, battle-tested
  • Rich Data Types: JSON, arrays, UUID, full-text search
  • Performance: Advanced indexing, query optimization
  • Extensibility: Custom functions, triggers, extensions
  • Open Source: No vendor lock-in
Features Used:
  • UUID primary keys
  • JSONB for structured data (open_hours, content_json)
  • Arrays for multi-value fields (tags, accessibility)
  • Full-text search capabilities
  • Timestamps with timezone
  • Foreign key constraints
  • Database-level enums
Connection Management:
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false },
  max: 5,
  idleTimeoutMillis: 10000,
});

Content & UI

EasyMDE 2.20.0

Purpose: Simple, embeddable Markdown editor Why EasyMDE?
  • User-Friendly: WYSIWYG-like toolbar for Markdown
  • Customizable: Extensive configuration options
  • Preview Mode: Live Markdown preview
  • Autosave: Built-in draft saving
  • Lightweight: No heavy dependencies
Use Cases:
  • Blog post editing
  • Comment composition
  • Service descriptions
  • Forum posts
Configuration:
const editor = new EasyMDE({
  element: document.getElementById('editor'),
  autosave: { enabled: true, uniqueId: 'blog-post' },
  toolbar: ['bold', 'italic', 'heading', '|', 'quote', 'unordered-list', 'ordered-list', '|', 'link', 'image', '|', 'preview', 'side-by-side', 'fullscreen'],
  spellChecker: false,
});

Markdown-it 14.1.1

Purpose: Markdown parser and renderer Why Markdown-it?
  • Fast: High-performance parsing
  • Extensible: Plugin system for custom syntax
  • Safe: Built-in HTML sanitization
  • CommonMark Compliant: Follows standard specification
Use Cases:
  • Rendering blog post content
  • Comment formatting
  • Documentation pages

Mapping & Geolocation

Leaflet 1.9.4

Purpose: Interactive map library Why Leaflet?
  • Lightweight: ~40KB gzipped
  • Mobile-Friendly: Touch interactions, responsive
  • Extensible: Rich plugin ecosystem
  • Open Source: No API keys or usage limits for base maps
  • Well-Documented: Extensive documentation and examples
Use Cases:
  • Place location display
  • Trail/route visualization (GPX tracks)
  • Geographic search and filtering
  • Points of interest (POIs)
  • Service area mapping
Features:
  • Marker clustering
  • Custom markers and popups
  • Tile layer providers (OpenStreetMap)
  • GeoJSON support
  • Drawing and editing tools
Example:
const map = L.map('map').setView([48.8566, 2.3522], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors'
}).addTo(map);
L.marker([48.8566, 2.3522]).addTo(map)
  .bindPopup('Location Name');

Email

Nodemailer 7.0.13

Purpose: Email sending for Node.js Why Nodemailer?
  • Versatile: SMTP, sendmail, SES, and more
  • Template Support: HTML and text emails
  • Attachments: File attachments with streams
  • Unicode Support: International characters
  • Well-Maintained: Active development and community
Use Cases:
  • Account verification emails
  • Password reset emails
  • Booking confirmations
  • Notification digests
  • Admin alerts
Configuration:
import nodemailer from 'nodemailer';

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: parseInt(process.env.SMTP_PORT),
  secure: true,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});
Email Templates:
  • HTML templates with inline CSS
  • Text fallbacks for plain-text clients
  • Multi-language support

Utilities & Validation

Validator 13.15.26

Purpose: String validation and sanitization Why Validator?
  • Comprehensive: 50+ validation functions
  • Sanitization: Clean and normalize user input
  • Well-Tested: High code coverage
  • Zero Dependencies: Lightweight
Common Validations:
  • Email addresses: validator.isEmail()
  • URLs: validator.isURL()
  • UUIDs: validator.isUUID()
  • Phone numbers: validator.isMobilePhone()
  • Alphanumeric: validator.isAlphanumeric()
Example:
import validator from 'validator';

if (!validator.isEmail(email)) {
  throw new Error('Invalid email address');
}
if (!validator.isURL(website)) {
  throw new Error('Invalid URL');
}

nanoid 5.1.6

Purpose: Tiny, secure URL-friendly unique string ID generator Why nanoid?
  • Compact: Shorter IDs than UUID (21 characters by default)
  • URL-Safe: Only uses A-Za-z0-9_-
  • Fast: 2x faster than UUID
  • Secure: Cryptographically strong random
Use Cases:
  • Short URLs for sharing
  • Session tokens
  • Temporary file names
  • Non-database unique identifiers

Development Tools

TypeScript 5.9.3

Purpose: Typed superset of JavaScript Why TypeScript?
  • Type Safety: Catch errors at compile time
  • Better IDE Support: Autocomplete, refactoring
  • Self-Documenting: Types serve as inline documentation
  • Gradual Adoption: Can mix with JavaScript
tsconfig.json:
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  }
}

Drizzle Kit 0.31.9

Purpose: Drizzle ORM migration toolkit Features:
  • Generate migrations from schema changes
  • Apply migrations to database
  • Introspect existing databases
  • Push schema directly (dev mode)
Commands:
pnpm db:generate  # Generate migration files
pnpm db:migrate   # Apply pending migrations

tsx 4.21.0

Purpose: TypeScript execute - run TS files directly Use Cases:
  • Database scripts (seed, migrate)
  • Build scripts
  • Utility scripts

Testing

Vitest 4.0.18

Purpose: Fast unit test framework Why Vitest?
  • Vite-Powered: Instant HMR for tests
  • Jest-Compatible: Familiar API
  • Fast: Multi-threaded test execution
  • TypeScript: First-class TS support
Features:
  • Unit tests: vitest run tests/unit
  • Integration tests: vitest run tests/integration
  • Coverage: @vitest/coverage-v8
  • UI: @vitest/ui for interactive test running

Playwright 1.58.2

Purpose: End-to-end browser testing Features:
  • Multi-browser (Chromium, Firefox, WebKit)
  • Auto-wait for elements
  • Network interception
  • Screenshots and videos

Happy DOM 20.7.0

Purpose: Lightweight DOM implementation for testing Why Happy DOM?
  • Fast: 2-3x faster than jsdom
  • Accurate: High compatibility with browser APIs
  • SSR Testing: Test Astro components

Asset Management

Astro Font 1.1.0

Purpose: Font optimization for Astro Features:
  • Automatic font subsetting
  • Preload optimization
  • Local font hosting

Astro Icon 1.1.5

Purpose: Icon component system Icon Sets:
  • @iconify-json/mdi - Material Design Icons (1.2.3)
  • @iconify-json/circle-flags - Country flags (1.2.10)
  • @iconify-json/openmoji - Emoji icons (1.2.22)
Usage:
<Icon name="mdi:account" size={24} />

Additional Dependencies

dotenv 17.3.1

  • Load environment variables from .env files
  • Development and production configuration

fast-glob 3.3.3

  • Fast file pattern matching
  • Used in build scripts and content collection

jose 6.1.3

  • JavaScript Object Signing and Encryption
  • JWT token handling (alternative to jsonwebtoken)

Deployment Adapters

@astrojs/node 9.5.4

Purpose: Node.js SSR adapter Use Cases:
  • Self-hosted deployments
  • VPS or dedicated servers
  • Docker containers

@astrojs/vercel 9.0.4

Purpose: Vercel platform adapter Features:
  • Edge functions support
  • Image optimization via Vercel
  • Analytics integration

Version Summary

CategoryTechnologyVersion
FrameworkAstro5.18.0
AuthBetter Auth1.4.18
ORMDrizzle ORM0.45.1
DatabasePostgreSQL (pg)8.18.0
MapsLeaflet1.9.4
EmailNodemailer7.0.13
EditorEasyMDE2.20.0
Markdownmarkdown-it14.1.1
Validationvalidator13.15.26
IDsnanoid5.1.6
TypeScripttypescript5.9.3
TestingVitest4.0.18
TestingPlaywright1.58.2
Iconsastro-icon1.1.5

Technology Selection Criteria

All technologies were chosen based on:
  1. Type Safety: Full TypeScript support
  2. Performance: Minimal runtime overhead
  3. Developer Experience: Great documentation and tooling
  4. Community: Active maintenance and ecosystem
  5. Security: Secure by default, regular updates
  6. Production-Ready: Battle-tested at scale

Next Steps