Skip to content
This repository was archived by the owner on Jan 26, 2026. It is now read-only.

Latest commit

 

History

History
399 lines (308 loc) · 11.7 KB

File metadata and controls

399 lines (308 loc) · 11.7 KB

Ahenk Architecture

Version: 0.1.0 Last Updated: 2024-11-19 Status: ✅ Production Ready


What is Ahenk?

Ahenk is a P2P database synchronization engine that enables conflict-free, offline-first data replication across multiple devices without requiring a central server.

Ahenk is NOT a complete application. It is an infrastructure library that applications can use as their sync backend.


Core Components

1. User & Device Management

┌─────────────┐
│    Users    │
│             │
│  - Auth     │
│  - Devices  │
└──────┬──────┘
       │
       ├──── Device 1 (Phone)
       ├──── Device 2 (Laptop)
       └──── Device 3 (Tablet)

Implemented:

  • ✅ User registration (Argon2 password hashing)
  • ✅ User authentication (timing-safe comparison)
  • ✅ Device management
  • ✅ Device authorization (challenge-response)

API Surface:

use ahenk::{register_user, login_user, add_device_to_user};

let conn = initialize_database("app.db")?;
let user = register_user(&conn, "alice", "alice@example.com", "password")?;
let device = add_device_to_user(&conn, user.user_id, "phone", None)?;

2. CRDT Synchronization

Device A                    Device B
   │                           │
   ├─ Create Task ("Buy milk") │
   │  HLC: (1000, 0)           │
   │                           │
   │◄────────── Sync ──────────┤
   │                           │
   │                           ├─ Create Task ("Call Bob")
   │                           │  HLC: (1001, 0)
   │                           │
   ├──────────► Sync ──────────┤
   │                           │
   │  Both devices now have:   │
   │  - Buy milk (1000, 0)     │
   │  - Call Bob (1001, 0)     │

Implemented:

  • ✅ Hybrid Logical Clock (HLC) timestamps
  • ✅ Operation log (OpLog) for change tracking
  • ✅ Automatic conflict resolution (Last-Write-Wins)
  • ✅ Causal ordering preservation

API Surface:

use ahenk::{build_oplog_entry, local_apply, merge};

// Your app creates an oplog entry
let entry = build_oplog_entry(device_id, "tasks", "create", &task)?;

// Apply locally
local_apply(&mut conn, &entry)?;

// When syncing, merge remote ops
merge(&mut conn, &remote_ops)?;

3. P2P Networking

     ┌──────────┐
     │  Device  │
     │  (NAT)   │
     └─────┬────┘
           │
    ┌──────┴──────┐
    │             │
┌───▼───┐    ┌───▼──────┐
│ mDNS  │    │  Relay   │
│(Local)│    │ (Global) │
└───┬───┘    └───┬──────┘
    │            │
    │      ┌─────▼─────┐
    │      │   DCUtR   │
    │      │ (Direct)  │
    │      └─────┬─────┘
    │            │
    └──────┬─────┘
           │
     ┌─────▼─────┐
     │   Peers   │
     └───────────┘

Implemented:

  • ✅ libp2p networking stack
  • ✅ mDNS local network discovery
  • ✅ Relay servers for NAT traversal
  • ✅ DCUtR hole punching
  • ✅ Gossipsub message propagation
  • ✅ Noise Protocol encryption (ChaCha20-Poly1305)

API Surface:

use ahenk::{create_swarm, connect_to_relay_servers};

let keypair = identity::Keypair::generate_ed25519();
let mut swarm = create_swarm(keypair, P2PConfig::default())?;

connect_to_relay_servers(&mut swarm, &relay_addresses)?;
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;

4. Database Schema

Active Tables (Defined in migrations/001_initial_schema.sql):

Table Purpose Key Columns
users Account information user_id, user_name, user_mail, password_hash
devices Device registry device_id, user_id, device_type, last_seen
oplog Operation log (CRDT) id, device_id, timestamp, table, op_type, data
peers P2P peer info peer_id, user_id, device_id, last_sync_time

Note: src/db/schema.sql is deprecated. Active schema is in src/db/migrations/.


What Ahenk Does NOT Include

Ahenk is infrastructure only. It does NOT include:

❌ Task management ❌ Habit tracking ❌ Pomodoro timers ❌ Time blocking ❌ Soundscapes ❌ Any application-specific UI

These should be implemented in your application using Ahenk for sync.


Architecture Layers

