merge: reconcile Gitea claude-notes commits (10-11 Apr) with local Phase 3+ code history
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
0
help4bis-claude-notes/.gitkeep
Normal file
0
help4bis-claude-notes/.gitkeep
Normal file
63
help4bis-claude-notes/current-state.md
Normal file
63
help4bis-claude-notes/current-state.md
Normal file
@@ -0,0 +1,63 @@
|
||||
## M8Chat App2 — Current State (2026-04-11)
|
||||
|
||||
Custom Flutter Matrix chat client deployed to app2.m8chat.au. Replaces the FluffyChat fork (app.m8chat.au). Built on Matrix Dart SDK 0.33.0, LiveKit for video, Olm for E2EE.
|
||||
|
||||
### What was built/changed this session
|
||||
|
||||
1. **Jitsi Conference tab** — 4th bottom nav tab for joining conf.m8chat.au meetings
|
||||
2. **Help tab** — 5th bottom nav tab with troubleshooting guides, account management links
|
||||
3. **Auth rewrite (v2.0.0)** — fresh login every session on web, no credential persistence
|
||||
4. **SSSS/cross-signing/key backup** — full security setup dialog (Bootstrap flow)
|
||||
5. **Key restore dialog** — enter recovery key to download Megolm keys from backup
|
||||
6. **Authenticated media (v2.0.0)** — switched to /_matrix/client/v1/media/download/ (Synapse 1.151.0 froze old endpoint)
|
||||
7. **LiveKit E2EE** — CallE2EEManager for m.rtc.encryption_keys key exchange, COOP/COEP headers
|
||||
8. **Hangup fix** — sends {} to clear call.member state event
|
||||
9. **Cleaned up 24 ghost devices** for try user (DB direct delete)
|
||||
|
||||
### What works
|
||||
- Login/logout flow (fresh every session)
|
||||
- Room list with avatars (authenticated media endpoint)
|
||||
- Chat messaging (text)
|
||||
- Encrypted message display (lock icon for undecryptable)
|
||||
- Security setup (SSSS + cross-signing + key backup creation)
|
||||
- Key restore from backup
|
||||
- Jitsi conference joining (Conference tab)
|
||||
- Help tab with troubleshooting content
|
||||
- Spaces view
|
||||
- Profile with security settings
|
||||
|
||||
### What's broken / untested
|
||||
- **Video calls (E2EE interop)** — COOP/COEP headers added, E2EE re-enabled, but NOT YET TESTED. May still show scrambled video if key exchange doesn't interop with Element X's m.rtc.encryption_keys format.
|
||||
- **Hangup termination** — Changed to send {} but NOT YET TESTED whether Element X recognises it.
|
||||
- **Incoming call detection** — Not implemented. No MSC3401 state event listener.
|
||||
- **Avatar 404s in cached/old data** — sync_persistence_service caches URLs; stale URLs may linger in IndexedDB
|
||||
- **Ghost devices accumulate** — each web login creates a new device. No cleanup mechanism.
|
||||
- **Rooms provider fires excessively** — console shows room list logged 15+ times per sync cycle (performance)
|
||||
- **Noto font warning** — emoji characters in room names can't render (missing font asset)
|
||||
|
||||
### Key file paths
|
||||
| File | Version | Purpose |
|
||||
|------|---------|---------|
|
||||
| lib/core/auth/auth_notifier.dart | 2.0.0 | Auth state machine — fresh login, no restore |
|
||||
| lib/core/auth/secure_storage.dart | 2.0.0 | Minimal — only stores device ID (currently unused) |
|
||||
| lib/core/config/app_config.dart | 2.0.0 | Server URLs, app name/version |
|
||||
| lib/shared/utils/mxc_url.dart | 2.0.0 | Authenticated media URL resolution |
|
||||
| lib/features/calls/data/livekit_service.dart | 1.4.0 | LiveKit connect/disconnect with E2EE |
|
||||
| lib/features/calls/data/call_e2ee.dart | 1.0.0 | E2EE key exchange via m.rtc.encryption_keys |
|
||||
| lib/features/profile/presentation/security_setup_dialog.dart | 1.0.0 | SSSS Bootstrap driver |
|
||||
| lib/features/profile/presentation/key_restore_dialog.dart | 1.0.0 | Recovery key input + loadAllKeys |
|
||||
| lib/features/help/presentation/help_tab.dart | 1.1.0 | In-app help content |
|
||||
| lib/features/jitsi/presentation/conference_tab.dart | 1.0.0 | Jitsi meeting join UI |
|
||||
| lib/features/rooms/presentation/rooms_screen.dart | 1.3.0 | 5-tab bottom nav |
|
||||
|
||||
### Server configuration
|
||||
- **COOP/COEP headers** added to ~/public_html/app2.m8chat.au/.htaccess
|
||||
- Synapse 1.151.0 on chat.m8chat.au (PostgreSQL, SQLite was wrong assumption)
|
||||
- LiveKit 1.10.1 on chat.m8chat.au
|
||||
- lk-jwt-service for MatrixRTC JWT at /_matrix/livekit/jwt/sfu/get
|
||||
|
||||
### Known technical debt
|
||||
- call_e2ee.dart imported but E2EE interop with Element X not verified
|
||||
- secure_storage.dart exists but device ID save/load is unused (removed to fix keys/upload 400)
|
||||
- key_restore_dialog.dart is separate from security_setup_dialog.dart — could be consolidated
|
||||
- Rooms provider rebuilds too frequently (every sync tick)
|
||||
71
help4bis-claude-notes/decisions.md
Normal file
71
help4bis-claude-notes/decisions.md
Normal file
@@ -0,0 +1,71 @@
|
||||
### 2026-04-10 18:00 — Enable Olm E2EE in web build
|
||||
- **Decision:** Re-enabled Olm encryption in index.html with synchronous load + Olm.init() before Flutter boots, graceful fallback if Olm fails
|
||||
- **Rationale:** 45 of 88 rooms have Megolm encryption. MatrixSdkDatabase persists Olm keys in IndexedDB resolving /keys/upload 400 errors
|
||||
- **Files affected:** web/index.html, lib/main.dart, app_config.dart, auth_repository.dart, pubspec.yaml
|
||||
- **Status:** Working — device keys uploaded, messages encrypt/decrypt correctly
|
||||
|
||||
### 2026-04-10 17:25 — Deploy target is app2.m8chat.au NOT app.m8chat.au
|
||||
- **Decision:** app.m8chat.au = PRODUCTION (old FluffyChat). app2.m8chat.au = dev/test for m8chat-app2
|
||||
- **Rationale:** User corrected after accidental production deploy. Production restored from backup.
|
||||
- **Status:** All future deploys to app2.m8chat.au
|
||||
|
||||
### 2026-04-10 17:15 — Lazy-load Jitsi external_api.js
|
||||
- **Decision:** Moved from index.html to dynamic load in jitsi_web_service.dart
|
||||
- **Rationale:** Brave blocks cross-origin scripts at page load
|
||||
- **Status:** Done
|
||||
|
||||
### 2026-04-10 17:10 — Add MessageType.encrypted with lock icon UX
|
||||
- **Files:** message_model.dart, chat_repository.dart, message_bubble.dart, room_preview.dart
|
||||
- **Status:** Done
|
||||
|
||||
### 2026-04-10 17:05 — Fix web metadata to M8Chat branding
|
||||
- **Files:** web/index.html, web/manifest.json
|
||||
- **Status:** Done
|
||||
|
||||
### 2026-04-11 02:00 — Add Jitsi Conference tab to bottom nav
|
||||
- **Decision:** Added 4th tab (videocam icon) to authenticated bottom nav so logged-in users can join Jitsi conferences
|
||||
- **Rationale:** Jitsi join was only accessible on the unauthenticated welcome screen. Logged-in users could never reach it.
|
||||
- **Files affected:** rooms_screen.dart (v1.3.0), conference_tab.dart (new), jitsi_screen.dart (Back→/rooms)
|
||||
- **Status:** Done and deployed
|
||||
|
||||
### 2026-04-11 03:00 — LiveKit E2EE frame encryption attempt
|
||||
- **Decision:** Added CallE2EEManager for m.rtc.encryption_keys to-device key exchange + E2EEOptions on LiveKit Room
|
||||
- **Rationale:** Element X encrypts video frames with AES-GCM. Without decryption, video is scrambled.
|
||||
- **Files affected:** call_e2ee.dart (new), livekit_service.dart (v1.4.0)
|
||||
- **Status:** PARTIALLY WORKING — E2EE worker requires SharedArrayBuffer which needs COOP/COEP headers. Headers added to .htaccess on 2026-04-11. Key exchange protocol (m.rtc.encryption_keys) implemented but interop with Element X NOT YET VERIFIED.
|
||||
|
||||
### 2026-04-11 04:00 — Web auth: fresh login every session (no session persistence)
|
||||
- **Decision:** Removed session restore entirely for web. Every visit requires login. No access token stored.
|
||||
- **Rationale:** Security — web app runs on untrusted/shared devices. Can't assume same user. Different from future APK which will persist sessions.
|
||||
- **Files affected:** auth_notifier.dart (v2.0.0), secure_storage.dart (v2.0.0), auth_repository.dart (v2.0.0), app_config.dart (v2.0.0)
|
||||
- **Status:** Done. Removed StoredCredentials, restoreSession(), storage key constants. Device ID persistence also removed (caused keys/upload 400 because Olm account not persisted).
|
||||
|
||||
### 2026-04-11 04:30 — SSSS + cross-signing + key backup bootstrap
|
||||
- **Decision:** Implemented full security setup dialog using Matrix SDK Bootstrap class
|
||||
- **Rationale:** Users need to create/restore SSSS to decrypt old messages. Replaces "Phase 2" placeholder.
|
||||
- **Files affected:** security_setup_dialog.dart (new), key_restore_dialog.dart (new), profile_screen.dart (v1.4.0)
|
||||
- **Status:** Done. User 'try' successfully ran security setup. Recovery key generated.
|
||||
|
||||
### 2026-04-11 05:00 — Fix authenticated media (Synapse 1.151.0)
|
||||
- **Decision:** Switched from frozen /_matrix/media/v3/download/ to /_matrix/client/v1/media/download/ with access_token query param
|
||||
- **Rationale:** Synapse 1.151.0 froze the old media endpoint. All room avatars returned 404.
|
||||
- **Files affected:** mxc_url.dart (v2.0.0)
|
||||
- **Status:** Done — avatars load correctly now
|
||||
|
||||
### 2026-04-11 06:00 — Add Help tab + Account management info
|
||||
- **Decision:** Added 5th bottom nav tab (Help) with expandable help cards
|
||||
- **Rationale:** Users need in-app guidance for encrypted messages, security setup, account management
|
||||
- **Files affected:** help_tab.dart (new), rooms_screen.dart (v1.3.0)
|
||||
- **Status:** Done. Contains: encrypted messages fix guide, getting started, conference guide, video call issues, account management (links to m8chat.au), privacy statement.
|
||||
|
||||
### 2026-04-11 07:00 — COOP/COEP headers for E2EE workers
|
||||
- **Decision:** Added Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy to .htaccess
|
||||
- **Rationale:** LiveKit E2EE frame encryption uses Web Workers that need SharedArrayBuffer
|
||||
- **Files affected:** .htaccess on app2.m8chat.au (production server)
|
||||
- **Status:** Headers verified active. E2EE re-enabled in code. NOT YET TESTED with a live call.
|
||||
|
||||
### 2026-04-11 07:00 — Fix hangup call termination
|
||||
- **Decision:** Changed _clearCallMemberEvent to send {} instead of {'memberships': []}
|
||||
- **Rationale:** Element X sends {} when ending calls (verified from DB). Our {'memberships': []} wasn't being recognised.
|
||||
- **Files affected:** livekit_service.dart
|
||||
- **Status:** Deployed. NOT YET TESTED.
|
||||
66
help4bis-claude-notes/remaining-work.md
Normal file
66
help4bis-claude-notes/remaining-work.md
Normal file
@@ -0,0 +1,66 @@
|
||||
## Remaining Work — M8Chat App2 (2026-04-11)
|
||||
|
||||
### P0 — Must test immediately (next session)
|
||||
- [ ] **Test video call with E2EE + COOP/COEP** — COOP/COEP headers are now on the server, E2EE is re-enabled in code. Start a call from app2 → Element X mobile. Watch console for:
|
||||
- `[E2EE] Received encryption key(s) from @user` — means key exchange worked
|
||||
- `worker error` — means SharedArrayBuffer still not available (COOP/COEP not working)
|
||||
- Scrambled video — key exchange format mismatch with Element X
|
||||
- [ ] **Test hangup termination** — end call from app2, verify Element X sees call ended
|
||||
- [ ] **If E2EE worker still crashes**: the COOP/COEP headers may break other things (e.g. loading cross-origin resources like Jitsi external_api.js, cached images). Test all features after enabling COEP.
|
||||
|
||||
### P1 — Important fixes
|
||||
- [ ] **Incoming call detection** — MSC3401 state event listener. When Element X starts a call, app2 should show an incoming call UI. Currently nothing happens.
|
||||
- [ ] **Ghost device cleanup** — Each web login creates a new device. Need either: (a) periodic admin API cleanup, (b) logout deletes the device, or (c) cron job to purge old M8Chat devices.
|
||||
- [ ] **Rooms provider performance** — Room list rebuilds on every sync tick (15+ times visible in console). Should debounce or only rebuild on actual changes.
|
||||
- [ ] **Device ID for APK/iOS** — When building native apps, re-enable session persistence and device ID reuse. The secure_storage.dart scaffold exists but is currently neutered for web.
|
||||
|
||||
### P2 — Quality improvements
|
||||
- [ ] **Noto emoji font** — Add NotoColorEmoji font asset to render emoji in room names (currently shows squares)
|
||||
- [ ] **Consolidate key restore dialogs** — key_restore_dialog.dart and security_setup_dialog.dart overlap. The security setup already does key restore.
|
||||
- [ ] **Voice-only calling** — LiveKit supports audio-only but no UI for it yet
|
||||
- [ ] **Cross-signing verification UX** — The Bootstrap flow creates cross-signing keys but there's no UI for verifying other users' devices (emoji comparison)
|
||||
|
||||
### P3 — Future features
|
||||
- [ ] **Push notifications** (Phase 2)
|
||||
- [ ] **Room search** (Phase 2 — placeholder in AppBar)
|
||||
- [ ] **Message reactions** (partial — display works, sending not implemented)
|
||||
- [ ] **File/image upload** (attachment button exists, handler not wired)
|
||||
- [ ] **Read receipts** (partial implementation)
|
||||
|
||||
### Blockers / dependencies
|
||||
- **E2EE video interop** depends on: (1) COOP/COEP working, (2) m.rtc.encryption_keys format matching Element X. If format doesn't match, need to capture what Element X actually sends (check to-device events on Synapse during a test call).
|
||||
- **COEP may break cross-origin loads** — CachedNetworkImage, Jitsi external API, and avatar images from matrix.m8chat.au may fail with `require-corp`. May need `credentialless` instead of `require-corp`, or add `crossorigin` attributes.
|
||||
|
||||
### Commands to resume
|
||||
```bash
|
||||
cd /srv/wp-dev/pwa-sites/m8chat-app2
|
||||
|
||||
# Build
|
||||
flutter build web --release
|
||||
|
||||
# Deploy
|
||||
rsync -avz --delete --exclude='.htaccess' \
|
||||
-e "ssh -i ~/.ssh/m8chat_prod -p 2233" \
|
||||
build/web/ m8chat@app.m8chat.au:~/public_html/app2.m8chat.au/
|
||||
|
||||
# Analyse
|
||||
dart analyze lib/
|
||||
|
||||
# Regenerate Riverpod/Freezed code
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
# Check Synapse DB
|
||||
ssh -i ~/.ssh/m8chat_key -p 2233 m8chat_help4bis@chat.m8chat.au \
|
||||
"PGPASSWORD=kijPt4cPWkoaZk8BVm psql -h localhost -U synapse_user -d synapse"
|
||||
|
||||
# Check deployed .htaccess (COOP/COEP headers)
|
||||
ssh -i ~/.ssh/m8chat_prod -p 2233 m8chat@app.m8chat.au \
|
||||
"cat ~/public_html/app2.m8chat.au/.htaccess"
|
||||
```
|
||||
|
||||
### What next session should start with
|
||||
1. `/catchup` to load these notes
|
||||
2. Test video call: app2 → Element X. Paste console output.
|
||||
3. If E2EE works → commit everything to Gitea
|
||||
4. If E2EE fails → check COEP compatibility issues, may need `credentialless` mode
|
||||
5. If hangup works → move to P1 (incoming call detection)
|
||||
Reference in New Issue
Block a user