Hold That Thought — Project Handbook (Flutter · Supabase · OpenAI)
Hold That Thought — Project Handbook (Flutter · Supabase · OpenAI)
App ID: com.holdthatthought
One-liner: Record thoughts (AAC .m4a), store locally + Supabase (DB + Storage), auto-transcribe (OpenAI Whisper), auto-summarize (Edge Function). Dark M3 “glass” UI. Offline-first with durable retries.
1) Architecture
- Flutter/Android: audio record/play; dark M3; glass cards.
- Storage:
- Local app dir for audio.
- Supabase Storage bucket
thoughts-audio
at path<uid>/<clientId>.m4a
. - Supabase Postgres table
thoughts
.
- Auth: Supabase anonymous auth; sessions persist + auto-refresh; all network paths re-ensure anon session.
- Transcription: HTTP Whisper (
Authorization: Bearer <OPENAI_API_KEY>
); offline queue + retries. - Summaries: Edge Function
index
validates JWT; uses service-role client; adopts orphan rows; upsert by(user_id, client_id)
; returns summary. Local OpenAI fallback only if Edge unavailable. - Offline: durable queues (upload + transcription); auto-summary on upload complete; reconnect sweep to backfill.
2) Key Files
Bootstrap/Config
lib/bootstrap.dart
— dotenv;Supabase.initialize
(persistSession/autoRefresh); starts Sync + reconnect sweep + upload→summary listener.lib/core/openai_key.dart
— resolver + masking.lib/core/auth_utils.dart
—ensureSession()
+ensureSignedInUid()
.lib/services/edge_client.dart
— Supabase Functions invoke.
Capture/Transcription/Summary/Sync
lib/pages/capture_page.dart
— capture UI + enqueue upload.lib/services/transcription_service.dart
— Whisper.lib/services/transcription_retry_queue.dart
— backoff + pause/resume.lib/services/upload_service.dart
— queue, event stream, Storage upload.lib/services/sync_service.dart
— upload→summary hook + reconnect sweep + auth hardening.lib/services/summary_service.dart
— Edge-first; strict prompt (return only a 1–2 sentence summary; no chatter).lib/widgets/thought_detail_bottom_sheet.dart
— single Summary button + spinner; persistent summary card; transcript edit pencil in header.lib/repositories/thought_repository.dart
— smart status updates.
Settings/Diagnostics
lib/pages/settings_page.dart
— glass cards; Fix Connection; key paste/validate (restart-safe).
Theme & Build
lib/theme/app_theme.dart
— dark M3.tool/pad_icon.dart
,flutter_launcher_icons
,flutter_native_splash
— launcher/splash.tooling/build_release.ps1
— one-click release pipeline.
Edge/Policies
supabase/functions/index.ts
— CORS; JWT; service client; adopt orphan; upsert (user_id, client_id); returns{id, clientId, summary}
.supabase/policies/rls_thoughts.sql
— RLS forthoughts
.- Storage bucket
thoughts-audio
with per-user RLS: first path segment ==auth.uid()
.
3) Shipped Highlights
- Secrets via
.env
+ secure storage; masked logs. - Anon auth with persisted session; all sync paths re-ensure session.
- Recording to
.m4a
; upload tothoughts-audio/<uid>/<clientId>.m4a
with retry. - Retry queues (401 → pause; resume on key fix); robust offline→online flows.
- SummaryService Edge-first with clean upsert and strict “summary-only” prompt.
- UI polish: single Summary button; spinner; persistent summary card; chips only when true (
✨ Summarized
whensummary.trim().isNotEmpty
). - Diagnostics & key validate; context-safe async; modernized APIs (SharePlus, PopScope, withValues(alpha)).
- Release builds green; Impeller/Vulkan OK.
4) Current Status (Today)
✅ E2E on device: record → upload → auto-transcribe → auto-summary.
✅ Reconnect sweep backfills; badges flow: Local → Uploaded → Transcribed → ✨ Summarized.
✅ Storage + RLS live; DB aligned: summary
, transcript
, client_id
(NOT NULL, unique per user), updated_at
trigger.
5) Next Up
Polish & Perf
- Waveform seek bar; micro-animations for chips.
- (Optional) Storage perf index:
storage.objects (bucket_id, first_segment)
.
Edge telemetry
- Structured logs/metrics for
index.ts
(latency, token usage, failures).
QA
- Long offline sessions; large files; concurrent uploads.
6) Commands
Build & install
flutter clean
flutter pub get
dart run tool/pad_icon.dart 0.97
dart run flutter_launcher_icons
dart run flutter_native_splash:create
flutter build apk --release
adb devices -l
adb -s <ID> install -r build/app/outputs/flutter-apk/app-release.apk
Logs
adb logcat -c
adb logcat *:S flutter:V AndroidRuntime:E ActivityManager:E > app_startup.txt