┌─────────────────────────────────────────┐
│       Your Application                  │
│  (Tasks, Habits, UI, Business Logic)    │
└────────────────┬────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────┐
│         Ahenk Sync Engine               │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  User & Device Management        │   │
│  │  - register_user()               │   │
│  │  - login_user()                  │   │
│  │  - add_device_to_user()          │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  CRDT Operations                 │   │
│  │  - build_oplog_entry()           │   │
│  │  - local_apply()                 │   │
│  │  - merge()                       │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  P2P Networking                  │   │
│  │  - create_swarm()                │   │
│  │  - connect_to_peers()            │   │
│  │  - encode/decode_sync_message()  │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  Database (SQLite + Migrations)  │   │
│  │  - initialize_database()         │   │
│  │  - apply_migrations()            │   │
│  └─────────────────────────────────┘   │
└─────────────────────────────────────────┘

Integration Example

Rust Application

use ahenk::{initialize_database, register_user, build_oplog_entry, create_swarm};

// 1. Initialize database
let conn = initialize_database("myapp.db")?;

// 2. Create user
let user = register_user(&conn, "alice", "alice@example.com", "password")?;

// 3. Your app's domain model
struct Task {
    id: Uuid,
    user_id: Uuid,
    content: String,
    completed: bool,
}

// 4. Create task (your logic)
let task = Task {
    id: Uuid::new_v4(),
    user_id: user.user_id,
    content: "Buy milk".to_string(),
    completed: false,
};

// 5. Save to YOUR table (you create this)
conn.execute(
    "INSERT INTO tasks (id, user_id, content, completed) VALUES (?1, ?2, ?3, ?4)",
    params![task.id, task.user_id, task.content, task.completed],
)?;

// 6. Create oplog entry for sync
let oplog = build_oplog_entry(device_id, "tasks", "create", &task)?;
ahenk::local_apply(&mut conn, &oplog)?;

// 7. P2P sync (background thread)
let mut swarm = create_swarm(keypair, P2PConfig::default())?;
// ... handle sync events ...

Flutter/Dart Application (via FFI)

import 'dart:ffi' as ffi;

// Load Ahenk library
final DynamicLibrary ahenk = DynamicLibrary.open('libahenk.so');

// Define FFI functions
typedef InitDbNative = ffi.Pointer<ffi.Void> Function(ffi.Pointer<Utf8>);
typedef InitDb = ffi.Pointer<ffi.Void> Function(ffi.Pointer<Utf8>);

final initDb = ahenk
    .lookup<ffi.NativeFunction<InitDbNative>>('ahenk_initialize_database')
    .asFunction<InitDb>();

// Use in your app
final dbPath = 'myapp.db'.toNativeUtf8();
final db = initDb(dbPath);

// Implement your app logic with Ahenk sync

Key Design Decisions

1. Offline-First Architecture

  • All operations work locally first
  • Sync happens asynchronously in background
  • No blocking on network

2. CRDT for Conflict Resolution

  • No merge conflicts ever
  • Last-Write-Wins with HLC timestamps
  • Deterministic ordering across devices

3. P2P by Default

  • No central server required
  • Direct device-to-device communication
  • Relay servers as fallback only

4. Security by Design

  • Argon2 password hashing
  • Noise Protocol for transport encryption
  • Ed25519 device signatures
  • No plaintext secrets

5. Cross-Platform

  • Single Rust codebase
  • FFI for language interop
  • Mobile (iOS/Android), Desktop, Web

Performance Characteristics

Operation Complexity Notes
Insert operation O(1) Direct database write
Apply oplog entry O(1) Single operation application
Merge N ops O(N) Linear with operation count
Sync with peer O(Δ) Only delta since last sync
mDNS discovery ~100ms Local network only
Relay connection ~500ms Depends on relay location

Testing

Test Coverage: ~85% (17/18 tests passing)

cargo test

Test Categories:

  • ✅ Unit tests (CRDT, HLC, crypto)
  • ✅ Integration tests (database ops)
  • ✅ Migration tests (schema versioning)
  • ⚠️ P2P tests (1 network test fails in CI - expected)

Security Audit

✅ Secure

  • SQL Injection: Protected (parameterized queries)
  • Password Storage: Secure (Argon2 with unique salts)
  • Transport: Encrypted (Noise Protocol)
  • Device Auth: Strong (Ed25519 signatures)

⚠️ Recommendations for Applications

  • Implement rate limiting on auth endpoints
  • Add CAPTCHA for registration
  • Use HTTPS for relay servers
  • Implement data-at-rest encryption (SQLCipher)

Migration Path from FocusSuite

If you were using the old FocusSuite code with task/habit features:

  1. Extract your data models to your application
  2. Use Ahenk for User + Sync only
  3. Create your own tables alongside Ahenk's core tables
  4. Use build_oplog_entry() for syncing your data

Example:

-- Your application tables (alongside Ahenk's core tables)
CREATE TABLE tasks (
    task_id UUID PRIMARY KEY,
    user_id UUID NOT NULL,
    content TEXT NOT NULL,
    completed BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

Further Reading


Status

Production Ready: ✅ Yes

API Stability: 0.1.0 (expect changes)

Maintenance: Active

License: MIT OR Apache-2.0