Files
OSIT-AE-App-Svelte/documentation/NATIVE_APP_V3_REWRITE_PLAN.md
Scott Idem 683ea0394d Fix: Restore Native caching business logic and implement 3-mode launcher
- Implemented Default, Onsite, and Native launcher modes in launcher_file_cont.svelte.
- Restored background pre-caching logic with configurable timers in new LauncherBackgroundSync component.
- Fixed standard browser download regression for regular website mode.
- Modernized electron_relay to TypeScript and standardized bridge detection in layout.
- Detailed startup and background sync technical flow in documentation.
2026-01-23 15:17:50 -05:00

9.2 KiB

Project Plan: Aether Native V3 Rewrite

Target: Electron 33+ Primary Platform: macOS (Production) Development Platform: Arch Linux API Version: Aether V3 (REST + JWT)

0. Project Purpose

The sole purpose of this Native App is to serve as the AE Events Launcher. It provides the SvelteKit frontend with the ability to:

  • Persistently cache files in the local filesystem.
  • Execute OS-level shell commands and scripts (e.g., launching presentation software).
  • Provide a "Zero-Config" experience for onsite event laptops.

0.1 Application Modes

The system must support three distinct operational modes:

Mode Refresh Logic File Handling
Default Slower auto-refresh timers. Standard browser downloads. No local caching.
Onsite Faster auto-refresh timers. Downloads files with modified extensions (e.g., .pptxwin).
Native Fastest auto-refresh timers. Full background pre-caching. Launching from local temp directory with original names.

1. Minimalist Configuration Strategy

To simplify laptop deployment, we will move away from large local JSON files.

1.1 The "Seed" Config

Each laptop will contain a seed.json. For development, this is located at ~/seed.json. In production, it will move to standard OS config paths (e.g., ~/.config/aether/seed.json or ~/Library/Application Support/Aether/).

{
  "event_device_id": "dbgMWS3KEHE",
  "primary_api_base_url": "https://dev-api.oneskyit.com",
  "backup_api_base_url": null,
  "onsite_api_base_url": null,
  "aether_api_key": "INSdG85ANwsEIru3nUttMw"
}

Note: only event_device_id is strictly required for the bootstrapper to start.

1.2 The Bootstrap Flow

  1. Launch: Electron reads the seed.json.
  2. Identity: App calls GET /v3/crud/event_device/{id}.
  3. Hydrate: App uses app_base_url from the device record to search for the corresponding site_domain.
  4. Target URL: Electron constructs the launcher URL: http://[app_base_url]/events/[event_id]/launcher/[event_location_id]
  5. Inject: Config and JWT are injected into the SvelteKit frontend via the Preload script.

1.3 Technical Flow: Startup & Background Caching

The system utilizes a multi-layered hydration and synchronization strategy to ensure files are available instantly.

Step 1: Zero-Config Initialization (Main Process)

  • Seed Discovery: Main process reads seed.json.
  • Identity Exchange: Main process authenticates with the API using the aether_api_key.
  • Global Injections: Once hydrated, the Main process provides the SvelteKit frontend with:
    • native_device: Full record from event_device table (contains timers).
    • aether_api_key: For authorized background downloads.
    • local_file_cache_path: Root for the permanent hashed cache.
    • host_file_temp_path: Root for the operational launch directory.

Step 2: Session-Driven Caching (Renderer Process)

  • View Trigger: When a user navigates to a session or location, the SvelteKit frontend populates the event_file_obj_li store.
  • Sync Cycle: The LauncherBackgroundSync component detects the new file list and:
    1. Extracts all event_file_id values.
    2. Fetches full metadata (hashes) from the local Dexie IndexedDB.
    3. Asynchronously checks the Native Cache for each hash.
  • Background Download: Missing files are downloaded directly to the hashed cache using the authorized Native API Key.
  • Timer Loop: A background loop runs every check_event_loop_period (configurable via API) to ensure the cache stays in sync with server-side changes.

Step 3: Hashed Cache Pattern (Filesystem)

To prevent filename collisions and handle versioning, the permanent cache follows the server's structure:

  • Root: [local_file_cache_path]
  • Subdirectory: First 2 characters of SHA256 (e.g., ab/)
  • Filename: Full SHA256 with .file extension (e.g., abc123...file)

Step 4: Safe Handover (Launch Sequence)

When a user clicks "Open", the system follows a non-destructive handover:

  1. Verify: Confirm hash exists in local_file_cache_path.
  2. Prepare: Copy the hashed file to host_file_temp_path.
  3. Restore: Rename the copy back to its original filename (e.g., Presentation.pptx).
  4. Execute: Trigger OS-level shell.openPath() on the temp file. This ensures the permanent cache remains clean while the third-party app (PowerPoint, etc.) can operate on a file with a familiar name.

