> Architecture

Single process, single database, zero external dependencies.


Overview

Echelon Analytics is a Deno + Fresh application backed by a single SQLite database. All state — sessions, rate limiter, burst maps, buffered writers — lives in memory. Runs as a single process (no --parallel flag).

Tech Stack

LayerTechnology
RuntimeDeno 2.x
FrameworkFresh 2.2.0 (file-system routing, Preact islands)
BuildVite 7
CSSTailwind CSS v4 (@tailwindcss/vite plugin)
UIPreact + @preact/signals
DatabaseSQLite via node:sqlite (WAL mode)
ContainerDocker (multi-stage, non-root, tini)

Request Flow

How a pageview goes from browser to database:

1. Script Load

Browser fetches /ea.js, which returns a dynamically-generated tracker script with an embedded WASM blob (rotated every 6 hours) and a per-minute challenge string.

2. Client Initialization

3. Pageview Beacon

On user interaction, the tracker loads /b.gif as an image with query params: path, site ID, session ID, PoW token, screen dimensions, referrer, UTM data.

4. Server Processing

5. Buffered Write

The BufferedWriter batches records (up to 50k) and flushes to SQLite every 10–15 seconds in a single transaction. On shutdown, remaining records are flushed before exit.

6. Behavioral Events

Scroll depth, clicks, bounces, session events, and custom events are sent via sendBeacon to POST /e. Same scoring and buffering pipeline, separate writer instance.


Database

SQLite Configuration

PRAGMAValueWhy
journal_modeWALConcurrent reads during writes
synchronousNORMALBalance durability and speed
busy_timeout5000Retry on lock contention
foreign_keysONReferential integrity

Core Tables

TablePurposeRetention
visitor_viewsRaw pageviews with bot scores90 days
visitor_views_dailyRollup aggregates (filtered)730 days
semantic_eventsBehavioral events (clicks, scrolls, bounces, custom)90 days

Supporting Tables

TablePurpose
excluded_visitorsManually excluded visitor IDs
experimentsA/B experiment metadata
experiment_variantsVariant definitions and weights
utm_campaignsCampaign tracking
site_settingsPer-site consent CSS
perf_metricsCI/CD performance tracking
maintenance_logRollup status tracking

Adapter Interface

The database layer uses an interface (DbAdapter) with methods for query, queryOne, run, exec, and transaction. Currently backed by node:sqlite. All queries use parameterized ? placeholders.


Data Pipeline

Buffered Writers

Two BufferedWriter<T> instances run in parallel:

WriterTargetFlush IntervalMax Buffer
viewWritervisitor_views15 seconds50,000
eventWritersemantic_events10 seconds50,000

Each flush runs in a single transaction. If a flush fails, records are re-added to the buffer.

Daily Rollup

At ~03:00 UTC, the maintenance task:

Data Purge

After rollup, expired data is purged:


Visitor Identity

Cookieless (default)

HMAC-SHA256 of IP + User-Agent + site ID + date, truncated to 16-char hex. Resets daily — no cross-day tracking. Requires no cookie consent.

Cookie (opt-in)

HttpOnly _ev cookie with a 16-char hex value, 30-day TTL. Enabled with data-cookie on the script tag.


Proof-of-Work System


Authentication

Bearer Token

Set ECHELON_SECRET env var. Verified via constant-time comparison to prevent timing attacks.

Username/Password

PBKDF2-SHA256 with 600k iterations, 256-bit key, 128-bit random salt. Uses Web Crypto API only — no external dependencies.

Sessions

In-memory session store. Random UUID tokens, 24-hour TTL, pruned every 30 minutes. echelon_session HttpOnly cookie.

CSRF Protection

Mutating requests (POST/PATCH/DELETE) with cookie auth must include a matching Origin or Referer header.


Directory Structure

echelon-analytics/
  main.ts                  Entry point, graceful shutdown
  deno.json                Config, import aliases, tasks
  vite.config.ts           Vite build config

  lib/
    tracker.ts             Tracker script generation
    beacon.ts              Pageview beacon handler
    events-endpoint.ts     Behavioral events handler
    bot-score.ts           Bot scoring heuristics
    challenge.ts           PoW challenge management
    challenge-wasm.ts      WASM bytecode builder
    buffered-writer.ts     Generic batch writer
    auth.ts                PBKDF2 password hashing
    session.ts             In-memory session store
    config.ts              Env var centralization
    maintenance.ts         Daily rollup and purge
    stats.ts               Stats query handlers
    utm.ts                 Campaign cache
    rate-limit.ts          Per-IP rate limiter
    db/
      adapter.ts           Database interface
      sqlite-adapter.ts    SQLite implementation
      database.ts          Init, migrations, singleton
      schema.ts            DDL and indexes

  routes/
    ea.js.ts               GET /ea.js
    b.gif.ts               GET /b.gif
    e.ts                   POST /e
    _middleware.ts          CORS, security headers
    api/                   REST API routes
    admin/                 Admin UI routes

  islands/                 Preact interactive components
  components/              Server-only Preact components
  assets/                  Tailwind CSS, images
  static/                  Favicon, static files

Design Decisions

Single Process

All state is in-memory. Simple to deploy and reason about. Trade-off: horizontal scaling requires moving to external session/state stores.

WAL Mode

Write-Ahead Logging enables concurrent reads while writes proceed. Combined with synchronous = NORMAL, balances durability and throughput.

Buffered Writes

Trades immediate durability for throughput. Beacon returns instantly (~1ms), records batch-flush every 10–15 seconds. Graceful shutdown flushes remaining buffers.

Runtime WASM Generation

Each deployment generates unique WASM blobs. Bot toolkits can't pre-compute solutions. Low barrier for browsers (150ms timeout with fallback).

Raw Data + Rollups

Raw data kept for inspection and re-analysis (90 days). Rollups provide fast long-range queries (2 years). Bot filtering happens at rollup time — raw data preserves everything for forensics.


Installation Features API Reference Bot Defense Configuration