Skip to content

Build Parler web audio sharing with Better Auth, Convex, R2, and desktop upload #11

Description

@Melvynx

What to build

Build Parler into a full voice-first product across desktop, web, and mobile.

This is one ambitious vertical feature epic: Parler should become a cross-platform speech-to-text system with local desktop transcription, web audio sharing, mobile dictation, account sync, Cloudflare R2 audio storage, and a Wispr Flow-style mobile experience.

The target product should feel like a premium voice keyboard / dictation platform, not just a simple recording uploader.

High-level architecture

Parler/
  src/                         existing desktop React/Tauri frontend
  src-tauri/                   existing Rust desktop backend
  web-app/                     TanStack Start + Better Auth + Convex + R2
  mobile-app/                  nowstack-mobile adapted into Parler Mobile
  packages/
    parler-contracts/          shared TS contracts: audio, transcript, upload, auth

Base projects to reuse

Web

Create web-app/ from nowstack-saas and copy/reuse as much as possible:

  • TanStack Start
  • Better Auth
  • Convex
  • Cloudflare R2/S3 helpers
  • app providers
  • auth routes
  • env/deploy scripts
  • UI primitives
  • testing/deployment conventions

Mobile

Create mobile-app/ from nowstack-mobile located at:

/Users/melvynx/Developer/apps/nowts-mobile/mobile-app

This project already includes the right foundation:

  • Expo 54
  • React Native 0.81
  • Expo Router
  • Better Auth Expo
  • Convex
  • SecureStore
  • Expo Linking
  • Expo FileSystem
  • R2/S3 SDK packages
  • native prebuild workflow
  • mobile onboarding/auth patterns

Adapt it into Parler Mobile.

Product domains and identifiers

  • Web domain: https://parler.melvynx.dev
  • Deep link scheme: parler://
  • Desktop auth callback: parler://auth/callback
  • Mobile app scheme: parler://
  • Suggested bundle IDs:
    • iOS: dev.melvynx.parler
    • Android: dev.melvynx.parler

Core product behavior

A signed-in Parler user should be able to:

  • Dictate on desktop.
  • Dictate in the mobile app.
  • Upload audio and transcripts to their account.
  • Store MP3 audio on Cloudflare R2.
  • Store metadata and transcript segments in Convex.
  • Open a beautiful web listen page.
  • See synchronized transcript playback.
  • See their library across desktop/web/mobile.
  • Copy/share listen links.
  • Use a mobile dictation workflow that feels close to Wispr Flow.

Authentication model

Use Better Auth everywhere.

Web app

  • Browser session via Better Auth.
  • Convex integration via @convex-dev/better-auth.
  • Protected account/library routes.

Mobile app

  • Better Auth Expo integration from nowstack-mobile.
  • Store sensitive session/token data using expo-secure-store.
  • Use Convex for synced account data.

Desktop app

The desktop app should not store raw browser cookies. Use an in-app sign-in bridge:

  1. User clicks sign in inside the Parler desktop app.

  2. Desktop opens:

    https://parler.melvynx.dev/auth/in-app-sign-in

  3. User signs in with Better Auth on the web.

  4. Web creates a short-lived device login code.

  5. Web redirects to:

    parler://auth/callback?code=...

  6. Tauri handles the deep link.

  7. Desktop exchanges the code for a scoped desktop token.

  8. Token is stored securely, preferably OS keychain/credential storage instead of plaintext Tauri settings.

  9. Desktop uses the token for audio upload, account status, and library sync.

Web app requirements

Create web-app/ with:

  • TanStack Start app based on nowstack-saas.
  • Better Auth configured for parler.melvynx.dev.
  • Convex schema/functions for audio files, desktop devices, desktop tokens, and device login sessions.
  • R2-backed MP3 audio storage.
  • /auth/in-app-sign-in route for desktop login bridge.
  • /listen/audio/{publicId} route for public/unlisted listen links.
  • /app/library route for the signed-in user's audio library.

Listen page

Build /listen/audio/{publicId} with a premium responsive UI:

  • MP3 audio player.
  • Mobile-first layout that still feels native and polished.
  • Desktop layout that feels high-end and purpose-built.
  • Synchronized transcript display.
  • Current segment highlighting based on audio.currentTime.
  • Copy transcript action.
  • Copy share link action.
  • Optional download action if visibility/settings allow it.
  • Proper empty/error states for missing, private, deleted, or unavailable audio.

The transcript does not need server-side streaming. Precomputed transcript segments are enough.

