Version: 0.1.0 Last Updated: 2024-11-19 Status: ✅ Production Ready
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.
┌─────────────┐
│ 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)?;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)?; ┌──────────┐
│ 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()?)?;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/.
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.
┌─────────────────────────────────────────┐
│ 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() │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
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 ...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- All operations work locally first
- Sync happens asynchronously in background
- No blocking on network
- No merge conflicts ever
- Last-Write-Wins with HLC timestamps
- Deterministic ordering across devices
- No central server required
- Direct device-to-device communication
- Relay servers as fallback only
- Argon2 password hashing
- Noise Protocol for transport encryption
- Ed25519 device signatures
- No plaintext secrets
- Single Rust codebase
- FFI for language interop
- Mobile (iOS/Android), Desktop, Web
| 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 |
Test Coverage: ~85% (17/18 tests passing)
cargo testTest Categories:
- ✅ Unit tests (CRDT, HLC, crypto)
- ✅ Integration tests (database ops)
- ✅ Migration tests (schema versioning)
⚠️ P2P tests (1 network test fails in CI - expected)
- SQL Injection: Protected (parameterized queries)
- Password Storage: Secure (Argon2 with unique salts)
- Transport: Encrypted (Noise Protocol)
- Device Auth: Strong (Ed25519 signatures)
- Implement rate limiting on auth endpoints
- Add CAPTCHA for registration
- Use HTTPS for relay servers
- Implement data-at-rest encryption (SQLCipher)
If you were using the old FocusSuite code with task/habit features:
- Extract your data models to your application
- Use Ahenk for User + Sync only
- Create your own tables alongside Ahenk's core tables
- 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)
);- README.md - Getting started guide
- DATABASE_MIGRATIONS.md - Migration system
- P2P_SYNC.md - P2P architecture details
- CLI_USAGE.md - CLI tool documentation
- CHANGELOG.md - Version history
Production Ready: ✅ Yes
API Stability: 0.1.0 (expect changes)
Maintenance: Active
License: MIT OR Apache-2.0