6.1 KiB
ADR-0007: Schema Extension — Phase 2 Missing Entities (Task 2.1)
Date: 2026-08-22
Status: Accepted
Task: 2.1 — Extend Schema with Missing Entities
Author: Autonomous Agent Cycle
Context
The Phase 2 completion criteria for ChronoGrid P2P require 13 total database tables (7 original Phase 1 tables + 6 new Phase 2 extension tables). The architecture review (ADL-006) identified 6 missing schema tables as a critical gap blocking Phase 3 (Flutter UI requires calendar/time-block entities) and Phase 4 (AI/automation requires ingestion and rule entities).
The canonical schema at docs/API_CONTRACTS/schema.sql is embedded at compile time via include_str! in crates/chronogrid_core/src/db.rs, making it the single source of truth for all database structure.
Decision
New Tables Added
Six new tables were added to docs/API_CONTRACTS/schema.sql:
1. time_blocks
- Purpose: Calendar time-blocking entries linked to tasks. Represents a scheduled block of time on the calendar grid.
- Key fields:
id,namespace_id,task_id(nullable FK → tasks, SET NULL),title,start_time,end_time,color_hex,is_all_day,recurrence_rule,hlc_timestamp - CRDT: Supports
entity_type = 'time_block'incrdt_docstable (documented in comment and tested). - Indexes:
idx_time_blocks_namespace,idx_time_blocks_task,idx_time_blocks_start
2. attachments
- Purpose: Binary/file attachments linked to notes or ingestion logs.
- Key fields:
id,note_id(nullable FK → notes, CASCADE),ingestion_log_id(nullable FK → ingestion_logs, CASCADE),file_name,mime_type,file_size_bytes,storage_path,checksum_sha256,hlc_timestamp - Design note:
storage_pathis a relative path inside the encrypted vault directory; actual file bytes are stored outside SQLite to avoid BLOB size limits. - Indexes:
idx_attachments_note,idx_attachments_ingestion
3. calendar_feeds
- Purpose: CalDAV external feed configuration per namespace.
- Key fields:
id,namespace_id(FK → namespaces, CASCADE),display_name,feed_url,username,encrypted_password_blob(AES-GCM encrypted, key from keychain),sync_interval_seconds,last_synced_at,is_enabled,hlc_timestamp - Security: Credentials are stored as encrypted blobs — never plaintext.
- Indexes:
idx_calendar_feeds_namespace
4. node_peers
- Purpose: P2P peer registry — NodeId, public key, last seen, swarm membership.
- Key fields:
id(NodeId: Ed25519 public key hash hex),public_key_bytes(BLOB, 32 bytes),swarm_key_fingerprint,last_seen_at,last_known_addrs(JSON array of multiaddr strings),is_trusted - Design note: No FK to
namespaces— peers are global to the node, not namespace-scoped. - No
hlc_timestamp: Peer registry entries are managed by the networking layer, not the CRDT engine. - Indexes:
idx_node_peers_swarm,idx_node_peers_last_seen
5. automation_rules
- Purpose: Local trigger/action rule definitions for the automation engine.
- Key fields:
id,namespace_id(FK → namespaces, CASCADE),name,trigger_type(task_created|task_status_changed|ingestion_received|schedule),trigger_config(JSON),action_type(set_field|create_task|send_notification|run_script),action_config(JSON),is_enabled,execution_count,last_executed_at,hlc_timestamp - Indexes:
idx_automation_rules_namespace,idx_automation_rules_trigger
6. ingestion_configs
- Purpose: IMAP account and file-watcher configuration per namespace.
- Key fields:
id,namespace_id(FK → namespaces, CASCADE),config_type(imap|file_watcher|hotkey), IMAP-specific fields (imap_host,imap_port,imap_username,encrypted_imap_password_blob,imap_mailbox,imap_use_tls), file-watcher fields (watch_path,watch_extensionsJSON array),poll_interval_seconds,last_polled_at,hlc_timestamp - Design note: Single table covers multiple ingestion types via
config_typediscriminator; type-specific fields are nullable for non-applicable types. - Indexes:
idx_ingestion_configs_namespace,idx_ingestion_configs_type
CRDT Compatibility
All 6 new tables include hlc_timestamp TEXT NOT NULL (except node_peers, which is managed by the networking layer and does not participate in CRDT sync). The crdt_docs table comment was updated to document time_block as a valid entity_type value alongside task and note.
Code Changes
| File | Change |
|---|---|
docs/API_CONTRACTS/schema.sql |
Added 6 new tables + 12 new indexes |
crates/chronogrid_core/src/db.rs |
Updated EXPECTED_TABLES from 7 to 13 entries |
crates/chronogrid_core/src/db.rs |
Added 8 new unit tests covering all Phase 2 tables |
Test Coverage Added
schema_has_exactly_13_tables— asserts total table count = 13open_in_memory_creates_indexes— expanded to cover all 17 indexes (5 Phase 1 + 12 Phase 2)crud_time_blocks— insert, read, FK SET NULL on task deletioncrud_attachments— insert, read, CASCADE delete with notecrud_calendar_feeds— insert, read, CASCADE delete with namespacecrud_node_peers— insert, read, updatelast_seen_atcrud_automation_rules— insert, read, CASCADE delete with namespacecrud_ingestion_configs— IMAP + file-watcher configs, CASCADE deletecrdt_doc_time_block_entity_type— verifiestime_blockentity_type incrdt_docs
Consequences
- Positive: All Phase 2 completion criteria for schema are met (13 tables confirmed by verification script).
- Positive:
EXPECTED_TABLESvalidation indb.rsnow enforces all 13 tables on every database open, preventing schema drift. - Positive: Existing Phase 1 tests are unaffected — all DDL uses
CREATE TABLE IF NOT EXISTS. - Neutral:
node_peersintentionally omitshlc_timestampas it is managed bychronogrid_net, not the CRDT engine. - Neutral:
attachments.storage_pathstores relative paths; the vault directory root is resolved at runtime by the application layer.