Cloud storage requirements

Use Cloudflare R2 for uploaded audio.

  • Store MP3 audio on R2.
  • Reuse the R2/S3 support already present in nowstack-saas.
  • Convex stores metadata and the R2 reference/key.
  • Access should support private/unlisted/public visibility.
  • Deleting an audio entry should also delete or revoke access to the R2 object.

Suggested Convex data model

Use tables equivalent to these concepts:

audioFiles

  • userId
  • publicId
  • title
  • originalFileName
  • mimeType
  • durationMs
  • r2Key or equivalent R2 object reference
  • transcriptText
  • transcriptSegments
  • visibility: private | unlisted | public
  • timestamps

Transcript segment shape:

{
  start: number;
  end: number;
  text: string;
}

desktopDevices

  • userId
  • deviceId
  • deviceName
  • lastSeenAt
  • revokedAt
  • timestamps

desktopTokens

  • userId
  • deviceId
  • hashed token
  • expiry
  • revoked state
  • timestamps

deviceLoginSessions

  • short-lived login code
  • user id
  • device id / redirect uri
  • expiry
  • consumed state

Mobile-related tables as needed

Add tables for:

  • mobile dictation drafts
  • user dictionary/custom words
  • prompt/tone preferences
  • app settings sync
  • optional saved notes

Keep schema practical. Do not overbuild if a field can wait.

Desktop app requirements

Update the existing Parler/Tauri app so web sharing is actually usable:

  • Preserve timestamped transcript segments from transcribe-rs instead of collapsing everything to plain text only.
  • Store transcript segments in local history.
  • Add signed-in/signed-out account state in settings or account UI.
  • Add sign-in action that opens /auth/in-app-sign-in.
  • Add deep link handling for parler://auth/callback.
  • Add secure desktop token storage.
  • Add upload action for the latest/current recording.
  • Convert/store uploaded audio as MP3 for R2.
  • Save remote URL and upload status in local history.
  • Copy the listen link after upload.
  • Add useful upload error and retry states.

CLI/audio file behavior

Add or prepare the CLI path so it can support:

parler transcribe-file ./audio.mp3 --upload --copy-link

Minimum expectation:

  • MP3 input is supported for upload/share.
  • Audio is uploaded to R2 as MP3.
  • Transcript segments are included.
  • The resulting listen URL is printed and optionally copied.

Mobile app requirements

Create mobile-app/ from nowstack-mobile and adapt it into Parler Mobile.

Mobile Phase 1: app shell and auth

  • Rename/brand nowstack-mobile to Parler.
  • Configure bundle IDs and scheme.
  • Connect Better Auth Expo.
  • Connect Convex.
  • Use SecureStore for sensitive data.
  • Implement core screens:
    • onboarding
    • sign in/sign up
    • library
    • dictate
    • settings
    • account

Mobile Phase 2: in-app dictation

Build mobile dictation inside the app first:

  • Hold-to-talk or tap-to-record mode.
  • Audio recording UI with waveform/state feedback.
  • Transcription cloud path first.
  • Editable transcript result.
  • Copy to clipboard.
  • Save to library.
  • Upload MP3 to R2.
  • Store transcript segments in Convex.
  • Sync with web/desktop library.

This ships value before native keyboard complexity.

Mobile Phase 3: iOS Wispr Flow-style experience

Build an iOS keyboard-adjacent experience similar to Wispr Flow, while respecting iOS constraints.

Architecture:

React Native containing app
  starts microphone session
  records/transcribes
  writes result to shared App Group
  can copy result to clipboard

Native iOS Keyboard Extension (Swift)
  displays Parler mic/start button
  opens app via parler://dictate/start
  reads latest result from App Group
  inserts text through textDocumentProxy when possible

Important: do not assume the keyboard extension itself can freely own microphone recording. The app should own the microphone session, similar to the Flow Session pattern.

Expected iOS UX:

  1. User enables Parler keyboard.
  2. User taps into a text field in any app.
  3. User switches to Parler keyboard.
  4. User taps Parler mic/start.
  5. Parler app opens and starts a dictation session.
  6. User returns to the previous app.
  7. Transcript is inserted by the keyboard when available, or copied to clipboard as fallback.

Add support for iOS shortcuts later:

  • Action Button shortcut.
  • Siri shortcut.
  • Lock screen widget / Live Activity if useful.

Mobile Phase 4: Android “super flow” experience

Android can be more direct than iOS.

