personal-ai is the existing Dodo Personal AI Assistant â Phase 1 project: an Expo React Native + TypeScript mobile application backed by Supabase, presented through the existing Midnight Orb visual design. This document specifies the work required to make that existing Phase 1 application genuinely functional and stable â not to rebuild it and not to extend it into Phase 2.
The product intent is a personal AI assistant that a single authenticated user can shape to themselves: they name the assistant (default Dodo), choose its avatar, choose the language it answers in (English, Thanglish, or Auto Detect), and choose how it addresses them (default bro). They keep durable personal records â contacts, tasks, reminders, memories â and hold a persistent conversation with the assistant. Every one of those editable features must actually save, load, and persist in Supabase, isolated per user, and must survive navigation, app restart, and logout/login.
The audience is the existing Phase 1 user of the Dodo Personal AI Assistant on Android and iOS, and the developer maintaining that codebase. The immediate engineering audience is the person fixing the current crash (Cannot find native module 'ExponentAV'), the current TypeError: undefined is not a function unhandled promise rejections, and the current "Something went wrong" / "Could not save" persistence failures.
This document is scoped strictly to the existing Phase 1 project. It preserves the existing UI, navigation, Midnight Orb design, Expo React Native + TypeScript architecture, and Supabase backend, and it does not modify unrelated parts of the project.
The system is a single Expo React Native + TypeScript mobile application (Android and iOS) with a Supabase backend. Supabase is the source of truth for all authenticated user data. The application is delivered as a first-party custom UI with application-owned identity: users self-enroll with email/password (or Google when real OAuth credentials are configured), verify themselves on return, and then work inside protected destinations.
Actors. The only active human actor is the Authenticated App User. Supabase Auth is the identity provider; Supabase Postgres with Row Level Security is the durable data owner; the operating system (Android/iOS) owns microphone and notification permission state; Expo Go / the native runtime owns audio and voice module availability. The deterministic/mock responder is an in-app system process, not a persona.
Accepted current behavior. The user can register, log in, recover a forgotten password, and log out. After authentication, a profile row is created or upserted and loaded at session start. The user can change the assistant name, the assistant avatar, the preferred language, the preferred addressing style, and profile information; each save validates input, writes to Supabase, updates local Zustand state only after a successful response, shows success, and navigates back only after success. The user can add, edit, delete, and list contacts (name, phone, optional email, important-contact status) and toggle Important ON/OFF. The user can create, edit, complete, and delete tasks. The user can create, edit, delete, and complete reminders, with local notification permission used safely when available. The user can save and remove simple personal memories. The user can chat with the assistant, with user and assistant messages displayed correctly, conversation history persisted to Supabase, no duplicate messages, and the user's language and addressing style applied. The Automations screen opens and states that it belongs to Phase 2.
Ownership and exclusions. Audio/voice is migrated from the obsolete expo-av usage to the modern expo-audio implementation compatible with the installed Expo SDK 57; no expo-av import that causes the ExponentAV crash remains. Voice capabilities unsupported in Expo Go degrade gracefully without crashing. Service-role keys are never exposed in the mobile app. Phase 2 capabilities â advanced automation workflows, WhatsApp reading/sending, device control, advanced background wake-word service, driving mode, live web search, live ChatGPT/Google intelligence, and automatic external messaging â are explicitly not implemented in this task; only clean service interfaces are kept so Phase 2 can be added later without rewriting the Phase 1 architecture. The application must not claim that live AI, web search, or WhatsApp integration exists in Phase 1 when it has not been implemented.
Delivery. The product is delivered as the existing first-party Expo React Native application on Android and iOS. There is no separate web product, no provider-hosted assistant surface, and no headless delivery in Phase 1. The Midnight Orb design and the existing navigation structure are preserved; this work fixes behavior, persistence, crash sources, and responsiveness rather than redesigning the product.
Access ownership. Identity is application-owned through Supabase Auth. Anonymous visitors reach Landing, Login, Sign Up, and Account Recovery without an account. Everything else â Home, Assistant, Contacts, Tasks, Reminders, Memory, Settings, Automations â requires login. The anonymous entry interaction (Landing â Login / Sign Up / Account Recovery) is a distinct access boundary from the protected destinations, and a protected destination never owns the interaction that establishes access to itself. Google sign-in remains available as a flow but may stay disabled until real Google OAuth credentials are configured; when the Google provider is unavailable the application must not crash.
Current vs. future boundary. Current: profile and assistant preferences, contacts, tasks, reminders, memory, chat with the deterministic/mock responder, permission handling, persistence, and stability. Future (Phase 2, placeholders only): automation workflows, WhatsApp reading/sending, device control, background wake-word service, driving mode, live web search, live ChatGPT/Google intelligence, and automatic external messaging. The Automations screen exists now only as a Phase 2 placeholder that must open without crashing.
Data boundary. Supabase is the source of truth. Local Zustand state is a mirror updated only after a successful Supabase response, following: UI action â service â Supabase â successful response â update local store â update UI. If the network fails, the user sees the error and no false success is reported. Saved values are never overwritten with defaults after navigation or app restart.
The reference directive for the existing Dodo Personal AI Assistant Phase 1 codebase declares content_source, structure_reference, and feature_reference with authoritative authority. The verified factual entities requested by that directive are the existing project's own artifacts, preserved as follows:
SpeechToTextService, VoiceService, permission layer, audio/voice functions, Supabase methods, Zustand stores, navigation.expo-av usage, ExponentAV native module reference, TypeError: undefined is not a function unhandled promise rejections, "Something went wrong" and "Could not save" persistence failures.No additional factual entities, dates, contacts, links, or media references are asserted by the source beyond these existing project artifacts.
Each requirement below is a distinct story point with provenance, lifecycle facts, and observable acceptance. Provenance is explicit for source-stated behavior, basic_default for accepted defaults, and required_inference for indispensable inferred mechanics.
FR-1 â Work only on the existing Phase 1 project. As an Authenticated App User, I should have the existing Dodo Personal AI Assistant Phase 1 project fixed in place, so that my app becomes functional without being rebuilt. Provenance: explicit. Trigger: developer begins the task. Observable result: the existing UI, navigation, Midnight Orb design, Expo React Native + TypeScript architecture, and Supabase backend are preserved; unrelated parts of the project are not modified; Phase 2 is not started. Failure/recovery: if a change would require rebuilding or touching unrelated areas, it is not made. Continuation: the remaining fixes proceed within the existing structure.
FR-2 â Android and iOS support. As an Authenticated App User, I should be able to use the app on both Android and iOS, so that my platform does not determine whether the app works. Provenance: explicit. Trigger: app launch on either platform. Observable result: code paths are compatible with both Android and iOS. Failure/recovery: platform-specific failures are surfaced clearly rather than crashing. Continuation: the user continues using the app on their platform.
FR-3 â Remove the ExponentAV crash. As an Authenticated App User, I should no longer see Cannot find native module 'ExponentAV', so that the app starts and runs. Provenance: explicit. Trigger: app launch or any code path that previously loaded expo-av. Observable result: no expo-av import remains that causes the crash; the entire project is searched for expo-av and ExponentAV and obsolete usage is removed. Failure/recovery: any remaining reference is found and removed. Continuation: audio/voice code runs through the migrated implementation.
FR-4 â Migrate audio/voice to expo-audio for Expo SDK 57. As an Authenticated App User, I should have the required audio/voice code running on the modern expo-audio implementation compatible with the installed Expo SDK 57, so that voice features work on the supported stack. Provenance: explicit. Trigger: any audio or voice operation. Observable result: SpeechToTextService, VoiceService, permissions, imports, package dependencies, and related files are updated as required; the expo-audio implementation and package compatibility are verified. Failure/recovery: incompatible usage is corrected rather than suppressed. Continuation: voice operations proceed through the migrated services.
FR-5 â Graceful Expo Go voice fallback. As an Authenticated App User, I should have voice capabilities that are unsupported in Expo Go handled gracefully, so that the app never crashes because of an unsupported voice capability. Provenance: explicit. Trigger: a voice capability is requested in an environment that does not support it. Observable result: the app reports the limitation clearly and continues running. Failure/recovery: the unsupported path is detected and handled without a crash. Continuation: the user continues with the remaining app functionality.
FR-6 â Fix TypeError: undefined is not a function. As an Authenticated App User, I should no longer encounter TypeError: undefined is not a function unhandled promise errors, so that the app behaves predictably. Provenance: explicit. Trigger: the code path that previously produced the error. Observable result: the actual undefined function is found and its source is fixed rather than the error being hidden. Failure/recovery: the root cause is corrected at its source. Continuation: the affected operation completes normally.
FR-7 â Audit service imports, exports, Supabase methods, Zustand stores, navigation, permissions, audio and voice functions. As an Authenticated App User, I should have all service imports, exports, Supabase methods, Zustand stores, navigation, permissions, audio and voice functions audited, so that broken wiring no longer causes failures. Provenance: explicit. Trigger: audit performed as part of the fix. Observable result: broken imports, exports, and method references are identified and corrected. Failure/recovery: each broken reference is fixed at its source. Continuation: the audited layers operate consistently.
FR-8 â All Phase 1 editable features actually save, update, load and persist. As an Authenticated App User, I should have every Phase 1 editable feature actually save, update, load and persist, so that "Something went wrong" and "Could not save" no longer appear for valid edits. Provenance: explicit. Trigger: any edit to a Phase 1 feature. Observable result: the complete persistence flow works end to end. Failure/recovery: failures are surfaced with clear, actionable errors. Continuation: the saved value is visible and remains after navigation and restart.
FR-9 â Supabase as source of truth with per-user isolation. As an Authenticated App User, I should have Supabase be the source of truth for my authenticated data, isolated to me using auth.uid() and proper RLS policies, so that my data is durable and private. Provenance: explicit. Trigger: any read or write of user data. Observable result: data is read from and written to Supabase under the authenticated user's identity. Failure/recovery: unauthorized or failed access is rejected and surfaced clearly. Continuation: the user's own data remains correct and isolated.
FR-10 â Correct user-based CRUD policies. As an Authenticated App User, I should have profiles, conversations, messages, memories, tasks, reminders and contacts covered by correct user-based CRUD policies, so that each table enforces my ownership. Provenance: explicit. Trigger: any CRUD operation on those tables. Observable result: policies are verified for each table. Failure/recovery: incorrect policies are corrected. Continuation: CRUD operations succeed only for the owning user.
FR-11 â Never expose service-role keys in the mobile app. As an Authenticated App User, I should have the mobile app never expose service-role keys, so that my data cannot be accessed through a leaked privileged key. Provenance: explicit. Trigger: app build and runtime. Observable result: no service-role key is present in the mobile app. Failure/recovery: any exposed key is removed. Continuation: the app operates with the appropriate non-privileged credentials.
FR-12 â Profile created after registration/login and loaded at session start. As an Authenticated App User, I should have my profile data created correctly after registration/login and loaded when the app starts, so that my saved values are available immediately. Provenance: explicit. Trigger: successful registration or login; app start with an authenticated session. Observable result: the profile row exists and is loaded. Failure/recovery: profile creation or load failure is surfaced clearly and retried. Continuation: the loaded profile drives the app's displayed values.
FR-13 â Do not overwrite saved values with defaults. As an Authenticated App User, I should have my saved values preserved rather than reset to defaults after navigation or app restart, so that my configuration is stable. Provenance: explicit. Trigger: navigation or app restart. Observable result: saved values remain in place. Failure/recovery: any accidental default substitution is corrected. Continuation: the user sees their saved configuration.
FR-14 â Assistant name fully functional. As an Authenticated App User, I should be able to change the assistant name from the default Dodo to any name such as Friday, so that the assistant is named the way I want. Provenance: explicit. Trigger: the user edits the assistant name and saves. Observable result: after saving, the new name immediately appears on Home, Assistant, greetings and all relevant screens; the value persists after app restart and logout/login; the value belongs only to that user. Failure/recovery: a failed save keeps the user on the screen with a useful error. Continuation: the new name is used everywhere the assistant is referenced.
FR-15 â User profile stores the required fields. As an Authenticated App User, I should have my profile store user id, display name, email, assistant name, assistant avatar, preferred language and preferred addressing style, so that all personalization is durable. Provenance: explicit. Trigger: profile creation and profile load at session start. Observable result: all listed fields are stored and loaded from Supabase when the authenticated session starts. Failure/recovery: missing or failed fields are surfaced and retried. Continuation: the loaded values drive the app.
FR-16 â Language selection fully functional. As an Authenticated App User, I should be able to select English, Thanglish, or Auto Detect, so that the assistant answers in the language I want. Provenance: explicit. Trigger: the user selects a language. Observable result: English mode responds in English; Thanglish mode responds naturally in Tamil written using English letters; Auto Detect replies in English when the user speaks/types English and Thanglish when the user speaks/types Thanglish; the selected language persists per user. Failure/recovery: a failed save keeps the user on the screen with a useful error. Continuation: subsequent responses follow the selected mode.
FR-17 â Explicit language override phrases. As an Authenticated App User, I should have "Thanglish la sollu" trigger a Thanglish reply and "English la sollu" trigger an English reply, so that I can switch language mid-conversation. Provenance: explicit. Trigger: the user says or types either phrase. Observable result: the assistant replies in the requested language. Failure/recovery: an unrecognized phrase leaves the current mode unchanged. Continuation: the conversation continues in the requested language.
FR-18 â Time-based greetings. As an Authenticated App User, I should receive greetings that depend on the current time â morning, afternoon, evening, or night â so that the assistant greets me appropriately. Provenance: explicit. Trigger: Home or greeting rendering. Observable result: the correct time bucket is selected; in Thanglish mode the greeting can be like "Hi bro\x20\xf0\x9f\x91\x8b Good afternoon, Balaji! Naan Dodo. Unakku enna help pannanum?" and in English mode it can be like "Hi Balaji! Good afternoon. How may I help you?". Failure/recovery: an unavailable time source falls back to a neutral greeting without crashing. Continuation: the greeting renders with the persisted name, assistant name, language, and addressing style.
FR-19 â Addressing style defaults to "bro". As an Authenticated App User, I should have the assistant default to addressing me as bro, so that the default tone is familiar. Provenance: basic_default. Trigger: first use without a saved addressing style. Observable result: the assistant uses "bro". Failure/recovery: a failed load does not silently change the saved style. Continuation: the default applies until the user changes it.
FR-20 â Follow the user's natural addressing word. As an Authenticated App User, I should have the assistant follow the word I naturally use â "bro", "mama", or "macha" â in subsequent responses, so that the assistant matches how I speak. Provenance: explicit. Trigger: the user calls the assistant "bro", "mama", or "macha" (for example "Hi mama"). Observable result: the assistant responds naturally using that word and does not randomly mix bro, mama and macha; the preferred style is saved where appropriate. Failure/recovery: an unrecognized word leaves the current style unchanged. Continuation: subsequent responses use the followed word.
FR-21 â Assistant avatar selection functional. As an Authenticated App User, I should be able to select an assistant avatar from the existing bundled avatars â AI Orb, Friendly AI, Futuristic, Minimal, Robot â so that the assistant looks the way I want. Provenance: explicit. Trigger: the user selects an avatar. Observable result: the UI updates immediately and the selection is saved to Supabase; the selection persists after restart and login; each user's avatar is independent. Failure/recovery: a failed save keeps the user on the screen with a useful error. Continuation: the selected avatar renders on Home and all relevant screens.
FR-22 â Contacts fully functional. As an Authenticated App User, I should be able to add, edit, delete and list contacts storing contact name, phone number, optional email and important-contact status (for example Amma, phone number, Important ON), so that my contacts are durable. Provenance: explicit. Trigger: the user adds, edits, deletes, lists, or toggles Important on a contact. Observable result: on Save the fields are validated, the contact is saved to Supabase, success is shown, the list refreshes, and the contact persists after restart; editing, deleting and Important ON/OFF also work; the current contact save error is fixed; fake local-only contact data is not used as the final source of truth. Failure/recovery: validation and network errors are shown clearly and the user stays on the form with input preserved. Continuation: the refreshed list shows the persisted contact.
FR-23 â Tasks fully functional in Phase 1. As an Authenticated App User, I should be able to create, edit, complete and delete tasks, so that my tasks are durable. Provenance: explicit. Trigger: the user creates, edits, completes, or deletes a task. Observable result: all task data is persisted in Supabase and isolated by authenticated user; loading, empty and error states are shown correctly. Failure/recovery: failures are shown clearly without false success. Continuation: the list reflects the persisted state.
FR-24 â Reminders functional in Phase 1 where supported. As an Authenticated App User, I should be able to create, edit, delete and complete reminders, so that my reminders are durable. Provenance: explicit. Trigger: the user creates, edits, deletes, or completes a reminder. Observable result: reminders are persisted in Supabase; if local notification permission is available it is used safely; if permission is denied the app does not crash and the reminder data is still saved. Failure/recovery: denied permission or network failure is shown clearly with the reminder data preserved. Continuation: the reminder remains in the list.
FR-25 â Memory functional. As an Authenticated App User, I should be able to save and remove simple personal preferences such as "Call me bro", "My assistant name is Dodo" and "I prefer Thanglish", so that the assistant remembers my preferences. Provenance: explicit. Trigger: the user saves or removes a memory. Observable result: memories are persisted in Supabase and one user can never see another user's memories. Failure/recovery: failures are shown clearly. Continuation: the memory list reflects the persisted state.
FR-26 â Assistant Chat reliable. As an Authenticated App User, I should have a reliable chat with the assistant, so that my conversation is usable and durable. Provenance: explicit. Trigger: the user sends a message. Observable result: the existing deterministic/mock responder may remain for Phase 1 if no live AI API is connected; user messages and assistant responses display correctly; conversation history persists to Supabase and remains after app restart; duplicate messages are avoided; loading and error states are handled; the user's language and addressing style are applied. Failure/recovery: send or load failures are shown clearly with no false success and no duplicate insertion. Continuation: the conversation continues from the persisted history.
FR-27 â No false Phase 1 capability claims. As an Authenticated App User, I should not be told that live AI, web search or WhatsApp integration exists in Phase 1 when it has not been implemented, so that I am not misled. Provenance: explicit. Trigger: any in-app statement about capabilities. Observable result: no such claim is made. Failure/recovery: incorrect claims are removed. Continuation: the app describes only what it does.
FR-28 â All Settings screens functional. As an Authenticated App User, I should have assistant name, language, avatar, profile information and addressing style save correctly from Settings, so that my preferences are durable. Provenance: explicit. Trigger: the user presses Save on a Settings screen. Observable result: input is validated, Supabase is updated, local Zustand/store state is updated, success is shown, and navigation back occurs only after successful saving. Failure/recovery: if Supabase fails, the user stays on the current screen and sees a useful error instead of silently losing the change. Continuation: the saved value is reflected across the app.
FR-29 â Keep Email/Password login, registration, forgot password and Google login flow. As an Authenticated App User, I should keep email/password login, registration, forgot password and the Google login flow, so that I can access my account the way I already do. Provenance: explicit. Trigger: the user uses any of these flows. Observable result: the flows remain available; profile creation works safely after authentication; the Google provider may remain disabled until real Google OAuth credentials are configured, but the application must not crash when the Google provider is unavailable. Failure/recovery: an unavailable Google provider is reported clearly without a crash. Continuation: the user can still use email/password access.
FR-30 â Permission layer for microphone and notifications. As an Authenticated App User, I should have microphone and notification permissions handled according to the actual Android/iOS APIs, so that permission states are truthful and never crash the app. Provenance: explicit. Trigger: a microphone or notification permission check or request. Observable result: allowed, denied, temporary/limited and permanently denied states are handled according to the actual OS APIs; no permission option the OS does not provide is promised; permission errors never crash the application. Failure/recovery: denied or permanently denied states are explained with actionable guidance. Continuation: the user can continue using the app without the denied capability.
FR-31 â Midnight Orb UI responsive across device sizes. As an Authenticated App User, I should have the current Midnight Orb UI responsive on small Android phones, large Android phones, small iPhones and large iPhones, so that the app is usable on my device. Provenance: explicit. Trigger: rendering on any supported device size. Observable result: safe-area issues, keyboard overlap, bottom-tab overlap, text overflow, fixed-width problems and content clipping are fixed using responsive layouts and safe-area insets correctly. Failure/recovery: layout defects are corrected rather than worked around. Continuation: the user navigates and edits without obstruction.
FR-32 â Fix every unhandled promise rejection. As an Authenticated App User, I should have every async operation wrapped with proper try/catch handling and useful developer logging, so that failures are handled rather than crashing. Provenance: explicit. Trigger: any async operation. Observable result: errors are caught with useful developer logging; errors are not hidden with a generic catch; user-facing errors are clear and actionable. Failure/recovery: the specific failure is identified and handled. Continuation: the user can retry or continue.
FR-33 â Zustand and Supabase consistency flow. As an Authenticated App User, I should have local Zustand state and Supabase state kept consistent using the flow UI action â service â Supabase â successful response â update local store â update UI, so that what I see reflects what is saved. Provenance: explicit. Trigger: any state-changing action. Observable result: local state is updated only after a successful Supabase response; fake local state is not used to pretend data was saved; if the network fails, the error is shown and no false success is reported. Failure/recovery: the error is surfaced and the local state is not falsely advanced. Continuation: the user can retry the action.
FR-34 â Phase 2 features remain placeholders only. As an Authenticated App User, I should have Phase 2 features remain placeholders, so that Phase 1 stays stable and scoped. Provenance: explicit. Trigger: any Phase 2 capability area. Observable result: advanced automation workflows, WhatsApp reading/sending, device control, advanced background wake-word service, driving mode, live web search, live ChatGPT/Google intelligence and automatic external messaging are not implemented in this task; clean service interfaces are kept so Phase 2 can be added later without rewriting the Phase 1 architecture; the Automations screen may show that it belongs to Phase 2 but must open without crashing. Failure/recovery: any attempt to implement Phase 2 behavior is not made. Continuation: Phase 1 remains the delivered scope.
FR-35 â Zero TypeScript errors and verified audio compatibility. As an Authenticated App User, I should have the project pass npx tsc --noEmit with zero TypeScript errors and verified expo-audio compatibility, so that the codebase is sound. Provenance: explicit. Trigger: running npx tsc --noEmit and the project-wide search for expo-av and ExponentAV. Observable result: zero TypeScript errors; no obsolete expo-av/ExponentAV usage remains; the expo-audio implementation and package compatibility are verified. Failure/recovery: each reported error is fixed at its source. Continuation: the verified build proceeds.
FR-36 â Verification of the full Phase 1 test matrix. As an Authenticated App User, I should have the full Phase 1 test matrix verified, so that the fixes are proven. Provenance: explicit. Trigger: running the verification pass. Observable result: registration, login, logout, login again, assistant name change, language change, avatar change, add/edit/delete contact, Important contact toggle, create/complete/delete task, create/edit/delete reminder, save/remove memory, send chat message, app restart and persistence are tested; Supabase RLS and user isolation are verified; no unhandled promise rejections are present; Android and iOS compatible code paths are verified. Failure/recovery: any failing item is fixed and retested. Continuation: the verified Phase 1 build is delivered.
FR-37 â Concise final report. As an Authenticated App User, I should receive a concise report at the end, so that I know what changed. Provenance: explicit. Trigger: completion of the fixes. Observable result: the report contains files changed, bugs fixed, Supabase changes, audio changes, tests performed and any remaining genuine Phase 1 limitations. Failure/recovery: missing items are added. Continuation: the report closes the task.
FR-38 â Self-service enrollment and returning verification. As an Authenticated App User, I should be able to enroll myself and verify myself on return before reaching protected destinations, so that my private durable records are bound to me. Provenance: required_inference. Trigger: first use without an account; later use with an existing account. Observable result: the anonymous entry interaction (Landing â Login / Sign Up / Account Recovery) establishes access, and protected destinations remain unavailable until identity is established. Failure/recovery: failed enrollment or verification is shown clearly with retry. Continuation: the user reaches the protected experience.
FR-39 â Profile creation or upsert after authentication and profile loading at session start. As an Authenticated App User, I should have my profile created or upserted after authentication and loaded at session start, so that my personalization is available from the first screen. Provenance: required_inference. Trigger: successful authentication; app start with an existing session. Observable result: the profile row exists and is loaded before personalized content renders. Failure/recovery: failure is surfaced and retried. Continuation: the loaded profile drives Home, Assistant, and Settings.
FR-40 â Supabase auth.uid()-based RLS for all user tables. As an Authenticated App User, I should have auth.uid()-based RLS on profiles, conversations, messages, memories, tasks, reminders and contacts, so that my rows are only reachable by me. Provenance: required_inference. Trigger: any query against those tables. Observable result: rows are scoped to the authenticated user. Failure/recovery: unauthorized access is rejected. Continuation: the user's own data operations succeed.
FR-41 â Backend persistence confirmation before local state update or success reporting. As an Authenticated App User, I should have local Zustand state updated and success reported only after backend persistence is confirmed, so that I am never shown a false success. Provenance: required_inference. Trigger: any save action. Observable result: the local store and UI advance only after Supabase confirms. Failure/recovery: on failure the user stays put with a useful error. Continuation: the user can retry.
FR-42 â Microphone and notification permission checks with safe denied and unsupported handling. As an Authenticated App User, I should have microphone and notification permission checks that handle denied and unsupported states safely, so that the app never crashes on permission outcomes. Provenance: required_inference. Trigger: a permission check or request. Observable result: denied and unsupported outcomes are handled without a crash and without promising unavailable options. Failure/recovery: the user is told what is unavailable and can continue. Continuation: the remaining functionality stays usable.
FR-43 â Voice/audio capability detection compatible with Expo SDK 57 and graceful Expo Go fallback. As an Authenticated App User, I should have voice/audio capability detection compatible with Expo SDK 57 and a graceful Expo Go fallback, so that voice features degrade instead of crashing. Provenance: required_inference. Trigger: a voice/audio capability is requested. Observable result: capability is detected and the fallback path is used when unsupported. Failure/recovery: the unsupported path is reported clearly. Continuation: the user continues without the unsupported capability.
Product context. The Authenticated App User is the single active human role in this Phase 1 personal AI assistant. They use the existing Dodo Personal AI Assistant on Android or iOS, presented through the Midnight Orb design. They arrive either as a new user creating an account or as a returning user verifying themselves, and they work inside protected destinations where their own durable records live.
Primary goal. To have a personal assistant that is genuinely theirs â named the way they want, speaking the language they want, addressing them the way they speak â and to have every editable Phase 1 feature actually save, load, and persist across navigation, app restart, and logout/login, with their data isolated to their own account.
Distinct accepted responsibilities. This role is not a generic "user of an app." Their work is specifically the recurring act of editing and saving Phase 1 features and confirming persistence. They:
Relevant inputs or decisions. Their inputs are the profile fields (display name, email, assistant name, assistant avatar, preferred language, preferred addressing style), contact fields, task fields, reminder fields, memory text, and chat messages. Their decisions are which name, avatar, language, and addressing style to use; which contacts are important; which tasks and reminders are complete; which memories to keep; and whether to grant microphone and notification permissions.
Interactions with other accepted participants. The role interacts with Supabase Auth for enrollment and returning verification, with Supabase Postgres for durable storage of their own rows, with the deterministic/mock responder for chat replies, and with the Android/iOS permission system for microphone and notification access. The role never interacts with another user's data, and no other human participant is affected by their work.
Observable success. Every Phase 1 editable feature saves, loads, and persists correctly; the app no longer crashes on audio/voice or unhandled promise errors; saved values are not overwritten with defaults after navigation or app restart; the Midnight Orb UI works responsively on small and large Android phones and small and large iPhones; and the user's data remains isolated to their own account.
Source-backed constraints. The role works only within the existing Phase 1 project; Phase 2 capabilities are not available to them in this task; the Google provider may be unavailable until real OAuth credentials are configured; voice capabilities unsupported in Expo Go are unavailable but must not crash the app; and notification-dependent reminder behavior depends on the OS permission outcome.
The user has not supplied a new palette, font, or brand specification for this task; the binding visual constraint is to preserve the existing Midnight Orb design. The tokens below are the coherent, accessible defaults that express that preserved direction. They are labeled as defaults and do not introduce new product behavior.
Theme name: Midnight Orb (preserved).
Mode: Dark-first, with the Midnight Orb as the single luminous focal element against a deep night field.
Color tokens (exact hex by role):
| Role | Token | Hex |
|---|---|---|
| App background (deep night) | bg.base | #070B18 |
| Elevated surface | bg.surface | #0E1428 |
| Raised surface / card | bg.raised | #151C36 |
| Hairline border | border.subtle | #232C4D |
| Primary text | text.primary | #F2F5FF |
| Secondary text | text.secondary | #A9B4D6 |
| Muted text | text.muted | #6E7AA3 |
| Orb core (primary accent) | accent.orb | #7C5CFF |
| Orb glow (secondary accent) | accent.glow | #3FD0FF |
| Success | state.success | #3DDC97 |
| Error | state.error | #FF6B81 |
| Warning | state.warning | #FFC46B |
| Important contact marker | state.important | #FFB020 |
Typography. Heading family: Inter (or the platform system sans as fallback). Body family: Inter. Type scale: display 32/38, title 24/30, heading 20/26, body 16/24, label 14/20, caption 12/16. Weights: 700 for display and title, 600 for heading and label, 400 for body and caption.
Radius and shape language. Orb: fully circular. Cards and sheets: 20px radius. Inputs and buttons: 14px radius. Chips and toggles: pill (999px). The shape language stays soft and rounded to match the orb motif.
Spacing rhythm. 4px base unit; scale 4, 8, 12, 16, 24, 32, 48. Screen horizontal padding 16px on small devices and 24px on large devices. Vertical rhythm between sections 24px.
Imagery style. The Midnight Orb is the signature image: a luminous sphere with a soft outer glow, rendered against the deep night field, with the bundled assistant avatars (AI Orb, Friendly AI, Futuristic, Minimal, Robot) presented as circular variants of the same motif. No stock photography, no generic gradient hero, and no indigo-on-white template look.
Accessibility. Primary text on bg.base and bg.surface meets contrast requirements; error and success colors are paired with text labels, not color alone.
Concept: "The Orb Answers."
The public entry (Landing) is composed around the Midnight Orb as the single focal subject. The orb sits centered in the deep night field, rendered in accent.orb with an accent.glow halo, and it is the visual anchor that the rest of the composition orbits.
Around the orb, the accepted Phase 1 identity of the product is stated plainly: the assistant can be named (default Dodo), given an avatar, taught a language (English, Thanglish, Auto Detect), and taught how to address the user (default bro). Below the orb, two access controls sit in the thumb-reachable lower third: a primary Sign Up control and a secondary Login control, with Account Recovery as a quiet tertiary link.
The signature move is that the orb is the same object the user will see again on Home and Assistant â the entry does not invent a separate mascot. The bundled avatars (AI Orb, Friendly AI, Futuristic, Minimal, Robot) are previewed as small circular satellites of the main orb, communicating that the assistant's appearance is the user's choice without adding any new capability.
This concept only recomposes accepted content, states, and controls. It introduces no new behavior, page, or destination.
No CREATIVE DIRECTION block was supplied for this task, and the binding instruction is to preserve the existing Midnight Orb design. The tempo below is chosen for the product's audience â a personal assistant used in short, frequent, low-friction sessions on a phone â and is stated with its rationale.
Interaction Model: Animated Motion Tempo: restrained Hero Dimensionality: layered_2d
Rationale for tempo. The audience opens this app many times a day for quick edits and short chats. A restrained tempo keeps the Midnight Orb feeling alive without adding latency or distraction to save-and-confirm interactions, which are the core of this task.
Landing Hero Motion Brief
accent.orb with an accent.glow halo against bg.base.NFR-1 â Platform compatibility. The app must work on both Android and iOS, with code paths verified for each. Provenance: explicit. Rationale: the source requires both platforms.
NFR-2 â Device responsiveness. The Midnight Orb UI must be responsive for small Android phones, large Android phones, small iPhones and large iPhones, with safe-area insets applied correctly and no keyboard overlap, bottom-tab overlap, text overflow, fixed-width problems, or content clipping. Provenance: explicit. Rationale: the source requires responsive layouts and correct safe-area insets.
NFR-3 â Type safety. npx tsc --noEmit must report zero TypeScript errors. Provenance: explicit. Rationale: the source requires a clean type check after all fixes.
NFR-4 â Crash elimination. The Cannot find native module 'ExponentAV' crash must be eliminated by removing obsolete expo-av usage, and the TypeError: undefined is not a function unhandled promise errors must be fixed at their source. Provenance: explicit. Rationale: the source names both as current defects.
NFR-5 â Audio stack compatibility. Audio/voice code must use the modern expo-audio implementation compatible with the installed Expo SDK 57, with package compatibility verified. Provenance: explicit. Rationale: the source specifies Expo SDK 57 and expo-audio.
NFR-6 â Graceful degradation. Voice capabilities unsupported in Expo Go, and notification permission denial, must degrade gracefully without crashing the app. Provenance: explicit. Rationale: the source requires graceful handling in both cases.
NFR-7 â Data isolation and security. Supabase must be the source of truth for authenticated user data, with per-user isolation using auth.uid() and proper RLS policies on profiles, conversations, messages, memories, tasks, reminders and contacts; service-role keys must never be exposed in the mobile app. Provenance: explicit. Rationale: the source requires user isolation and key safety.
NFR-8 â Error handling discipline. Every async operation must have proper try/catch handling and useful developer logging; errors must not be hidden with a generic catch; user-facing errors must be clear and actionable; no unhandled promise rejections may remain. Provenance: explicit. Rationale: the source requires this discipline explicitly.
NFR-9 â State consistency. Local Zustand state and Supabase state must remain consistent using the flow UI action â service â Supabase â successful response â update local store â update UI; fake local state must not be used to pretend data was saved; network failure must show an error and must not report false success. Provenance: explicit. Rationale: the source specifies this flow as a requirement.
NFR-10 â Permission truthfulness. Microphone and notification permission handling must reflect the actual Android/iOS APIs, including allowed, denied, temporary/limited and permanently denied states, and must not promise options the OS does not provide. Provenance: explicit. Rationale: the source requires truthful permission handling.
NFR-11 â Scope discipline. Only the existing Phase 1 project may be modified; unrelated parts of the project must not be modified; Phase 2 must not be started. Provenance: explicit. Rationale: the source states this as a hard constraint.
NFR-12 â Phase 2 extensibility. Clean service interfaces must be kept so Phase 2 can be added later without rewriting the Phase 1 architecture. Provenance: explicit. Rationale: the source requires forward-compatible interfaces without implementing Phase 2.
NFR-13 â Honest capability reporting. The app must not claim that live AI, web search, or WhatsApp integration exists in Phase 1 when it has not been implemented. Provenance: explicit. Rationale: the source prohibits false capability claims.
Source-specified choices are preserved exactly; no substitutions are made.
expo-audio (modern implementation), replacing obsolete expo-av usage. Provenance: explicit.npx tsc --noEmit must report zero errors. Provenance: explicit.No additional frameworks, state libraries, or backend services are introduced by this document.
Assumptions
[Default â not specified by user].Constraints
expo-av import that causes the ExponentAV crash; migrate required audio/voice code to expo-audio compatible with Expo SDK 57. Provenance: explicit.auth.uid() and proper RLS policies. Provenance: explicit.npx tsc --noEmit must report zero TypeScript errors. Provenance: explicit.Future (Phase 2 â not implemented in this task)
These remain out of current scope and out of current page behavior. Only clean service interfaces are kept so they can be added later without rewriting the Phase 1 architecture.
auth.uid().auth.uid() â The Supabase Auth function returning the authenticated user's identifier, used as the ownership key for per-user data isolation.expo-av â The obsolete audio package whose usage causes the ExponentAV native module crash and must be removed.expo-audio â The modern audio implementation compatible with Expo SDK 57, to which the required audio/voice code is migrated.
Your personal assistant, shaped around the way you talk.
A personal assistant you shape to yourself, with records that stay yours. Here is exactly what Phase 1 covers.
The assistant can be named â Dodo by default â and given an avatar from the bundled set (AI Orb, Friendly AI, Futuristic, Minimal, Robot).
It can be taught a language â English, Thanglish, Auto Detect â and taught how to address you, bro by default.
You keep durable personal records â contacts, tasks, reminders, memories â and hold a persistent conversation with the assistant.
Phase 1 scope: live AI, web search, and WhatsApp integration are not implemented yet. Voice and automation capabilities that are not supported on a device degrade safely rather than crashing.

Your personal assistant, shaped around the way you talk.
A personal assistant you shape to yourself, with records that stay yours. Here is exactly what Phase 1 covers.
The assistant can be named â Dodo by default â and given an avatar from the bundled set (AI Orb, Friendly AI, Futuristic, Minimal, Robot).
It can be taught a language â English, Thanglish, Auto Detect â and taught how to address you, bro by default.
You keep durable personal records â contacts, tasks, reminders, memories â and hold a persistent conversation with the assistant.
Phase 1 scope: live AI, web search, and WhatsApp integration are not implemented yet. Voice and automation capabilities that are not supported on a device degrade safely rather than crashing.
No comments yet. Be the first!