1.3 Technical Flow: Startup & Background Caching

The system utilizes a multi-layered hydration and synchronization strategy to ensure files are available instantly.

Step 1: Zero-Config Initialization (Main Process)

  • Seed Discovery: Main process reads seed.json.
  • Identity Exchange: Main process authenticates with the API using the aether_api_key.
  • Global Injections: Once hydrated, the Main process provides the SvelteKit frontend with:
    • native_device: Full record from event_device table (contains timers).
    • aether_api_key: For authorized background downloads.
    • local_file_cache_path: Root for the permanent hashed cache.
    • host_file_temp_path: Root for the operational launch directory.

Step 2: Session-Driven Caching (Renderer Process)

  • View Trigger: When a user navigates to a session or location, the SvelteKit frontend populates the event_file_obj_li store.
  • Sync Cycle: The LauncherBackgroundSync component detects the new file list and:
    1. Extracts all event_file_id values.
    2. Fetches full metadata (hashes) from the local Dexie IndexedDB.
    3. Asynchronously checks the Native Cache for each hash.
  • Background Download: Missing files are downloaded directly to the hashed cache using the authorized Native API Key.
  • Timer Loop: A background loop runs every check_event_loop_period (configurable via API) to ensure the cache stays in sync with server-side changes.

Step 3: Hashed Cache Pattern (Filesystem)

To prevent filename collisions and handle versioning, the permanent cache follows the server's structure:

  • Root: [local_file_cache_path]
  • Subdirectory: First 2 characters of SHA256 (e.g., ab/)
  • Filename: Full SHA256 with .file extension (e.g., abc123...file)

Step 4: Safe Handover (Launch Sequence)

When a user clicks "Open", the system follows a non-destructive handover:

  1. Verify: Confirm hash exists in local_file_cache_path.
  2. Prepare: Copy the hashed file to host_file_temp_path.
  3. Restore: Rename the copy back to its original filename (e.g., Presentation.pptx).
  4. Execute: Trigger OS-level shell.openPath() on the temp file. This ensures the permanent cache remains clean while the third-party app (PowerPoint, etc.) can operate on a file with a familiar name.

2. macOS Hardening (Permissions)

... macOS requires explicit user consent for several features. The new app will handle these during the "Splash Screen" phase.

  • AV Access: Use systemPreferences.askForMediaAccess('camera') and microphone.
  • Accessibility: For remote control/automation, check systemPreferences.isTrustedAccessibilityClient(true).
  • Screen Recording: Required for the presentation tracker. We will use a "Check and Prompt" loop.

3. Cross-Platform Handling

Feature macOS (Production) Linux/Windows (Dev/Comp)
Process Kill killall -INT "PowerPoint" pkill -f "powerpnt.exe"
Automation AppleScript (osascript) Mocked via logs or Shell commands.
Paths ~/Library/Caches/Aether ~/.cache/aether
Window Frameless, Transparent support. Standard decorated window.

4. Proposed Directory Structure

aether_app_native_v3/
├── src/
│   ├── main/
│   │   ├── index.ts          # Window lifecycle
│   │   ├── ipc_handlers.ts   # Whitelisted OS commands
│   │   ├── macos_perms.ts    # Mic/Cam/Accessibility logic
│   │   └── api_client.ts     # V3 Auth & Config sync
│   ├── preload/
│   │   └── index.ts          # Secure ContextBridge
│   └── shared/
│       └── types.ts          # TS Interfaces for the bridge
├── resources/                # Icons and splash screens
└── electron-builder.yml      # Multi-platform build config

5. Security Upgrades

  1. JWT Storage: Store the session token in Electron's safeStorage (OS-level encryption) rather than simple localStorage.
  2. Navigation Lock: Prevent the SvelteKit UI from navigating away from the Aether domain.
  3. Command Whitelisting: Instead of a generic run_cmd, implement specific handlers like native:launch-presentation which only accepts a file hash.

6. Deployment & Self-Update

To support onsite deployment via Syncthing:

  1. Version Watcher: Main process monitors admin_share/binaries/native_app/version.json.
  2. Atomic Swap: Use a dedicated update_helper.sh to swap the .app bundle while the app is closed.
  3. Zero-Touch Provisioning: Auto-copy seed_[hostname].json from the sync share if local config is missing.

7. Development Tools (Arch Linux)

  • Use fakeroot and binutils to package for macOS on Linux.
  • Use Xvfb for headless testing of Electron windows in CI/CD.