Build either:

  1. Floating bubble above text fields, or
  2. Native Android IME keyboard.

Prefer bubble first for speed and UX:

Android overlay / accessibility-assisted bubble
  appears around text fields
  starts recording
  transcribes
  inserts text or copies fallback

Then add true InputMethodService if needed.

Android requirements:

  • Microphone permission.
  • Overlay/display-over-other-apps permission if bubble is used.
  • Accessibility permission if needed for robust text insertion.
  • Clear privacy onboarding.
  • No appearance in password/PIN/banking-sensitive contexts when detectable.

Local mobile models: V2, not first MVP

Do not block the first mobile MVP on local models.

First ship cloud transcription or server-backed transcription.

Then add native local model support:

  • iOS: whisper.cpp via C++/Swift bridge, ONNX Runtime Mobile, or Core ML.
  • Android: whisper.cpp via NDK or ONNX Runtime Mobile.
  • Expose to React Native through a native module / TurboModule.
  • Use quantized tiny/base models first.
  • Add model download/storage management later.

“Parler under steroids” feature set

Once the core path works, add premium voice-first features:

  • Personal dictionary synced across desktop/web/mobile.
  • Custom words and names.
  • Filler word cleanup.
  • Smart punctuation.
  • Tone rewrite presets.
  • “Make this a professional email.”
  • “Turn this into a message.”
  • Prompt mode for ChatGPT/Claude.
  • Fast clipboard dictation.
  • Desktop/mobile/web unified history.
  • Shareable audio transcript links.
  • Private/unlisted/public controls.
  • Local-first mode.
  • Cloud-enhanced mode.
  • Usage limits/paywall later if needed.

Review and verification requirements

This issue requires a full review and verification pass before completion.

Verify web:

  • web-app boots locally.
  • Better Auth works.
  • Convex works.
  • R2 upload works.
  • /auth/in-app-sign-in works.
  • /listen/audio/{publicId} works.
  • Transcript sync follows audio playback.
  • Private/unlisted/public access rules are correct.
  • Library only shows the current user's files.

Verify desktop:

  • Deep link parler://auth/callback works.
  • Code exchange rejects expired/consumed/invalid codes.
  • Desktop token is not stored in plaintext app settings.
  • Desktop preserves transcript segments.
  • Desktop upload stores MP3 in R2.
  • Desktop saves remote URL/upload status locally.
  • Desktop copies listen link.

Verify mobile:

  • mobile-app boots on iOS and Android.
  • Better Auth Expo works.
  • Convex session works.
  • In-app dictation records audio.
  • Mobile upload creates library item.
  • Mobile library syncs with web.
  • iOS keyboard extension proof-of-concept opens the app and returns/copies/inserts result.
  • Android bubble or IME proof-of-concept records and inserts/copies result.

Verify quality:

  • Typecheck/build/test commands pass for touched projects.
  • UI reviewed on mobile and desktop viewports.
  • Privacy-sensitive flows reviewed.
  • App Store/Play Store permission copy is clear.
  • Error states are present.

Acceptance criteria

  • web-app exists and runs as a TanStack Start app based on nowstack-saas patterns.
  • mobile-app exists and runs as an Expo React Native app based on nowstack-mobile patterns.
  • parler.melvynx.dev is represented in config/env docs.
  • Better Auth is wired for web.
  • Better Auth Expo is wired for mobile.
  • Convex is wired for web/mobile/shared app data.
  • Cloudflare R2 is used for MP3 audio storage.
  • /auth/in-app-sign-in supports the desktop login flow.
  • parler://auth/callback deep link is handled by the desktop app.
  • Desktop can exchange a short-lived login code for a scoped token.
  • Desktop can upload MP3 audio + transcript segments and receive a listen URL.
  • Desktop copies the listen URL after upload.
  • /listen/audio/{publicId} plays audio and highlights transcript segments by time.
  • Signed-in users can view their audio library on web.
  • Signed-in users can view their audio library on mobile.
  • Mobile in-app dictation can create an audio/transcript library item.
  • iOS keyboard-extension proof-of-concept exists for launching a Parler dictation session.
  • Android bubble or IME proof-of-concept exists for starting dictation near text fields.
  • Access control prevents cross-user private file access.
  • MP3 upload path is supported.
  • Full review and verification pass is completed before closing.

Notes

Treat this as one large product epic. It can land over multiple PRs if needed, but keep the implementation direction unified: desktop + web + mobile should share the same account, library, audio storage, transcript model, and link system.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions