Files
OSIT-AE-App-Svelte/documentation/AE_UI_Journals_module_update_2026.md

6.6 KiB

Aether Journals UI Update (2026)

Status: 🚧 Stuck on Phase 4 (Security/Encryption Blockers) Last Updated: 2026-01-14 Primary Agent: Frontend SvelteKit Agent

1. Project Overview

This document outlines the modernization of the Journals module UI in the SvelteKit frontend (aether_app_sveltekit). The primary goals are to fully leverage the generic V3 API architecture and introduce high-velocity productivity features for journal management.

Context: The backend transition to the generic api_crud_v3 router is complete. Custom legacy routers have been removed. The frontend must now fully align with this pattern and provide a frictionless user experience.


2. Core Objectives

🎯 Primary Goals

  1. V3 API Verification: Ensure all CRUD operations utilize the generic api_crud_v3 endpoints (Verified).
  2. Quick Add UI: Implement a specialized interface for rapid, friction-free entry creation.
  3. Append/Prepend UI: Allow users to quickly add text to the beginning or end of existing entries without full edit mode.
  4. Interop & Portability: Robust import/export logic for Markdown/HTML (Nextcloud Notes compatibility).
  5. Security Hardening: Review and harden client-side encryption logic (BLOCKED).

3. Technical Architecture

Backend (Completed)

  • Router: api_crud_v3 (Generic)
  • Definitions: app/ae_obj_types_def.py -> app/object_definitions/journals.py
  • Endpoints: /v3/crud/journal/... and /v3/crud/journal_entry/...

Frontend (In Progress)

  • State Management: src/lib/ae_journals/ae_journals_stores.ts
  • Local Storage: Dexie.js (db_journals)
  • API Client: src/lib/api/api.ts -> get_ae_obj_v3
  • Export Engine: Centralized templates in src/lib/ae_journals/ae_journals_export_templates.ts.

4. Feature Specifications

Quick Add (Complete)

  • Component: src/routes/journals/ae_comp__journal_entry_quick_add.svelte
  • Behavior: Creates a new journal_entry attached to the active journal without leaving the list view.

📝 Append / Prepend (Complete)

  • Interaction: Fast text injection via AeCompModalJournalEntryAppend.
  • Logic: Updates entry content without full editor state overhead.

🔄 Interop (Markdown/HTML) (Complete)

  • Goal: Bulk export/import for data portability.
  • Templates: Standard, Personal Log, Amazon Vine.

5. Implementation Plan

Phase 1: Foundation (Done)

  • Backend cleanup (remove legacy routers).
  • Verify frontend uses V3 API (ae_journals__journal.ts).

Phase 2: Rapid Entry (Complete)

  • Create ae_comp__journal_entry_quick_add.svelte.
  • Integrate Quick Add into +page.svelte.

Phase 3: Content Manipulation & Portability (Complete)

  • Implement Append/Prepend logic.
  • Implement Bulk Export/Import system.
  • Establish centralized Export Template engine.

Phase 4: Polish & Security (ACTIVE)

  • Implement Auto-Save toggle and visual status indicators.
  • Extract decryption workflow to non-reactive helper.
  • Solidify E2EE passcode system for Journals and Entries.
  • RESOLVED: Decryption workflow stability (Fixed via dependency isolation).
  • Audit encryption flow for Quick Added and Imported entries.
  • Integrate Outbound Email sharing.

🧠 Lessons Learned: Solving the Svelte 5 Reactivity Hang

During the implementation of the Privacy/Decryption toggle, we encountered a critical browser hang caused by an infinite reactivity loop. Here is how we resolved it and the patterns we should follow in the future:

1. Rigorous Dependency Isolation (untrack)

Svelte 5 runes ($effect, $derived) automatically track every reactive variable read inside them.

  • The Problem: An effect would read save_status or tmp_entry_obj.content to decide if it should sync, but the act of syncing would update those same variables, re-triggering the effect.
  • The Fix: Wrap any "check-only" state or store reads in untrack(() => ... ). This allows the effect to use the value without becoming a dependency of it.

2. Manual Deep Copying vs. Proxies

Svelte 5 state is backed by Proxies.

  • The Problem: Using JSON.parse(JSON.stringify(proxy)) can sometimes trigger unexpected behavior or loops when used inside a reactive context.
  • The Fix: Implement a manual deep_copy helper or selective property assignment when syncing "Original" vs "Temporary" state. This ensures orig_entry_obj is a plain JS object, making the has_unsaved_changes check stable.

3. Concurrency Locking (is_processing)

  • The Problem: Decryption (Async) and Auto-Save (Debounced Async) can fire nearly simultaneously.
  • The Fix: Use a simple is_processing boolean flag. If any async workflow is active, block others from starting and prevent the has_unsaved_changes derived rune from reporting true.

4. Comparison Normalization

  • The Problem: Trivial differences (e.g., null vs "" or trailing whitespace) would trigger "unsaved changes" and fire the save loop.
  • The Fix: Use a normalize() function in the has_unsaved_changes derived rune to trim strings and treat null/undefined as empty strings during comparison.

⚠️ Technical Blocker: The "Decryption-Sync" Loop (Resolved)

The Issue

The component is suffering from a Reactive Feedback Loop between decryption, auto-save, and background IDB refreshes.

  1. Decrypting content triggers a change in tmp_entry_obj.content.
  2. The Auto-Save effect sees this as a manual user edit and saves to the database.
  3. Dexie LiveQuery detects the DB update and refreshes the object.
  4. The Sync effect resets the entry to its encrypted state (from DB).
  5. The Auto-Decryption effect fires again, starting the loop over.

What we tried:

  • is_processing flags: Attempted to block reactivity during decryption.
  • untrack(): Attempted to isolate store updates.
  • Reference Sync: Attempted to update orig_entry_obj simultaneously with decryption to fool the change detector.
  • Direct Store Updates: Switching from property assignment to journals_sess.update() to fix Svelte 5 notification failures.

Future Fix Ideas:

  1. Native Svelte 5 State: Refactor journals_sess from a Svelte 4 Writable to a class using $state.
  2. Logic Extraction: Move decryption logic into a non-reactive class/helper to isolate side effects from the UI render cycle.
  3. Hash Comparison: Use content hashes for change detection instead of string comparisons to avoid whitespace/normalization loops.