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:
-
User clicks sign in inside the Parler desktop app.
-
Desktop opens:
https://parler.melvynx.dev/auth/in-app-sign-in
-
User signs in with Better Auth on the web.
-
Web creates a short-lived device login code.
-
Web redirects to:
parler://auth/callback?code=...
-
Tauri handles the deep link.
-
Desktop exchanges the code for a scoped desktop token.
-
Token is stored securely, preferably OS keychain/credential storage instead of plaintext Tauri settings.
-
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:
- User enables Parler keyboard.
- User taps into a text field in any app.
- User switches to Parler keyboard.
- User taps Parler mic/start.
- Parler app opens and starts a dictation session.
- User returns to the previous app.
- 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:
- Floating bubble above text fields, or
- 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
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.
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, authBase projects to reuse
Web
Create
web-app/fromnowstack-saasand copy/reuse as much as possible:Mobile
Create
mobile-app/fromnowstack-mobilelocated at:/Users/melvynx/Developer/apps/nowts-mobile/mobile-appThis project already includes the right foundation:
Adapt it into Parler Mobile.
Product domains and identifiers
https://parler.melvynx.devparler://parler://auth/callbackparler://dev.melvynx.parlerdev.melvynx.parlerCore product behavior
A signed-in Parler user should be able to:
Authentication model
Use Better Auth everywhere.
Web app
@convex-dev/better-auth.Mobile app
nowstack-mobile.expo-secure-store.Desktop app
The desktop app should not store raw browser cookies. Use an in-app sign-in bridge:
User clicks sign in inside the Parler desktop app.
Desktop opens:
https://parler.melvynx.dev/auth/in-app-sign-inUser signs in with Better Auth on the web.
Web creates a short-lived device login code.
Web redirects to:
parler://auth/callback?code=...Tauri handles the deep link.
Desktop exchanges the code for a scoped desktop token.
Token is stored securely, preferably OS keychain/credential storage instead of plaintext Tauri settings.
Desktop uses the token for audio upload, account status, and library sync.
Web app requirements
Create
web-app/with:nowstack-saas.parler.melvynx.dev./auth/in-app-sign-inroute for desktop login bridge./listen/audio/{publicId}route for public/unlisted listen links./app/libraryroute for the signed-in user's audio library.Listen page
Build
/listen/audio/{publicId}with a premium responsive UI:audio.currentTime.The transcript does not need server-side streaming. Precomputed transcript segments are enough.
Cloud storage requirements
Use Cloudflare R2 for uploaded audio.
nowstack-saas.Suggested Convex data model
Use tables equivalent to these concepts:
audioFilesuserIdpublicIdtitleoriginalFileNamemimeTypedurationMsr2Keyor equivalent R2 object referencetranscriptTexttranscriptSegmentsvisibility:private | unlisted | publicTranscript segment shape:
desktopDevicesuserIddeviceIddeviceNamelastSeenAtrevokedAtdesktopTokensuserIddeviceIddeviceLoginSessionsMobile-related tables as needed
Add tables for:
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:
transcribe-rsinstead of collapsing everything to plain text only./auth/in-app-sign-in.parler://auth/callback.CLI/audio file behavior
Add or prepare the CLI path so it can support:
Minimum expectation:
Mobile app requirements
Create
mobile-app/fromnowstack-mobileand adapt it into Parler Mobile.Mobile Phase 1: app shell and auth
Mobile Phase 2: in-app dictation
Build mobile dictation inside the app first:
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:
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:
Add support for iOS shortcuts later:
Mobile Phase 4: Android “super flow” experience
Android can be more direct than iOS.
Build either:
Prefer bubble first for speed and UX:
Then add true
InputMethodServiceif needed.Android requirements:
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:
“Parler under steroids” feature set
Once the core path works, add premium voice-first features:
Review and verification requirements
This issue requires a full review and verification pass before completion.
Verify web:
web-appboots locally./auth/in-app-sign-inworks./listen/audio/{publicId}works.Verify desktop:
parler://auth/callbackworks.Verify mobile:
mobile-appboots on iOS and Android.Verify quality:
Acceptance criteria
web-appexists and runs as a TanStack Start app based onnowstack-saaspatterns.mobile-appexists and runs as an Expo React Native app based onnowstack-mobilepatterns.parler.melvynx.devis represented in config/env docs./auth/in-app-sign-insupports the desktop login flow.parler://auth/callbackdeep link is handled by the desktop app./listen/audio/{publicId}plays audio and highlights transcript segments by time.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.