"Test_ID","Domain","Feature","Scenario","Test_Method","Priority","Platforms","Preconditions","Steps","Expected_Result","Edge_Cases","Assumptions","Automation_Recommendation","automated"
"AUTH-001","Authentication","App start routing","First launch routes to onboarding when hasCompletedOnboarding=false","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Fresh install, no token","Launch app","Onboarding welcome is shown, not login/main tabs","Corrupted local onboarding flag","Onboarding state is persisted locally","Automate (UI smoke)","🟢 testF001_ColdLaunchShowsOnboardingWelcome"
"AUTH-002","Authentication","App start routing","Returning user with onboarding complete and no token routes to login","Manual + E2E UI","P0","iOS, Android, Web, Desktop","hasCompletedOnboarding=true, token missing","Launch app","Login screen shown","Stale cached user object present","Token is source of truth","Automate","🟢 testAppLaunchesAndShowsLoginScreen"
"AUTH-003","Authentication","App start routing","Authenticated + verified user routes to main tabs","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Valid token, verified user","Launch app","Main tab shell displayed","Cached token exists but API fails","Current-user fetch determines validity","Automate","🟢 testR203_validLoginTransitionsToMainAppRoot"
"AUTH-004","Authentication","App start routing","Authenticated but unverified user routes to verify email","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Valid token, verified=false","Launch app","Verify email screen shown","User gets verified between launches","Verification status fetched from backend","Automate","🟢 testR104_verificationGateBlocksMainAppBeforeCodeEntry | testR110_relaunchUnverifiedUserNeverLandsInMainApp"
"AUTH-005","Authentication","Token invalidation","Invalid token at startup clears session and returns to login","Manual + Integration","P0","iOS, Android, Web, Desktop","Expired/invalid token stored","Launch app","Data cleared and login shown","Backend 500 vs 401 behavior","401/failed current-user means logout","Automate","🟢 test08_invalidatedTokenRedirectsToLogin"
"AUTH-006","Authentication","Login","Valid username/password login success","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Existing verified account","Submit login form","Token persisted, lookups initialized, main shown","Slow network during login","Login API returns token+user","Automate","🟢 test02_loginWithValidCredentials | testR202_validCredentialsSubmitFromLogin"
"AUTH-007","Authentication","Login","Invalid credentials shows actionable error","Manual + E2E UI","P0","iOS, Android, Web, Desktop","No session","Submit wrong password","Error shown, user remains on login","Rate-limit or lockout responses","Error parser maps backend errors","Automate","🟢 test01_loginWithInvalidCredentials"
"AUTH-008","Authentication","Login validation","Empty username/password blocked client-side","Manual + UI","P1","iOS, Android, Web, Desktop","No session","Tap login with empty fields","Validation errors shown, no API call","Whitespace-only input","Client validation active","Automate","🟢 testF205_LoginButtonDisabledWhenCredentialsAreEmpty | testF207_LoginScreenShowsAllExpectedElements | testF208_RegisterFormShowsAllRequiredFields"
"AUTH-009","Authentication","Registration","Create account success then verify-email step","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Unique email/username","Submit valid registration","Session established and verify-email screen appears","Existing email conflict","Register API auto-authenticates","Automate","🟢 testR103_successfulRegistrationTransitionsToVerificationGate"
"AUTH-010","Authentication","Registration validation","Invalid email/password formats rejected","Manual + UI","P1","iOS, Android, Web, Desktop","No session","Try invalid email, short password, weak password","User-friendly validation errors","Unicode emails, long usernames","Validation rules are enforced consistently","Automate","🟢 test03_registrationWithEmptyFields | test04_registrationWithInvalidEmail | test06_registrationWithWeakPassword"
"AUTH-011","Authentication","Email verification","Valid 6-digit code verifies account","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged-in unverified user","Enter 6-digit numeric code","Account marked verified and app routes forward","Code already used","Code must be exactly 6 digits","Automate","🟢 testR105_validVerificationCodeTransitionsToMainApp | test07_successfulRegistrationAndVerification"
"AUTH-012","Authentication","Email verification","Non-numeric/short/long code blocked","Manual + UI","P1","iOS, Android, Web, Desktop","On verify-email screen","Enter invalid codes","Verify action disabled or error shown","Pasted with spaces","Code input sanitizes to digits","Automate","🟢 testR107_invalidVerificationCodeShowsErrorAndStaysBlocked | testR109_verifyButtonDisabledForIncompleteCode | test10_verificationCodeFieldValidation | emptyCodeReturnsRequired | wrongLengthReturnsInvalidCode | nonNumericCodeReturnsInvalidCode | validSixDigitCodeReturnsNil | customLengthFourDigitCode | customLengthWrongDigitCount (ValidationRulesTests)"
"AUTH-013","Authentication","Logout","Logout clears token, user data, lookups, and returns to login","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in","Tap logout","Login shown; protected API calls fail without token","Logout API fails network-side","Client clears state even if API call fails","Automate","🟢 test06_logout | testR205_logoutFromMainAppReturnsToLoginRoot"
"AUTH-014","Authentication","Forgot password","Request reset by email success path","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Known account email","Submit forgot-password email","Success message and next step available","Unknown email behavior privacy-safe","Backend may still return generic success","Automate","🟢 test05_forgotPasswordNavigation | testF206_ForgotPasswordButtonIsAccessible | testF209_ForgotPasswordNavigatesToResetFlow"
"AUTH-015","Authentication","Reset code verification","Verify reset code success path","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Reset email submitted","Enter correct code","Reset-token available for password reset","Expired code","Code verification endpoint returns token","Automate","🟢 test03_verifyResetCodeSuccess"
"AUTH-016","Authentication","Password reset","Reset password success with matching confirmation","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Valid reset token","Enter new password + confirm","Password changed; user can log in (or auto-login flow)","Token expires mid-flow","Reset endpoint ignores confirm field","Automate","🟢 test04_resetPasswordSuccessAndLogin"
"AUTH-017","Authentication","Password reset","Mismatched password confirmation blocked","Manual + UI","P1","iOS, Android, Web, Desktop","Reset password screen","Enter mismatch","Inline error; no reset request","Trailing spaces","Client validates before submit","Automate","🟢 mismatchedPasswordsFails | caseSensitiveMismatchFails (ValidationHelpersTests) | matchingPasswordsReturnsNil | mismatchedPasswordsReturnsMismatch | caseSensitiveMismatch (ValidationRulesTests) | requiredFieldErrorDescription | invalidEmailErrorDescription | passwordTooShortErrorDescription | passwordMismatchErrorDescription | passwordMissingLetterErrorDescription | passwordMissingNumberErrorDescription | invalidCodeErrorDescription | invalidUsernameErrorDescription | customMessageErrorDescription (ValidationRulesTests)"
"AUTH-018","Authentication","Deep link reset","Password-reset deep link opens flow with token prefilled","Manual + E2E UI","P0","iOS, Android","Installed app with deep-link support","Open reset deep link","Forgot/reset flow opens and token is consumed","Malformed token in URL","Deep link token can be cleared on back","Automate","🟢 defaultInitStartsAtRequestCode | initWithTokenStartsAtResetPassword | moveToNextStepFromRequestCode | moveToNextStepFromVerifyCode | moveToNextStepFromResetPassword | moveToNextStepFromLoggingIn | moveToNextStepFromSuccessIsNoOp | moveToPreviousStepFromVerifyCode | moveToPreviousStepFromResetPassword | moveToPreviousStepFromRequestCodeIsNoOp | moveToPreviousStepFromLoggingInIsNoOp | moveToPreviousStepFromSuccessIsNoOp | resetClearsAllState | clearErrorNilsOutErrorMessage | clearSuccessNilsOutSuccessMessage | verifyResetCodeWithEmptyCodeSetsError | verifyResetCodeWithNonNumericCodeSetsError | resetPasswordWithEmptyPasswordSetsError | resetPasswordWithWeakPasswordSetsError | resetPasswordWithMismatchedPasswordsSetsError | resetPasswordWithNilTokenSetsError | allCasesHasFiveValues | allCasesContainsExpectedSteps (PasswordResetViewModelTests)"
"AUTH-019","Authentication","SSO Apple","Apple Sign-In success creates or signs in account","Manual + Integration","P1","iOS","Apple-capable test device/simulator","Complete Apple sign-in","Session established; verification state handled","User hides email, first-login only email scope","Apple credential mapped to backend request","Automate partially (mock)",""
"AUTH-020","Authentication","SSO Google","Google Sign-In success path","Manual + Integration","P1","Android, Web, KMP UI","Google sign-in configured","Complete Google sign-in","Session established with backend token","Revoked Google token","Backend validates ID token","Automate partially",""
"ONB-001","Onboarding","Intent split","Start Fresh path goes through value props and name residence","Manual + E2E UI","P0","iOS, Android (KMP)","Fresh install","Choose Start Fresh and continue","Step order matches intended flow","Back navigation at each step","Flow differs by intent","Automate","🟢 testF101_StartFreshFlowReachesCreateAccount | testR002_startFreshFlowReachesCreateAccount"
"ONB-002","Onboarding","Intent split","Join Existing path skips value/name steps and goes to account creation","Manual + E2E UI","P0","iOS, Android (KMP)","Fresh install","Choose Join Existing","Expected condensed step order","User switches intent mid-flow","Intent persisted during onboarding","Automate","🟢 testF102_JoinExistingFlowGoesToCreateAccount | testF105_JoinExistingFlowSkipsValuePropsAndNameResidence"
"ONB-003","Onboarding","Navigation","Back button transitions and step history correctness","Manual + UI","P1","iOS, Android (KMP)","In onboarding multi-step flow","Navigate forward then back","Returns to correct previous step","Back from verify-email triggers logout on iOS","Back behavior is product-defined","Automate","🟢 testF103_BackNavigationFromNameResidenceReturnsToValueProps | testF108_BackFromCreateAccountNavigatesToPreviousStep"
"ONB-004","Onboarding","Skip behavior","Skippable screens skip to next valid state","Manual + UI","P1","iOS, Android (KMP)","On skippable step","Tap Skip","Progress advances without corrupting state","Skip on terminal upsell step completes onboarding","Skip availability is step-dependent","Automate","🟢 testF104_SkipOnValuePropsMovesToNameResidence"
"ONB-005","Onboarding","Residence bootstrap","Start Fresh creates residence automatically after verification","Manual + Integration","P0","iOS, Android (KMP)","Onboarding start-fresh with residence name","Verify email and continue","Residence created or graceful fallback if creation fails","Blank residence name bypasses creation","Creation failure should not hard-block onboarding","Automate","🟢 testF110_startFreshCreatesResidenceAfterVerification"
"ONB-006","Onboarding","Join residence","Join-existing flow joins via share code","Manual + E2E UI","P0","iOS, Android (KMP)","Valid join code","Submit code in onboarding","User added to shared residence","Expired/invalid/reused code","Join code endpoint enforces ownership rules","Automate",""
"ONB-007","Onboarding","First task","First-task onboarding step can create selected tasks","Manual + Integration","P1","iOS, Android (KMP)","On first-task step","Select templates and continue","Tasks created; flow proceeds","Partial task creation failures","At least one success considered success in KMP VM","Automate",""
"ONB-008","Onboarding","Completion persistence","Completing onboarding persists flag and bypasses onboarding next launch","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Completed onboarding once","Restart app","Onboarding is skipped","App data clear resets flag","Onboarding flag stored locally","Automate","🟢 testF111_completedOnboardingBypassedOnRelaunch"
"RES-001","Residences","List","Residences list loads with empty and non-empty states","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in","Open residences tab","Correct list/empty UI shown","Slow API and stale cache","List can come from cache or network","Automate","🟢 test01_viewResidencesList | testR303_residencesListLoadsAfterTabSelection"
"RES-002","Residences","Create","Create residence with required fields only","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in","Fill minimum fields and save","Residence appears in list/detail","Duplicate name allowed/not allowed behavior","Name required; other fields optional","Automate","🟢 test05_createResidenceWithMinimalData | testR306_createResidenceMinimalDataSubmitsSuccessfully"
"RES-003","Residences","Create validation","Prevent submit when required name missing","Manual + UI","P1","iOS, Android, Web, Desktop","Open add residence form","Submit blank name","Validation error, no API call","Whitespace-only name","Required validation trims input","Automate","🟢 test01_cannotCreateResidenceWithEmptyName"
"RES-004","Residences","Create optional fields","All optional numeric/text/address fields persist correctly","Manual + Integration","P1","iOS, Android, Web, Desktop","Open add residence form","Fill all fields and save","Values round-trip correctly in detail/edit","Decimals for bathrooms/lot size","Type conversion preserves precision","Automate","🟢 test12_updateAllResidenceFields"
"RES-005","Residences","Edit","Edit residence updates list and detail views","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Existing residence","Modify fields and save","Updated values shown immediately","Concurrent edit from another user","DataManager updates local caches","Automate","🟢 test11_editResidenceName | test12_updateAllResidenceFields"
"RES-006","Residences","Delete","Delete residence removes related task/document cached subsets","Manual + Integration","P0","iOS, Android, Web, Desktop","Residence with tasks/docs exists","Delete residence","Residence gone; related cached sections removed","Delete primary/only residence","Server cascade semantics documented","Automate","🟢 test02_residenceCRUDFlow"
"RES-007","Residences","Primary residence","Set/retain primary residence behavior","Manual","P2","iOS, Android, Web, Desktop","Multiple residences","Mark one as primary and reload","Only intended residence is primary","Two rapid primary updates","Backend enforces uniqueness","Automate partially","🟢 test18_setPrimaryResidence"
"RES-008","Residences","Summary","Residence summary counts derive from kanban columns correctly","Manual + Integration","P1","iOS, Android, Web, Desktop","Residence with mixed task statuses","Open summary cards","Counts match task column truth","No tasks state","Summary can be client-computed","Automate","🟢 test09_fullFlowSummary | test06_verifyKanbanStructure"
"RES-009","Residences","Join by code","Join residence from manual share code entry","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Valid share code from another account","Enter code in join flow","Membership granted and residence appears","Code expired or already member","Join endpoint returns reasoned errors","Automate",""
"RES-010","Residences","Generate share code","Generate/refresh residence share code","Manual + Integration","P1","iOS, Android, Web, Desktop","Owner access to residence","Generate code","New valid code returned/visible","Repeated generation invalidates old codes","Access limited by role","Automate","🟢 test07_residenceSharingUIElements"
"RES-011","Residences","Share package export","Create residence .casera package and open share sheet","Manual","P1","Android","Residence exists, logged in","Tap share residence","Share sheet opens with file attachment","Filename sanitization with special chars","Backend generates package with shareCode","Automate partially",""
"RES-012","Residences","Share package import","Import .casera residence file joins residence","Manual + Integration","P0","Android","Valid .casera file received","Open file via app/import handler and confirm","Join succeeds and success dialog shown","Invalid JSON/wrong extension/no auth","Import requires auth and parse success","Automate partially",""
"RES-013","Residences","Task report","Generate residence tasks report with/without email","Manual + Integration","P2","iOS, Android, Web, Desktop","Residence exists","Trigger generate report","Report creation success feedback","Invalid email format optional field","Backend handles async report generation","Automate",""
"RES-014","Residences","Manage users view","Residence users list loads with owner/member roles","Manual + E2E UI","P1","iOS, Android (KMP)","Residence with multiple users","Open manage users","Accurate users and role indicators displayed","Owner missing from response","Role data trusted from API","Automate",""
"RES-015","Residences","Remove user","Owner removes a member successfully","Manual + Integration","P0","iOS, Android (KMP)","Owner logged in, target member exists","Remove member","Member removed and state refreshes","Attempt remove self/owner","API enforces permission rules","Automate",""
"TASK-001","Tasks","All tasks load","Kanban columns load for all residences","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in with at least one residence","Open tasks tab","Columns and counts render correctly","Zero tasks across all columns","Columns include overdue/in-progress/due-soon/upcoming/completed/cancelled","Automate","🟢 test03_viewTasksList"
"TASK-002","Tasks","Residence filtering","Tasks by residence uses filtered allTasks cache correctly","Manual + Integration","P1","iOS, Android, Web, Desktop","Multiple residences with tasks","Open residence detail tasks","Only selected residence tasks shown","Residence cache stale while global cache fresh","Client-side filtering path exists","Automate","🟢 test07_residenceDetailsShowTasks"
"TASK-003","Tasks","Create task","Create minimal valid task","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Residence exists, lookups loaded","Submit task with required fields","Task appears in expected column","Missing lookups due to failed seed load","Category/frequency/priority are required","Automate","🟢 test03_createTaskWithMinimalData | test06_createBasicTask"
"TASK-004","Tasks","Create from template","Create task from template browser","Manual + E2E UI","P1","iOS, Android, Web, Desktop","Templates available","Open templates, select one, save","Task prefilled and created","Template with long description/tags","Template data from seeded lookups","Automate","🟢 test16_createTaskFromTemplate"
"TASK-005","Tasks","Template search","Search templates requires >=2 chars and limits results","Manual + Unit","P2","iOS, Android, Web, Desktop","Templates loaded","Search with 1 char then 2+ chars","1 char returns empty, 2+ filtered max 10","Case-insensitive tag match","Search is local in DataManager","Automate","🟢 searchWithSingleCharReturnsEmpty | searchWithTwoCharsMatchesTitles | searchIsCaseInsensitive | searchMatchesDescription | searchMatchesTags | searchReturnsMaxTenResults | emptyQueryReturnsEmpty (TemplateSearchTests)"
"TASK-006","Tasks","Edit task","Edit task fields and persist updates","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Existing task","Change title/category/frequency/priority/due/cost","Task updates and remains consistent in caches","Invalid cost string conversion","Edit route passes serialized fields","Automate","🟢 test09_editTaskTitle | test10_updateAllTaskFields"
"TASK-007","Tasks","Mark in progress","Transition task to in-progress column","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Existing non-in-progress task","Tap mark in progress","Task moves to in-progress column","Already in progress idempotency","UpdateTask uses kanbanColumn target","Automate","🟢 test03_taskStateTransitions"
"TASK-008","Tasks","Clear in progress","Clear in-progress state returns task to scheduled column","Manual + Integration","P1","iOS, Android, Web, Desktop","Task currently in progress","Clear in-progress","Task leaves in-progress with correct new column","Due date past while clearing","Backend decides target column","Automate","🟢 test03_taskStateTransitions"
"TASK-009","Tasks","Cancel task","Cancel action moves task to cancelled state","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Active task exists","Cancel task","Task appears in cancelled column/state","Cancel already-cancelled task","Endpoint idempotency defined","Automate","🟢 test04_taskCancelOperation"
"TASK-010","Tasks","Uncancel task","Restore cancelled task to active lifecycle","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Cancelled task exists","Uncancel task","Task restored to appropriate column","Uncancel archived task","State transitions validated by API","Automate","🟢 test15_uncancelRestorescancelledTask"
"TASK-011","Tasks","Archive/unarchive","Archive hides task from active flow; unarchive restores","Manual + Integration","P1","iOS, Android, Web, Desktop","Task exists","Archive then unarchive","Visibility toggles correctly","Archived + cancelled combined states","Archive APIs available and cached updates propagate","Automate","🟢 test05_taskArchiveOperation"
"TASK-012","Tasks","Delete semantics","Task removal updates all cached columns and summaries","Manual + Integration","P1","iOS, Android, Web, Desktop","Task exists in cached data","Delete or server-remove task then refresh","Task absent in all views and counts updated","Task present in multiple cached views","DataManager removeTask updates all maps","Automate","🟢 allTasksIsNilAfterClear | removeTaskOnNilAllTasksIsNoOp | tasksByResidenceIsEmptyAfterClear (RemoveTaskTests)"
"TASK-013","Tasks","Due date handling","Past/now/future due dates map to correct columns","Manual + Integration","P1","iOS, Android, Web, Desktop","Tasks with boundary due dates","Load tasks around timezone boundaries","Kanban placement matches backend logic","DST transitions","Backend provides canonical kanban_column","Automate","🟢 test04_kanbanColumnDistribution | mixedTaskCategories (TaskMetricsTests)"
"TASK-014","Tasks","Cost fields","Estimated cost accepts numeric and rejects invalid formats","Manual + UI","P2","iOS, Android, Web, Desktop","Task form open","Enter valid/invalid cost strings","Valid persisted; invalid blocked or sanitized","Locale decimal separators","Cost parsed to Double","Automate","🟢 test04_createTaskWithAllFields"
"TASK-015","Tasks","Task detail navigation","Push/deep-link task navigation opens tasks tab and relevant task context","Manual + E2E UI","P0","iOS, Android","App receives task navigation ID","Tap notification/open intent","Tasks tab selected and task reachable","Task deleted before open","Main shell handles navigate_to_task contract","Automate",""
"TASK-016","Tasks","Bulk state refresh","After any task CRUD/action, summary cards refresh immediately","Manual + Integration","P1","iOS, Android, Web, Desktop","Dashboard visible with summaries","Perform task action","Summary counts update without hard reload","Rapid consecutive actions","Summary derived from cached kanban","Automate","🟢 test09_fullFlowSummary"
"TASK-017","Tasks","Concurrency","Two users edit same task; conflict resolution UX","Manual","P2","iOS, Android, Web, Desktop","Same task open on two accounts","Save conflicting edits","Consistent final state and clear error/last-write behavior","Out-of-order responses","Server conflict strategy documented","Manual",""
"TCOMP-001","Task completion","Complete task basic","Complete task with notes/cost/rating","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Active task exists","Open complete flow and submit","Completion created and task column updates","Null rating vs default value","Completion endpoint accepts optional fields","Automate","🟢 test03_taskLifecycleFlow"
"TCOMP-002","Task completion","Complete with images","Attach one or multiple images during completion","Manual + Integration","P0","iOS, Android","Camera/gallery permission granted","Submit completion with images","Images uploaded and linked to completion","Large image compression/failure mid-upload","Image compression and multipart upload enabled","Automate partially",""
"TCOMP-003","Task completion","Validation","Required completed-by field enforced (iOS form state)","Manual + UI","P1","iOS","Open complete task form","Submit blank completed-by","Validation error shown","Whitespace-only value","CompletedBy required by client form","Automate","🟢 completedByFieldRequired | completedByFieldWithValuePasses | completedByFieldWhitespaceOnlyFails (TaskCompletionValidationTests)"
"TCOMP-004","Task completion","Completion history","History list loads for task and sorted correctly","Manual + Integration","P1","iOS, Android, Web, Desktop","Task with multiple completions","Open completion history","Entries ordered and accurate","Missing images in older completion records","History endpoint returns full list","Automate","🟢 test10_completionHistoryLoadsAndIsSorted"
"DOC-001","Documents","List","Load all documents and residence-filtered documents","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in with docs data","Open documents tab and residence detail docs","Correct sets shown","Residence with zero docs","List supports optional residence filter","Automate","🟢 test01_NavigateToDocumentsScreen | test20_HandleEmptyDocumentsList | test21_HandleEmptyWarrantiesList"
"DOC-002","Documents","Create document","Create generic document with required fields","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Residence exists","Create document with title/type/residence","Document appears in lists","Missing residence selection on create","Create requires title/type/residence","Automate","🟢 test04_CreateDocumentWithMinimalFields"
"DOC-003","Documents","Create warranty fields","Create warranty/appliance with provider/dates metadata","Manual + Integration","P1","iOS, Android, Web, Desktop","Document form open","Enter warranty-specific fields and save","Fields persist and render in detail","End date before start date","Date validation expectations defined","Automate","🟢 test06_CreateWarrantyWithAllFields | test07_CreateWarrantyWithFutureDates | test08_CreateExpiredWarranty"
"DOC-004","Documents","Edit document","Edit existing document including type/category/tags","Manual + E2E UI","P1","iOS, Android, Web, Desktop","Document exists","Modify and save","Detail/list reflect updates","Switching types with stale fields","Backend accepts partial update","Automate","🟢 test15_EditDocumentTitle | test16_EditWarrantyDates"
"DOC-005","Documents","Delete document","Delete removes from global and residence caches","Manual + Integration","P0","iOS, Android, Web, Desktop","Document exists in caches","Delete document","Document removed everywhere","Delete while detail screen open","DataManager removeDocument updates both caches","Automate","🟢 test17_DeleteDocument | test18_DeleteWarranty"
"DOC-006","Documents","Upload image","Upload document image from camera/gallery","Manual + Integration","P0","iOS, Android","Permissions granted","Add image to document","Thumbnail and full image accessible","Upload timeout","Upload endpoint returns image metadata","Automate partially",""
"DOC-007","Documents","Delete image","Delete specific document image updates detail immediately","Manual + Integration","P1","iOS, Android, Web, Desktop","Document with multiple images","Delete one image","Remaining images preserved","Deleting last image","Image delete endpoint idempotency","Automate","🟢 test22_documentImageSectionExists"
"DOC-008","Documents","Download","Download/open document file via URL","Manual","P1","iOS, Android, Web, Desktop","Document has downloadable URL","Tap download/open","File retrieved and usable","Expired signed URL","Download API wraps binary result","Automate partially",""
"DOC-009","Documents","Validation","Claim email optional but must be valid if provided","Manual + UI","P2","iOS","Document form open","Enter invalid claim email","Validation error shown","Internationalized domains","Email regex defines valid format","Automate","🟢 validEmailPasses | invalidEmailMissingAtFails (ValidationHelpersTests + StringExtensionsTests)"
"DOC-010","Documents","Media viewer","Image viewer navigation, zoom, swipe, close behavior","Manual","P2","iOS, Android","Document with multiple images","Open viewer and interact","No crashes; correct index and gestures","Very large images","Viewer supports list index initialization","Manual",""
"CON-001","Contractors","List","Load contractors with empty and populated states","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in","Open contractors tab","List/empty state correct","Large list pagination if any","API supports optional filters","Automate","🟢 test16_refreshContractorsList"
"CON-002","Contractors","Create","Create contractor minimal required fields","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Logged in","Create contractor with name","Contractor appears in list/detail","Special characters in names","Name is required","Automate","🟢 test03_createContractorWithMinimalData"
"CON-003","Contractors","Create optional data","Persist optional company/contact/address/specialties","Manual + Integration","P1","iOS, Android, Web, Desktop","Contractor form open","Fill optional fields and save","All values persist accurately","Invalid website URL format","Optional fields may be null","Automate","🟢 test04_createContractorWithAllFields | test14_updateAllContractorFields"
"CON-004","Contractors","Email validation","Optional email must be valid if supplied","Manual + UI","P1","iOS, Android, Web, Desktop","Contractor form open","Enter invalid email","Validation error blocks save","Uppercase email + spaces","Validation trims and regex-checks","Automate","🟢 validEmailPasses | invalidEmailMissingAtFails | invalidEmailMissingDomainFails (ValidationHelpersTests + StringExtensionsTests)"
"CON-005","Contractors","Edit","Edit contractor and verify list/detail sync","Manual + E2E UI","P1","iOS, Android, Web, Desktop","Existing contractor","Update fields and save","Updated across views","Concurrent remote update","DataManager updateContractor handles summary mapping","Automate","🟢 test13_editContractorName | test14_updateAllContractorFields"
"CON-006","Contractors","Delete","Delete contractor removes from caches and residence associations","Manual + Integration","P0","iOS, Android, Web, Desktop","Existing contractor","Delete contractor","Removed from all views","Deleting favorite contractor","Association cleanup server-side","Automate","🟢 test08_contractorCRUD"
"CON-007","Contractors","Favorite toggle","Toggle favorite updates UI and persistence","Manual + E2E UI","P1","iOS, Android, Web, Desktop","Existing contractor","Toggle favorite twice","State toggles correctly and persists refresh","Rapid repeated taps","Endpoint supports idempotent toggles","Automate","🟢 test20_toggleContractorFavorite"
"CON-008","Contractors","By residence filter","Load contractors scoped to residence","Manual + Integration","P1","iOS, Android, Web, Desktop","Multiple residences and linked contractors","Open residence contractor section","Only related contractors shown","Contractor with null residence","Filtering done server-side","Automate","🟢 test21_contractorByResidenceFilter"
"CON-009","Contractors","Share export","Share contractor as .casera file","Manual","P1","Android","Contractor exists","Tap share contractor","Share sheet opens with valid file payload","Name containing '/' and long length","Filename sanitization applied","Manual",""
"CON-010","Contractors","Import .casera","Import contractor from valid file","Manual + Integration","P0","Android","Logged in, valid contractor file","Open file/import confirm","Contractor created and success dialog shown","Unknown specialty names in file","Specialties mapped by name to known IDs","Automate partially",""
"CON-011","Contractors","Import invalid file","Invalid extension/JSON/auth state handled safely","Manual","P0","Android","Invalid file or logged out","Attempt import","Clear error shown; no partial creation","Huge malformed JSON","Import parser errors are surfaced","Manual",""
"NOTIF-001","Notifications","Permission prompt","Notification permission request outcomes handled","Manual","P0","iOS, Android","Fresh install","Respond Allow and Deny in separate runs","App continues gracefully; state reflects permission","User changes setting later","Permission checked on foreground","Manual",""
"NOTIF-002","Notifications","Device registration","Register device token after login only","Manual + Integration","P0","iOS, Android","Have APNs/FCM token","Login with token available","registerDevice called once and succeeds","Token arrives before auth","Auth gating prevents unauthenticated registration","Automate",""
"NOTIF-003","Notifications","Token refresh","New push token triggers backend re-registration","Manual + Integration","P1","iOS, Android","Previously registered token","Simulate token rotation","Backend receives updated registration id","No token change should skip call","Last registered token cache used","Automate",""
"NOTIF-004","Notifications","Foreground notification","Foreground notifications display banner/sound and update read state","Manual","P1","iOS, Android","Permission granted, send test push","Receive push while app active","Banner shown; notification handled","Malformed payload missing type","Foreground presentation explicitly enabled","Manual",""
"NOTIF-005","Notifications","Notification tap navigation","Tap task push opens app and routes to tasks context","Manual + E2E","P0","iOS, Android","Task-linked push sent","Tap push from background/terminated","App opens on tasks flow for target task","Task no longer exists","Task id may be string or int","Automate partially",""
"NOTIF-006","Notifications","Action buttons premium","Premium users see and can execute task action buttons","Manual + Integration","P0","iOS, Android","Premium subscription active","Receive actionable task notification, tap action","Action API executes and UI refreshes","Action timeout/network loss","Actions gated by premium/limitationsEnabled","Manual","🟢 encodeDecodeRoundTrip | decodedValuesMatch | sameValuesAreEqual | differentTaskIdNotEqual | differentTaskTitleNotEqual | taskIdReturnsCorrectValue | taskTitleReturnsCorrectValue (WidgetActionTests)"
"NOTIF-007","Notifications","Action buttons free-tier gating","Free users with limitations enabled are routed home/not allowed actions","Manual","P0","iOS, Android","Free user limitationsEnabled=true","Tap actionable notification","No privileged task action executed","Subscription cache stale nil","Nil subscription defaults allow on iOS currently","Manual","🟢 encodeDecodeRoundTrip | sameValuesAreEqual | differentTaskIdNotEqual | differentTaskTitleNotEqual (WidgetActionTests)"
"NOTIF-008","Notifications","Preferences","Load and update notification preference toggles","Manual + Integration","P1","iOS, Android, Web, Desktop","Logged in","Open notification preferences, toggle settings, save","Preferences persist and affect server payloads","Partial update failures","Preferences API supports patch/update","Automate",""
"NOTIF-009","Notifications","History/read state","Notification history list and mark-read operations","Manual + Integration","P2","iOS, Android, Web, Desktop","Notifications exist","Open history, mark one and mark all","Unread counts decrement correctly","Race with incoming push","Unread count endpoint consistent","Automate",""
"SUB-001","Subscription","Status load","Subscription status loads at app launch/foreground","Manual + Integration","P0","iOS, Android, Web, Desktop","Logged in","Launch then background/foreground app","Status cache updates and UI gating accurate","Backend temporarily unavailable","Status refresh should be non-fatal","Automate",""
"SUB-002","Subscription","Upgrade screen products","Load purchasable plans and pricing","Manual","P0","iOS, Android","Store config present","Open upgrade screen","Monthly/annual products displayed","Store connectivity issues","Product IDs configured as expected","Manual + mocked automation",""
"SUB-003","Subscription","Purchase monthly","Complete monthly purchase and backend verification","Manual + Integration","P0","iOS, Android","Sandbox account, product available","Buy monthly plan","Entitlement granted, subscription status becomes pro","Pending transactions","Verification endpoint must return success","Manual",""
"SUB-004","Subscription","Purchase annual","Complete annual purchase and backend verification","Manual + Integration","P0","iOS, Android","Sandbox account","Buy annual plan","Entitlement granted and reflected in app","Upgrade/downgrade from existing plan","Latest transaction determines tier","Manual",""
"SUB-005","Subscription","Restore purchases","Restore on clean install/device migration","Manual + Integration","P0","iOS, Android","Existing prior subscription","Tap restore","Entitlements restored and backend synced","No previous purchases","Restore should not duplicate grants","Manual",""
"SUB-006","Subscription","Purchase cancellation","User-cancelled purchase does not show fatal error","Manual","P1","iOS, Android","Open paywall","Start then cancel purchase","No entitlement changes; UX remains stable","Repeated cancel attempts","User cancel considered non-error","Manual",""
"SUB-007","Subscription","Backend verification failure","Store purchase succeeds but backend verify fails","Manual","P0","iOS, Android","Force backend verify failure","Complete purchase","User sees recoverable state and can retry/restore","Receipt parsing mismatch","App should avoid false pro unlock","Manual",""
"SUB-008","Subscription","Feature gating","Pro-only features hidden/disabled for limited users","Manual + E2E","P0","iOS, Android, Web, Desktop","Test free and pro accounts","Traverse gated features (actions, limits, upgrades)","Gating consistent across surfaces","Cache stale after plan change","Gating uses subscription status + limitationsEnabled","Automate","🟢 noSubscriptionTierIsFree | subscriptionWithExpiresAtTierIsPro | subscriptionWithEmptyExpiresAtTierIsFree | subscriptionWithNilExpiresAtTierIsFree | nilSubscriptionNeverBlocks | limitationsDisabledNeverBlocks | proTierNeverBlocks | freeTierUnderLimitAllowed | freeTierAtLimitBlocked | freeTierOverLimitBlocked | tasksLimitEnforced | contractorsLimitEnforced | documentsLimitEnforced | nilLimitMeansUnlimited | unknownLimitKeyReturnsFalse | noLimitsForTierReturnsFalse | deprecatedPromptFreeWithLimitations | deprecatedPromptFreeWithoutLimitations | deprecatedPromptNilSubscription | canShareResidenceWhenNoSubscription | canShareResidenceWhenLimitationsDisabled | cannotShareResidenceWhenFreeWithLimitations | canShareResidenceWhenProWithLimitations | canShareContractorWhenNoSubscription | canShareContractorWhenLimitationsDisabled | cannotShareContractorWhenFreeWithLimitations | canShareContractorWhenProWithLimitations (SubscriptionGatingTests)"
"WID-001","Widgets","Small widget rendering","Small widget shows counts and opens app","Manual","P1","Android","Widget added, logged in","Place small widget and tap","Correct counts; tap opens app","No data cached yet","Widget reads from shared preferences state","Manual",""
"WID-002","Widgets","Medium widget list","Medium widget shows top tasks and overdue badge","Manual","P1","Android","Tasks exist","Place medium widget","Task rows and overdue badge correct","Malformed tasks_json","JSON parse fallback to empty list","Manual",""
"WID-003","Widgets","Large widget interactions","Large widget actions execute for pro users","Manual + Integration","P0","Android","Pro account, widget configured","Tap row and action controls","Opens task or executes action as expected","Free user should not see/execute pro actions","Widget passes task_id in intent","Manual","🟢 encodeDecodeRoundTrip | decodedValuesMatch | taskIdReturnsCorrectValue | taskTitleReturnsCorrectValue (WidgetActionTests)"
"WID-004","Widgets","Widget refresh","Widgets refresh after task state changes","Manual","P1","Android","Widget present","Complete/cancel task in app","Widget counts/list update within expected interval","Background restrictions","Widget update manager triggers refresh","Manual",""
"SHR-001","Sharing/Import","File association",".casera files open app import flow","Manual","P1","Android","Have .casera file","Open file from files app/share sheet","Import confirmation dialog shown","Multiple apps can open same MIME","Intent filter handles application/json with extension","Manual",""
"SHR-002","Sharing/Import","Security","Import rejects when unauthenticated","Manual","P0","Android","Logged out, .casera file ready","Attempt import","Error shown, no data mutation","Stale token in storage","Auth check occurs before API call","Manual",""
"SHR-003","Sharing/Import","Corrupt payload","Corrupt .casera payload fails safely without crash","Manual","P0","Android","Malformed JSON file","Attempt import","Graceful error dialog","Very large payload","Parser exceptions are caught","Manual",""
"DATA-001","Data layer","Lookups init","Seeded lookup data loads once and marks initialized","Manual + Integration","P0","iOS, Android, Web, Desktop","Fresh login","Observe first data bootstrap","Lookups available for forms/templates","Slow network during bootstrap","initializeLookups has concurrency guard","Automate","🟢 test06_lookupDataAvailable | setTaskCategoriesPopulatesList | setTaskCategoriesBuildsMappedLookup | setTaskPrioritiesPopulatesListAndMap | setTaskFrequenciesPopulatesListAndMap | setResidenceTypesPopulatesListAndMap | setContractorSpecialtiesPopulatesListAndMap | markLookupsInitializedSetsFlag (DataLayerTests)"
"DATA-002","Data layer","ETag refresh","Lookup refresh uses ETag and handles 304 not modified","Manual + Integration","P1","iOS, Android, Web, Desktop","Lookups already loaded + ETag","Foreground app or force refresh","No unnecessary data churn on 304","ETag lost between sessions","ETag persisted in storage","Automate","🟢 staticDataEndpointReturnsETag | conditionalRequestReturns304WhenDataUnchanged | staleETagReturns200 (DataLayerETagTests)"
"DATA-003","Data layer","Legacy fallback","If seeded-data endpoint fails, fallback static data path works","Manual + Integration","P1","iOS, Android, Web, Desktop","Mock seeded endpoint failure","Initialize lookups","Core lookups still available","Templates missing in fallback","Fallback endpoint still reachable","Automate","🟢 staticDataContainsAllRequiredLookupTypes | allLookupItemsHaveIdAndName | taskCategoriesHaveColorAndIcon | taskPrioritiesHaveLevelAndColor (DataLayerAPISchemaTests)"
"DATA-004","Data layer","Cache timeout","One-hour cache timeout triggers fresh fetch after expiry","Manual + Integration","P1","iOS, Android, Web, Desktop","Cached data older/newer than timeout","Request data with forceRefresh=false","Valid cache reused; stale cache refetched","Clock skew/device time changes","Timeout constant is 3600000 ms","Automate","🟢 cacheTimeZeroIsInvalid | recentCacheTimeIsValid | expiredCacheTimeIsInvalid | cacheTimeoutConstantIsOneHour | allCacheTimestampsStartAtZeroAfterClear (DataLayerTests.CacheValidationTests)"
"DATA-005","Data layer","Cache invalidation on logout","Logout clears user data/cache/ETag but retains theme","Manual + Integration","P0","iOS, Android, Web, Desktop","Logged in with populated data","Logout then inspect next launch","No user data remains; theme preference retained","Persistence clear implementation drift","Theme stored separately from persistenceManager.clear","Automate","🟢 testR206_postLogoutMainAppIsNoLongerAccessible | clearResetsAllCacheTimestamps | clearEmptiesLookupLists | clearResetsLookupsInitializedFlag | clearUserDataKeepsLookups | clearUserDataResetsCacheTimestamps (DataLayerTests.ClearTests)"
"DATA-006","Data layer","Disk persistence","Current user and lookups reload correctly after app restart","Manual + Integration","P1","iOS, Android, Web, Desktop","Logged in and data loaded","Kill and relaunch app","State restored without full refetch where valid","Partial/corrupt persisted JSON","Deserializer ignoreUnknownKeys is enabled","Automate","🟢 test08_diskPersistencePreservesLookupsAfterRestart"
"DATA-007","Data layer","Map/list consistency","Lookup map IDs and list values remain consistent after updates","Unit + Integration","P2","iOS, Android, Web, Desktop","Lookup update operation","Compare list and map representations","No missing or mismatched IDs","Duplicate IDs from backend","Maps are built via associateBy(id)","Automate","🟢 setTaskCategoriesBuildsMappedLookup | getterReturnsNilForMissingId | getterReturnsNilForNilId | allIdsAreUniquePerLookupType (DataLayerTests.LookupSetterTests + DataLayerAPISchemaTests)"
"OFF-001","Resilience","Offline launch","Offline launch with cached token/data behaves gracefully","Manual","P0","iOS, Android, Web, Desktop","Previously logged in with cached data","Launch with network off","No crash; clear messaging; cached UI where possible","Token validation cannot reach server","Current behavior may clear session on fetch failure","Manual",""
"OFF-002","Resilience","Offline action handling","Create/update actions fail with retriable errors when offline","Manual","P0","iOS, Android, Web, Desktop","Network disabled","Attempt create/edit/delete flows","Errors shown; no phantom local success","Intermittent network flaps","No offline queue currently assumed","Manual",""
"OFF-003","Resilience","Retry behavior","Retry from error dialogs succeeds without stale UI state","Manual + E2E","P1","iOS, Android, Web, Desktop","Force transient API failure","Tap retry then restore network","Action succeeds and loading/error states reset","Double-tap retry race","ApiResult state machine handles Idle/Loading/Error","Automate","🟢 testP010_retryButtonExistsOnErrorState"
"OFF-004","Resilience","Idempotency UX","Double submit protection for create flows","Manual + UI","P1","iOS, Android, Web, Desktop","Open any create form","Rapid tap save","Single record created","Very slow API response","Buttons disabled during loading","Automate","🟢 test19_doubleSubmitProtection"
"SEC-001","Security","Auth boundaries","Protected endpoints reject without token and UI handles 401","Manual + Integration","P0","iOS, Android, Web, Desktop","No token","Attempt protected operations","Redirect/login prompt or clear error","Token injected but expired","APILayer checks token before API in many calls","Automate","🟢 test05_crossUserAccessControl"
"SEC-002","Security","Session cleanup","Sensitive data not accessible after logout and app restart","Manual","P0","iOS, Android, Web, Desktop","Logged in then logout","Force close and relaunch","No protected screens/data accessible","Widget still showing stale data","Widget caches should be cleared on logout (iOS path)","Manual","🟢 testR206_postLogoutMainAppIsNoLongerAccessible"
"SEC-003","Security","Import validation","Imported files cannot execute code or break parser boundaries","Manual","P1","Android","Craft malicious JSON payload","Import payload","App rejects safely, no crash","Oversized strings, deep nesting","Deserializer should throw and be caught","Manual",""
"SEC-004","Security","PII exposure","Logs and analytics avoid leaking sensitive credential values","Manual + Code audit","P1","iOS, Android, Web, Desktop","Enable debug logging","Run auth/payment flows","No passwords/tokens in logs/events","Third-party SDK auto-capture risk","PostHog config reviewed","Manual",""
"PERF-001","Performance","Cold start","Startup time within target for logged-out and logged-in states","Manual + Perf","P1","iOS, Android","Profile build with instrumentation","Measure cold launch","Meets agreed startup SLA","Slow network path for verified user","Auth check performs network call","Automate perf",""
"PERF-002","Performance","Large data rendering","Task/document/contractor lists remain responsive with large datasets","Manual + Perf","P1","iOS, Android, Web, Desktop","Seed large dataset","Scroll and interact lists","No jank/crash; acceptable memory","Thousands of items and images","Virtualized list behavior depends on platform","Manual + benchmarks","🟢 test17_residenceListPerformance | test14_taskListPerformance | test19_contractorListPerformance"
"PERF-003","Performance","Image handling","Large image capture/upload/compression memory stability","Manual + Perf","P0","iOS, Android","Use high-resolution photos","Attach multiple images","No OOM/crash; upload completes or fails gracefully","Low-memory device","ImageCompressor platform implementations are active","Manual",""
"PERF-004","Performance","Background operations","Foreground/resume refresh does not block UI thread","Manual + Perf","P2","iOS, Android","App with valid session","Background then foreground repeatedly","UI remains interactive during refresh","Concurrent refresh and navigation","Lookups refresh runs async","Manual","🟢 test16_residencePersistsAfterBackgroundingApp | test13_taskPersistsAfterBackgroundingApp | test18_contractorPersistsAfterBackgroundingApp"
"A11Y-001","Accessibility","Basic semantics","All primary controls have accessible labels/identifiers","Manual","P0","iOS, Android, Web, Desktop","Screen reader on","Traverse major flows","Controls are announced clearly","Custom components lacking labels","Accessibility identifiers partly defined","Manual + lint","🟢 testA001_OnboardingPrimaryControlsAreReachable | testA003_CoreControlsExposeIdentifiers | testA004_ValuePropsScreenControlsAreReachable | testA005_NameResidenceScreenControlsAreReachable | testA006_CreateAccountScreenControlsAreReachable"
"A11Y-002","Accessibility","Dynamic type","Text scales correctly without clipping in key screens","Manual","P1","iOS, Android","Large accessibility font settings","Open forms/lists/dialogs","Layout remains usable","Long localized strings","Design system supports flexible layout","Manual",""
"A11Y-003","Accessibility","Keyboard navigation","Tab/focus order valid on web/desktop forms","Manual","P1","Web, Desktop","Hardware keyboard","Navigate forms using keyboard only","Logical focus traversal and visible focus states","Modal dialogs focus trap","Compose/web focus handling may differ","Manual",""
"A11Y-004","Accessibility","Color contrast","Theme variants meet minimum contrast requirements","Manual + Tooling","P1","iOS, Android, Web, Desktop","Cycle themes","Inspect text/icon contrast","WCAG contrast thresholds met","Error/success states on tinted backgrounds","Multiple custom themes supported","Manual + automated audit",""
"I18N-001","Localization","String coverage","No missing keys/placeholders across supported locales","Manual + Static check","P1","iOS, Android, Web, Desktop","Run app in each locale","Traverse major screens","No raw keys, no placeholder mismatches","Pluralization and gender strings","Locales include es/fr/de/it/ja/ko/nl/pt/zh etc.","Automate (lint + screenshot)",""
"I18N-002","Localization","Layout expansion","Long translations do not break onboarding/forms/buttons","Manual","P1","iOS, Android, Web, Desktop","Switch to longest-string locale","Review high-density screens","No clipping/overlap","RTL future locale support","Current locales may be LTR only","Manual",""
"THEME-001","Theming","Theme persistence","Theme choice persists across app restarts","Manual + Integration","P1","iOS, Android, Web, Desktop","Logged in or logged out","Change theme then relaunch","Selected theme reapplied","Theme ID missing/corrupt in storage","Theme stored separately from auth data","Automate","🟢 defaultThemeIdIsDefault | setThemeIdUpdatesValue | clearDoesNotResetTheme | themeIdIsPreservedAsOceanAfterClear (ThemePersistenceTests) | test09_themePersistsAcrossRestart"
"THEME-002","Theming","Theme switch live update","Changing theme updates active screen without broken states","Manual + UI","P2","iOS, Android, Web, Desktop","Open app on any tab","Change theme in profile/settings","Immediate UI recolor with legible components","Transition while modal open","Theme manager publishes updates","Manual","🟢 allCasesCountIsEleven | allDisplayNamesAreNonEmpty | allDescriptionsAreNonEmpty | rawValueRoundTripsForAllCases | allRawValuesAreUnique | brightDisplayNameIsDefault | oceanRawValueIsOcean (ThemeIDTests)"
"NAV-001","Navigation","Bottom tabs","Residences/Tasks/Contractors/Documents tabs navigate and preserve expected state","Manual + E2E UI","P0","iOS, Android","Logged in","Switch tabs repeatedly","Correct screens shown; no stuck navigation","Push navigation then tab switch back","Nested nav stacks differ per platform","Automate","🟢 test03_navigationBetweenTabs | test10_navigateBetweenTabs | testR309_navigationAcrossPrimaryTabsAndBackToResidences"
"NAV-002","Navigation","Back stack safety","Back from details/forms returns to correct parent","Manual + E2E UI","P0","iOS, Android, Web, Desktop","Navigate into detail/edit screens","Use back gestures/buttons","Parent state intact and refreshed as expected","Direct deep-link entry without parent","Saved-state refresh flags used in KMP nav","Automate","🟢 test02_cancelRegistration | test04_cancelResidenceCreation | test02_cancelTaskCreation | test19_CancelDocumentCreation"
"NAV-003","Navigation","Duplicate routes","Avoid duplicate screen instances from repeated tap/navigation actions","Manual","P2","iOS, Android, Web, Desktop","Rapidly tap nav actions","Observe back stack and UI","No duplicate stacking or loops","Double tap race conditions","NavHost popUpTo rules applied","Manual","🟢 testP003_RapidDoubleTapOnValuePropsContinueLandsOnNameResidence | testP004_StartFreshThenBackToWelcomeThenJoinExistingDoesNotCorruptState | testP005_RepeatedLoginNavigationRemainsStable"
"ANL-001","Analytics","Auth events","Login/register/logout/verify events fire once with correct properties","Manual + Integration","P2","iOS, Android","Analytics enabled in test env","Perform auth flows","Expected events emitted once","Retries causing duplicate events","Event taxonomy defined in analytics layer","Automate with mocked sink",""
"ANL-002","Analytics","Core feature events","Residence/task/document/contractor create-edit-delete events tracked","Manual + Integration","P2","iOS, Android","Analytics test workspace","Perform CRUD actions","Events mapped to correct feature","Failed actions should not emit success","PostHog wrappers used consistently","Automate",""
"ANL-003","Analytics","Subscription events","Upgrade prompt open, purchase, restore, verification outcomes tracked","Manual + Integration","P2","iOS, Android","Store sandbox + analytics","Run subscription flows","Lifecycle events present and correctly attributed","Purchase canceled path","No sensitive receipt data in events","Manual",""
"QA-001","Cross-platform parity","Feature parity","Core flows behave equivalently between KMP UI and iOS native UI","Manual regression","P0","iOS, Android, Web, Desktop","Same seeded account","Run same scenarios on each platform","Equivalent outcomes and data integrity","Known UX differences documented","iOS native app is source for iOS UX","Manual",""
"QA-002","Cross-platform parity","API contract consistency","All clients handle new/unknown JSON fields gracefully","Integration","P1","iOS, Android, Web, Desktop","Backend adds extra fields","Run major endpoints","No crash; fields ignored where unknown","Type changes breaking parsing","Kotlin serializers set ignoreUnknownKeys","Automate","🟢 widgetTaskDecodesWithExtraFields | widgetTaskIgnoresUnknownNestedObjects (JSONUnknownFieldsResilienceTests)"
"QA-003","Release quality","Smoke suite","Minimal release gate across auth, residence, task, document, contractor, notification, subscription","Manual + Automated","P0","iOS, Android","Release candidate build","Run smoke checklist","No blockers before release","Environment instability","Smoke should run against stable test backend","Automate + manual signoff","🟢 test01_authenticationFlow | test02_residenceCRUDFlow | test03_taskLifecycleFlow | test08_contractorCRUD | test01_NavigateToDocumentsScreen"
"QA-004","Release quality","Data migration","Upgrade app version preserves critical local state safely","Manual","P1","iOS, Android, Web, Desktop","Install old build with data then upgrade","Launch and use app","No corruption; expected resets only","Schema/key changes in persistence","Persistence keys remain compatible","Manual",""
