Files
honeyDueKMP/docs/ios_greenfield_test_plan.csv
treyt 0c803af9bc Add 4 new unit test suites for greenfield test plan coverage
Add 87 new tests (384 total) covering ValidationRules/ValidationError,
PasswordResetViewModel navigation and client-side validation, WidgetAction
Codable/Equatable/accessors, parseDate, and ThemeID enum properties.
Updates greenfield CSV for AUTH-012/017/018, NOTIF-006/007, WID-003, THEME-002.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 19:29:12 -06:00

55 KiB

1Test_IDDomainFeatureScenarioTest_MethodPriorityPlatformsPreconditionsStepsExpected_ResultEdge_CasesAssumptionsAutomation_Recommendationautomated
2AUTH-001AuthenticationApp start routingFirst launch routes to onboarding when hasCompletedOnboarding=falseManual + E2E UIP0iOS, Android, Web, DesktopFresh install, no tokenLaunch appOnboarding welcome is shown, not login/main tabsCorrupted local onboarding flagOnboarding state is persisted locallyAutomate (UI smoke)🟢 testF001_ColdLaunchShowsOnboardingWelcome
3AUTH-002AuthenticationApp start routingReturning user with onboarding complete and no token routes to loginManual + E2E UIP0iOS, Android, Web, DesktophasCompletedOnboarding=true, token missingLaunch appLogin screen shownStale cached user object presentToken is source of truthAutomate🟢 testAppLaunchesAndShowsLoginScreen
4AUTH-003AuthenticationApp start routingAuthenticated + verified user routes to main tabsManual + E2E UIP0iOS, Android, Web, DesktopValid token, verified userLaunch appMain tab shell displayedCached token exists but API failsCurrent-user fetch determines validityAutomate🟢 testR203_validLoginTransitionsToMainAppRoot
5AUTH-004AuthenticationApp start routingAuthenticated but unverified user routes to verify emailManual + E2E UIP0iOS, Android, Web, DesktopValid token, verified=falseLaunch appVerify email screen shownUser gets verified between launchesVerification status fetched from backendAutomate🟢 testR104_verificationGateBlocksMainAppBeforeCodeEntry | testR110_relaunchUnverifiedUserNeverLandsInMainApp
6AUTH-005AuthenticationToken invalidationInvalid token at startup clears session and returns to loginManual + IntegrationP0iOS, Android, Web, DesktopExpired/invalid token storedLaunch appData cleared and login shownBackend 500 vs 401 behavior401/failed current-user means logoutAutomate🟢 test08_invalidatedTokenRedirectsToLogin
7AUTH-006AuthenticationLoginValid username/password login successManual + E2E UIP0iOS, Android, Web, DesktopExisting verified accountSubmit login formToken persisted, lookups initialized, main shownSlow network during loginLogin API returns token+userAutomate🟢 test02_loginWithValidCredentials | testR202_validCredentialsSubmitFromLogin
8AUTH-007AuthenticationLoginInvalid credentials shows actionable errorManual + E2E UIP0iOS, Android, Web, DesktopNo sessionSubmit wrong passwordError shown, user remains on loginRate-limit or lockout responsesError parser maps backend errorsAutomate🟢 test01_loginWithInvalidCredentials
9AUTH-008AuthenticationLogin validationEmpty username/password blocked client-sideManual + UIP1iOS, Android, Web, DesktopNo sessionTap login with empty fieldsValidation errors shown, no API callWhitespace-only inputClient validation activeAutomate🟢 testF205_LoginButtonDisabledWhenCredentialsAreEmpty | testF207_LoginScreenShowsAllExpectedElements | testF208_RegisterFormShowsAllRequiredFields
10AUTH-009AuthenticationRegistrationCreate account success then verify-email stepManual + E2E UIP0iOS, Android, Web, DesktopUnique email/usernameSubmit valid registrationSession established and verify-email screen appearsExisting email conflictRegister API auto-authenticatesAutomate🟢 testR103_successfulRegistrationTransitionsToVerificationGate
11AUTH-010AuthenticationRegistration validationInvalid email/password formats rejectedManual + UIP1iOS, Android, Web, DesktopNo sessionTry invalid email, short password, weak passwordUser-friendly validation errorsUnicode emails, long usernamesValidation rules are enforced consistentlyAutomate🟢 test03_registrationWithEmptyFields | test04_registrationWithInvalidEmail | test06_registrationWithWeakPassword
12AUTH-011AuthenticationEmail verificationValid 6-digit code verifies accountManual + E2E UIP0iOS, Android, Web, DesktopLogged-in unverified userEnter 6-digit numeric codeAccount marked verified and app routes forwardCode already usedCode must be exactly 6 digitsAutomate🟢 testR105_validVerificationCodeTransitionsToMainApp | test07_successfulRegistrationAndVerification
13AUTH-012AuthenticationEmail verificationNon-numeric/short/long code blockedManual + UIP1iOS, Android, Web, DesktopOn verify-email screenEnter invalid codesVerify action disabled or error shownPasted with spacesCode input sanitizes to digitsAutomate🟢 testR107_invalidVerificationCodeShowsErrorAndStaysBlocked | testR109_verifyButtonDisabledForIncompleteCode | test10_verificationCodeFieldValidation | emptyCodeReturnsRequired | wrongLengthReturnsInvalidCode | nonNumericCodeReturnsInvalidCode | validSixDigitCodeReturnsNil | customLengthFourDigitCode | customLengthWrongDigitCount (ValidationRulesTests)
14AUTH-013AuthenticationLogoutLogout clears token, user data, lookups, and returns to loginManual + E2E UIP0iOS, Android, Web, DesktopLogged inTap logoutLogin shown; protected API calls fail without tokenLogout API fails network-sideClient clears state even if API call failsAutomate🟢 test06_logout | testR205_logoutFromMainAppReturnsToLoginRoot
15AUTH-014AuthenticationForgot passwordRequest reset by email success pathManual + E2E UIP0iOS, Android, Web, DesktopKnown account emailSubmit forgot-password emailSuccess message and next step availableUnknown email behavior privacy-safeBackend may still return generic successAutomate🟢 test05_forgotPasswordNavigation | testF206_ForgotPasswordButtonIsAccessible | testF209_ForgotPasswordNavigatesToResetFlow
16AUTH-015AuthenticationReset code verificationVerify reset code success pathManual + E2E UIP0iOS, Android, Web, DesktopReset email submittedEnter correct codeReset-token available for password resetExpired codeCode verification endpoint returns tokenAutomate🟢 test03_verifyResetCodeSuccess
17AUTH-016AuthenticationPassword resetReset password success with matching confirmationManual + E2E UIP0iOS, Android, Web, DesktopValid reset tokenEnter new password + confirmPassword changed; user can log in (or auto-login flow)Token expires mid-flowReset endpoint ignores confirm fieldAutomate🟢 test04_resetPasswordSuccessAndLogin
18AUTH-017AuthenticationPassword resetMismatched password confirmation blockedManual + UIP1iOS, Android, Web, DesktopReset password screenEnter mismatchInline error; no reset requestTrailing spacesClient validates before submitAutomate🟢 mismatchedPasswordsFails | caseSensitiveMismatchFails (ValidationHelpersTests) | matchingPasswordsReturnsNil | mismatchedPasswordsReturnsMismatch | caseSensitiveMismatch (ValidationRulesTests) | requiredFieldErrorDescription | invalidEmailErrorDescription | passwordTooShortErrorDescription | passwordMismatchErrorDescription | passwordMissingLetterErrorDescription | passwordMissingNumberErrorDescription | invalidCodeErrorDescription | invalidUsernameErrorDescription | customMessageErrorDescription (ValidationRulesTests)
19AUTH-018AuthenticationDeep link resetPassword-reset deep link opens flow with token prefilledManual + E2E UIP0iOS, AndroidInstalled app with deep-link supportOpen reset deep linkForgot/reset flow opens and token is consumedMalformed token in URLDeep link token can be cleared on backAutomate🟢 defaultInitStartsAtRequestCode | initWithTokenStartsAtResetPassword | moveToNextStepFromRequestCode | moveToNextStepFromVerifyCode | moveToNextStepFromResetPassword | moveToNextStepFromLoggingIn | moveToNextStepFromSuccessIsNoOp | moveToPreviousStepFromVerifyCode | moveToPreviousStepFromResetPassword | moveToPreviousStepFromRequestCodeIsNoOp | moveToPreviousStepFromLoggingInIsNoOp | moveToPreviousStepFromSuccessIsNoOp | resetClearsAllState | clearErrorNilsOutErrorMessage | clearSuccessNilsOutSuccessMessage | verifyResetCodeWithEmptyCodeSetsError | verifyResetCodeWithNonNumericCodeSetsError | resetPasswordWithEmptyPasswordSetsError | resetPasswordWithWeakPasswordSetsError | resetPasswordWithMismatchedPasswordsSetsError | resetPasswordWithNilTokenSetsError | allCasesHasFiveValues | allCasesContainsExpectedSteps (PasswordResetViewModelTests)
20AUTH-019AuthenticationSSO AppleApple Sign-In success creates or signs in accountManual + IntegrationP1iOSApple-capable test device/simulatorComplete Apple sign-inSession established; verification state handledUser hides email, first-login only email scopeApple credential mapped to backend requestAutomate partially (mock)
21AUTH-020AuthenticationSSO GoogleGoogle Sign-In success pathManual + IntegrationP1Android, Web, KMP UIGoogle sign-in configuredComplete Google sign-inSession established with backend tokenRevoked Google tokenBackend validates ID tokenAutomate partially
22ONB-001OnboardingIntent splitStart Fresh path goes through value props and name residenceManual + E2E UIP0iOS, Android (KMP)Fresh installChoose Start Fresh and continueStep order matches intended flowBack navigation at each stepFlow differs by intentAutomate🟢 testF101_StartFreshFlowReachesCreateAccount | testR002_startFreshFlowReachesCreateAccount
23ONB-002OnboardingIntent splitJoin Existing path skips value/name steps and goes to account creationManual + E2E UIP0iOS, Android (KMP)Fresh installChoose Join ExistingExpected condensed step orderUser switches intent mid-flowIntent persisted during onboardingAutomate🟢 testF102_JoinExistingFlowGoesToCreateAccount | testF105_JoinExistingFlowSkipsValuePropsAndNameResidence
24ONB-003OnboardingNavigationBack button transitions and step history correctnessManual + UIP1iOS, Android (KMP)In onboarding multi-step flowNavigate forward then backReturns to correct previous stepBack from verify-email triggers logout on iOSBack behavior is product-definedAutomate🟢 testF103_BackNavigationFromNameResidenceReturnsToValueProps | testF108_BackFromCreateAccountNavigatesToPreviousStep
25ONB-004OnboardingSkip behaviorSkippable screens skip to next valid stateManual + UIP1iOS, Android (KMP)On skippable stepTap SkipProgress advances without corrupting stateSkip on terminal upsell step completes onboardingSkip availability is step-dependentAutomate🟢 testF104_SkipOnValuePropsMovesToNameResidence
26ONB-005OnboardingResidence bootstrapStart Fresh creates residence automatically after verificationManual + IntegrationP0iOS, Android (KMP)Onboarding start-fresh with residence nameVerify email and continueResidence created or graceful fallback if creation failsBlank residence name bypasses creationCreation failure should not hard-block onboardingAutomate🟢 testF110_startFreshCreatesResidenceAfterVerification
27ONB-006OnboardingJoin residenceJoin-existing flow joins via share codeManual + E2E UIP0iOS, Android (KMP)Valid join codeSubmit code in onboardingUser added to shared residenceExpired/invalid/reused codeJoin code endpoint enforces ownership rulesAutomate
28ONB-007OnboardingFirst taskFirst-task onboarding step can create selected tasksManual + IntegrationP1iOS, Android (KMP)On first-task stepSelect templates and continueTasks created; flow proceedsPartial task creation failuresAt least one success considered success in KMP VMAutomate
29ONB-008OnboardingCompletion persistenceCompleting onboarding persists flag and bypasses onboarding next launchManual + E2E UIP0iOS, Android, Web, DesktopCompleted onboarding onceRestart appOnboarding is skippedApp data clear resets flagOnboarding flag stored locallyAutomate🟢 testF111_completedOnboardingBypassedOnRelaunch
30RES-001ResidencesListResidences list loads with empty and non-empty statesManual + E2E UIP0iOS, Android, Web, DesktopLogged inOpen residences tabCorrect list/empty UI shownSlow API and stale cacheList can come from cache or networkAutomate🟢 test01_viewResidencesList | testR303_residencesListLoadsAfterTabSelection
31RES-002ResidencesCreateCreate residence with required fields onlyManual + E2E UIP0iOS, Android, Web, DesktopLogged inFill minimum fields and saveResidence appears in list/detailDuplicate name allowed/not allowed behaviorName required; other fields optionalAutomate🟢 test05_createResidenceWithMinimalData | testR306_createResidenceMinimalDataSubmitsSuccessfully
32RES-003ResidencesCreate validationPrevent submit when required name missingManual + UIP1iOS, Android, Web, DesktopOpen add residence formSubmit blank nameValidation error, no API callWhitespace-only nameRequired validation trims inputAutomate🟢 test01_cannotCreateResidenceWithEmptyName
33RES-004ResidencesCreate optional fieldsAll optional numeric/text/address fields persist correctlyManual + IntegrationP1iOS, Android, Web, DesktopOpen add residence formFill all fields and saveValues round-trip correctly in detail/editDecimals for bathrooms/lot sizeType conversion preserves precisionAutomate🟢 test12_updateAllResidenceFields
34RES-005ResidencesEditEdit residence updates list and detail viewsManual + E2E UIP0iOS, Android, Web, DesktopExisting residenceModify fields and saveUpdated values shown immediatelyConcurrent edit from another userDataManager updates local cachesAutomate🟢 test11_editResidenceName | test12_updateAllResidenceFields
35RES-006ResidencesDeleteDelete residence removes related task/document cached subsetsManual + IntegrationP0iOS, Android, Web, DesktopResidence with tasks/docs existsDelete residenceResidence gone; related cached sections removedDelete primary/only residenceServer cascade semantics documentedAutomate🟢 test02_residenceCRUDFlow
36RES-007ResidencesPrimary residenceSet/retain primary residence behaviorManualP2iOS, Android, Web, DesktopMultiple residencesMark one as primary and reloadOnly intended residence is primaryTwo rapid primary updatesBackend enforces uniquenessAutomate partially🟢 test18_setPrimaryResidence
37RES-008ResidencesSummaryResidence summary counts derive from kanban columns correctlyManual + IntegrationP1iOS, Android, Web, DesktopResidence with mixed task statusesOpen summary cardsCounts match task column truthNo tasks stateSummary can be client-computedAutomate🟢 test09_fullFlowSummary | test06_verifyKanbanStructure
38RES-009ResidencesJoin by codeJoin residence from manual share code entryManual + E2E UIP0iOS, Android, Web, DesktopValid share code from another accountEnter code in join flowMembership granted and residence appearsCode expired or already memberJoin endpoint returns reasoned errorsAutomate
39RES-010ResidencesGenerate share codeGenerate/refresh residence share codeManual + IntegrationP1iOS, Android, Web, DesktopOwner access to residenceGenerate codeNew valid code returned/visibleRepeated generation invalidates old codesAccess limited by roleAutomate🟢 test07_residenceSharingUIElements
40RES-011ResidencesShare package exportCreate residence .casera package and open share sheetManualP1AndroidResidence exists, logged inTap share residenceShare sheet opens with file attachmentFilename sanitization with special charsBackend generates package with shareCodeAutomate partially
41RES-012ResidencesShare package importImport .casera residence file joins residenceManual + IntegrationP0AndroidValid .casera file receivedOpen file via app/import handler and confirmJoin succeeds and success dialog shownInvalid JSON/wrong extension/no authImport requires auth and parse successAutomate partially
42RES-013ResidencesTask reportGenerate residence tasks report with/without emailManual + IntegrationP2iOS, Android, Web, DesktopResidence existsTrigger generate reportReport creation success feedbackInvalid email format optional fieldBackend handles async report generationAutomate
43RES-014ResidencesManage users viewResidence users list loads with owner/member rolesManual + E2E UIP1iOS, Android (KMP)Residence with multiple usersOpen manage usersAccurate users and role indicators displayedOwner missing from responseRole data trusted from APIAutomate
44RES-015ResidencesRemove userOwner removes a member successfullyManual + IntegrationP0iOS, Android (KMP)Owner logged in, target member existsRemove memberMember removed and state refreshesAttempt remove self/ownerAPI enforces permission rulesAutomate
45TASK-001TasksAll tasks loadKanban columns load for all residencesManual + E2E UIP0iOS, Android, Web, DesktopLogged in with at least one residenceOpen tasks tabColumns and counts render correctlyZero tasks across all columnsColumns include overdue/in-progress/due-soon/upcoming/completed/cancelledAutomate🟢 test03_viewTasksList
46TASK-002TasksResidence filteringTasks by residence uses filtered allTasks cache correctlyManual + IntegrationP1iOS, Android, Web, DesktopMultiple residences with tasksOpen residence detail tasksOnly selected residence tasks shownResidence cache stale while global cache freshClient-side filtering path existsAutomate🟢 test07_residenceDetailsShowTasks
47TASK-003TasksCreate taskCreate minimal valid taskManual + E2E UIP0iOS, Android, Web, DesktopResidence exists, lookups loadedSubmit task with required fieldsTask appears in expected columnMissing lookups due to failed seed loadCategory/frequency/priority are requiredAutomate🟢 test03_createTaskWithMinimalData | test06_createBasicTask
48TASK-004TasksCreate from templateCreate task from template browserManual + E2E UIP1iOS, Android, Web, DesktopTemplates availableOpen templates, select one, saveTask prefilled and createdTemplate with long description/tagsTemplate data from seeded lookupsAutomate🟢 test16_createTaskFromTemplate
49TASK-005TasksTemplate searchSearch templates requires >=2 chars and limits resultsManual + UnitP2iOS, Android, Web, DesktopTemplates loadedSearch with 1 char then 2+ chars1 char returns empty, 2+ filtered max 10Case-insensitive tag matchSearch is local in DataManagerAutomate🟢 searchWithSingleCharReturnsEmpty | searchWithTwoCharsMatchesTitles | searchIsCaseInsensitive | searchMatchesDescription | searchMatchesTags | searchReturnsMaxTenResults | emptyQueryReturnsEmpty (TemplateSearchTests)
50TASK-006TasksEdit taskEdit task fields and persist updatesManual + E2E UIP0iOS, Android, Web, DesktopExisting taskChange title/category/frequency/priority/due/costTask updates and remains consistent in cachesInvalid cost string conversionEdit route passes serialized fieldsAutomate🟢 test09_editTaskTitle | test10_updateAllTaskFields
51TASK-007TasksMark in progressTransition task to in-progress columnManual + E2E UIP0iOS, Android, Web, DesktopExisting non-in-progress taskTap mark in progressTask moves to in-progress columnAlready in progress idempotencyUpdateTask uses kanbanColumn targetAutomate🟢 test03_taskStateTransitions
52TASK-008TasksClear in progressClear in-progress state returns task to scheduled columnManual + IntegrationP1iOS, Android, Web, DesktopTask currently in progressClear in-progressTask leaves in-progress with correct new columnDue date past while clearingBackend decides target columnAutomate🟢 test03_taskStateTransitions
53TASK-009TasksCancel taskCancel action moves task to cancelled stateManual + E2E UIP0iOS, Android, Web, DesktopActive task existsCancel taskTask appears in cancelled column/stateCancel already-cancelled taskEndpoint idempotency definedAutomate🟢 test04_taskCancelOperation
54TASK-010TasksUncancel taskRestore cancelled task to active lifecycleManual + E2E UIP0iOS, Android, Web, DesktopCancelled task existsUncancel taskTask restored to appropriate columnUncancel archived taskState transitions validated by APIAutomate🟢 test15_uncancelRestorescancelledTask
55TASK-011TasksArchive/unarchiveArchive hides task from active flow; unarchive restoresManual + IntegrationP1iOS, Android, Web, DesktopTask existsArchive then unarchiveVisibility toggles correctlyArchived + cancelled combined statesArchive APIs available and cached updates propagateAutomate🟢 test05_taskArchiveOperation
56TASK-012TasksDelete semanticsTask removal updates all cached columns and summariesManual + IntegrationP1iOS, Android, Web, DesktopTask exists in cached dataDelete or server-remove task then refreshTask absent in all views and counts updatedTask present in multiple cached viewsDataManager removeTask updates all mapsAutomate🟢 allTasksIsNilAfterClear | removeTaskOnNilAllTasksIsNoOp | tasksByResidenceIsEmptyAfterClear (RemoveTaskTests)
57TASK-013TasksDue date handlingPast/now/future due dates map to correct columnsManual + IntegrationP1iOS, Android, Web, DesktopTasks with boundary due datesLoad tasks around timezone boundariesKanban placement matches backend logicDST transitionsBackend provides canonical kanban_columnAutomate🟢 test04_kanbanColumnDistribution | mixedTaskCategories (TaskMetricsTests)
58TASK-014TasksCost fieldsEstimated cost accepts numeric and rejects invalid formatsManual + UIP2iOS, Android, Web, DesktopTask form openEnter valid/invalid cost stringsValid persisted; invalid blocked or sanitizedLocale decimal separatorsCost parsed to DoubleAutomate🟢 test04_createTaskWithAllFields
59TASK-015TasksTask detail navigationPush/deep-link task navigation opens tasks tab and relevant task contextManual + E2E UIP0iOS, AndroidApp receives task navigation IDTap notification/open intentTasks tab selected and task reachableTask deleted before openMain shell handles navigate_to_task contractAutomate
60TASK-016TasksBulk state refreshAfter any task CRUD/action, summary cards refresh immediatelyManual + IntegrationP1iOS, Android, Web, DesktopDashboard visible with summariesPerform task actionSummary counts update without hard reloadRapid consecutive actionsSummary derived from cached kanbanAutomate🟢 test09_fullFlowSummary
61TASK-017TasksConcurrencyTwo users edit same task; conflict resolution UXManualP2iOS, Android, Web, DesktopSame task open on two accountsSave conflicting editsConsistent final state and clear error/last-write behaviorOut-of-order responsesServer conflict strategy documentedManual
62TCOMP-001Task completionComplete task basicComplete task with notes/cost/ratingManual + E2E UIP0iOS, Android, Web, DesktopActive task existsOpen complete flow and submitCompletion created and task column updatesNull rating vs default valueCompletion endpoint accepts optional fieldsAutomate🟢 test03_taskLifecycleFlow
63TCOMP-002Task completionComplete with imagesAttach one or multiple images during completionManual + IntegrationP0iOS, AndroidCamera/gallery permission grantedSubmit completion with imagesImages uploaded and linked to completionLarge image compression/failure mid-uploadImage compression and multipart upload enabledAutomate partially
64TCOMP-003Task completionValidationRequired completed-by field enforced (iOS form state)Manual + UIP1iOSOpen complete task formSubmit blank completed-byValidation error shownWhitespace-only valueCompletedBy required by client formAutomate🟢 completedByFieldRequired | completedByFieldWithValuePasses | completedByFieldWhitespaceOnlyFails (TaskCompletionValidationTests)
65TCOMP-004Task completionCompletion historyHistory list loads for task and sorted correctlyManual + IntegrationP1iOS, Android, Web, DesktopTask with multiple completionsOpen completion historyEntries ordered and accurateMissing images in older completion recordsHistory endpoint returns full listAutomate🟢 test10_completionHistoryLoadsAndIsSorted
66DOC-001DocumentsListLoad all documents and residence-filtered documentsManual + E2E UIP0iOS, Android, Web, DesktopLogged in with docs dataOpen documents tab and residence detail docsCorrect sets shownResidence with zero docsList supports optional residence filterAutomate🟢 test01_NavigateToDocumentsScreen | test20_HandleEmptyDocumentsList | test21_HandleEmptyWarrantiesList
67DOC-002DocumentsCreate documentCreate generic document with required fieldsManual + E2E UIP0iOS, Android, Web, DesktopResidence existsCreate document with title/type/residenceDocument appears in listsMissing residence selection on createCreate requires title/type/residenceAutomate🟢 test04_CreateDocumentWithMinimalFields
68DOC-003DocumentsCreate warranty fieldsCreate warranty/appliance with provider/dates metadataManual + IntegrationP1iOS, Android, Web, DesktopDocument form openEnter warranty-specific fields and saveFields persist and render in detailEnd date before start dateDate validation expectations definedAutomate🟢 test06_CreateWarrantyWithAllFields | test07_CreateWarrantyWithFutureDates | test08_CreateExpiredWarranty
69DOC-004DocumentsEdit documentEdit existing document including type/category/tagsManual + E2E UIP1iOS, Android, Web, DesktopDocument existsModify and saveDetail/list reflect updatesSwitching types with stale fieldsBackend accepts partial updateAutomate🟢 test15_EditDocumentTitle | test16_EditWarrantyDates
70DOC-005DocumentsDelete documentDelete removes from global and residence cachesManual + IntegrationP0iOS, Android, Web, DesktopDocument exists in cachesDelete documentDocument removed everywhereDelete while detail screen openDataManager removeDocument updates both cachesAutomate🟢 test17_DeleteDocument | test18_DeleteWarranty
71DOC-006DocumentsUpload imageUpload document image from camera/galleryManual + IntegrationP0iOS, AndroidPermissions grantedAdd image to documentThumbnail and full image accessibleUpload timeoutUpload endpoint returns image metadataAutomate partially
72DOC-007DocumentsDelete imageDelete specific document image updates detail immediatelyManual + IntegrationP1iOS, Android, Web, DesktopDocument with multiple imagesDelete one imageRemaining images preservedDeleting last imageImage delete endpoint idempotencyAutomate🟢 test22_documentImageSectionExists
73DOC-008DocumentsDownloadDownload/open document file via URLManualP1iOS, Android, Web, DesktopDocument has downloadable URLTap download/openFile retrieved and usableExpired signed URLDownload API wraps binary resultAutomate partially
74DOC-009DocumentsValidationClaim email optional but must be valid if providedManual + UIP2iOSDocument form openEnter invalid claim emailValidation error shownInternationalized domainsEmail regex defines valid formatAutomate🟢 validEmailPasses | invalidEmailMissingAtFails (ValidationHelpersTests + StringExtensionsTests)
75DOC-010DocumentsMedia viewerImage viewer navigation, zoom, swipe, close behaviorManualP2iOS, AndroidDocument with multiple imagesOpen viewer and interactNo crashes; correct index and gesturesVery large imagesViewer supports list index initializationManual
76CON-001ContractorsListLoad contractors with empty and populated statesManual + E2E UIP0iOS, Android, Web, DesktopLogged inOpen contractors tabList/empty state correctLarge list pagination if anyAPI supports optional filtersAutomate🟢 test16_refreshContractorsList
77CON-002ContractorsCreateCreate contractor minimal required fieldsManual + E2E UIP0iOS, Android, Web, DesktopLogged inCreate contractor with nameContractor appears in list/detailSpecial characters in namesName is requiredAutomate🟢 test03_createContractorWithMinimalData
78CON-003ContractorsCreate optional dataPersist optional company/contact/address/specialtiesManual + IntegrationP1iOS, Android, Web, DesktopContractor form openFill optional fields and saveAll values persist accuratelyInvalid website URL formatOptional fields may be nullAutomate🟢 test04_createContractorWithAllFields | test14_updateAllContractorFields
79CON-004ContractorsEmail validationOptional email must be valid if suppliedManual + UIP1iOS, Android, Web, DesktopContractor form openEnter invalid emailValidation error blocks saveUppercase email + spacesValidation trims and regex-checksAutomate🟢 validEmailPasses | invalidEmailMissingAtFails | invalidEmailMissingDomainFails (ValidationHelpersTests + StringExtensionsTests)
80CON-005ContractorsEditEdit contractor and verify list/detail syncManual + E2E UIP1iOS, Android, Web, DesktopExisting contractorUpdate fields and saveUpdated across viewsConcurrent remote updateDataManager updateContractor handles summary mappingAutomate🟢 test13_editContractorName | test14_updateAllContractorFields
81CON-006ContractorsDeleteDelete contractor removes from caches and residence associationsManual + IntegrationP0iOS, Android, Web, DesktopExisting contractorDelete contractorRemoved from all viewsDeleting favorite contractorAssociation cleanup server-sideAutomate🟢 test08_contractorCRUD
82CON-007ContractorsFavorite toggleToggle favorite updates UI and persistenceManual + E2E UIP1iOS, Android, Web, DesktopExisting contractorToggle favorite twiceState toggles correctly and persists refreshRapid repeated tapsEndpoint supports idempotent togglesAutomate🟢 test20_toggleContractorFavorite
83CON-008ContractorsBy residence filterLoad contractors scoped to residenceManual + IntegrationP1iOS, Android, Web, DesktopMultiple residences and linked contractorsOpen residence contractor sectionOnly related contractors shownContractor with null residenceFiltering done server-sideAutomate🟢 test21_contractorByResidenceFilter
84CON-009ContractorsShare exportShare contractor as .casera fileManualP1AndroidContractor existsTap share contractorShare sheet opens with valid file payloadName containing '/' and long lengthFilename sanitization appliedManual
85CON-010ContractorsImport .caseraImport contractor from valid fileManual + IntegrationP0AndroidLogged in, valid contractor fileOpen file/import confirmContractor created and success dialog shownUnknown specialty names in fileSpecialties mapped by name to known IDsAutomate partially
86CON-011ContractorsImport invalid fileInvalid extension/JSON/auth state handled safelyManualP0AndroidInvalid file or logged outAttempt importClear error shown; no partial creationHuge malformed JSONImport parser errors are surfacedManual
87NOTIF-001NotificationsPermission promptNotification permission request outcomes handledManualP0iOS, AndroidFresh installRespond Allow and Deny in separate runsApp continues gracefully; state reflects permissionUser changes setting laterPermission checked on foregroundManual
88NOTIF-002NotificationsDevice registrationRegister device token after login onlyManual + IntegrationP0iOS, AndroidHave APNs/FCM tokenLogin with token availableregisterDevice called once and succeedsToken arrives before authAuth gating prevents unauthenticated registrationAutomate
89NOTIF-003NotificationsToken refreshNew push token triggers backend re-registrationManual + IntegrationP1iOS, AndroidPreviously registered tokenSimulate token rotationBackend receives updated registration idNo token change should skip callLast registered token cache usedAutomate
90NOTIF-004NotificationsForeground notificationForeground notifications display banner/sound and update read stateManualP1iOS, AndroidPermission granted, send test pushReceive push while app activeBanner shown; notification handledMalformed payload missing typeForeground presentation explicitly enabledManual
91NOTIF-005NotificationsNotification tap navigationTap task push opens app and routes to tasks contextManual + E2EP0iOS, AndroidTask-linked push sentTap push from background/terminatedApp opens on tasks flow for target taskTask no longer existsTask id may be string or intAutomate partially
92NOTIF-006NotificationsAction buttons premiumPremium users see and can execute task action buttonsManual + IntegrationP0iOS, AndroidPremium subscription activeReceive actionable task notification, tap actionAction API executes and UI refreshesAction timeout/network lossActions gated by premium/limitationsEnabledManual🟢 encodeDecodeRoundTrip | decodedValuesMatch | sameValuesAreEqual | differentTaskIdNotEqual | differentTaskTitleNotEqual | taskIdReturnsCorrectValue | taskTitleReturnsCorrectValue (WidgetActionTests)
93NOTIF-007NotificationsAction buttons free-tier gatingFree users with limitations enabled are routed home/not allowed actionsManualP0iOS, AndroidFree user limitationsEnabled=trueTap actionable notificationNo privileged task action executedSubscription cache stale nilNil subscription defaults allow on iOS currentlyManual🟢 encodeDecodeRoundTrip | sameValuesAreEqual | differentTaskIdNotEqual | differentTaskTitleNotEqual (WidgetActionTests)
94NOTIF-008NotificationsPreferencesLoad and update notification preference togglesManual + IntegrationP1iOS, Android, Web, DesktopLogged inOpen notification preferences, toggle settings, savePreferences persist and affect server payloadsPartial update failuresPreferences API supports patch/updateAutomate
95NOTIF-009NotificationsHistory/read stateNotification history list and mark-read operationsManual + IntegrationP2iOS, Android, Web, DesktopNotifications existOpen history, mark one and mark allUnread counts decrement correctlyRace with incoming pushUnread count endpoint consistentAutomate
96SUB-001SubscriptionStatus loadSubscription status loads at app launch/foregroundManual + IntegrationP0iOS, Android, Web, DesktopLogged inLaunch then background/foreground appStatus cache updates and UI gating accurateBackend temporarily unavailableStatus refresh should be non-fatalAutomate
97SUB-002SubscriptionUpgrade screen productsLoad purchasable plans and pricingManualP0iOS, AndroidStore config presentOpen upgrade screenMonthly/annual products displayedStore connectivity issuesProduct IDs configured as expectedManual + mocked automation
98SUB-003SubscriptionPurchase monthlyComplete monthly purchase and backend verificationManual + IntegrationP0iOS, AndroidSandbox account, product availableBuy monthly planEntitlement granted, subscription status becomes proPending transactionsVerification endpoint must return successManual
99SUB-004SubscriptionPurchase annualComplete annual purchase and backend verificationManual + IntegrationP0iOS, AndroidSandbox accountBuy annual planEntitlement granted and reflected in appUpgrade/downgrade from existing planLatest transaction determines tierManual
100SUB-005SubscriptionRestore purchasesRestore on clean install/device migrationManual + IntegrationP0iOS, AndroidExisting prior subscriptionTap restoreEntitlements restored and backend syncedNo previous purchasesRestore should not duplicate grantsManual
101SUB-006SubscriptionPurchase cancellationUser-cancelled purchase does not show fatal errorManualP1iOS, AndroidOpen paywallStart then cancel purchaseNo entitlement changes; UX remains stableRepeated cancel attemptsUser cancel considered non-errorManual
102SUB-007SubscriptionBackend verification failureStore purchase succeeds but backend verify failsManualP0iOS, AndroidForce backend verify failureComplete purchaseUser sees recoverable state and can retry/restoreReceipt parsing mismatchApp should avoid false pro unlockManual
103SUB-008SubscriptionFeature gatingPro-only features hidden/disabled for limited usersManual + E2EP0iOS, Android, Web, DesktopTest free and pro accountsTraverse gated features (actions, limits, upgrades)Gating consistent across surfacesCache stale after plan changeGating uses subscription status + limitationsEnabledAutomate
104WID-001WidgetsSmall widget renderingSmall widget shows counts and opens appManualP1AndroidWidget added, logged inPlace small widget and tapCorrect counts; tap opens appNo data cached yetWidget reads from shared preferences stateManual
105WID-002WidgetsMedium widget listMedium widget shows top tasks and overdue badgeManualP1AndroidTasks existPlace medium widgetTask rows and overdue badge correctMalformed tasks_jsonJSON parse fallback to empty listManual
106WID-003WidgetsLarge widget interactionsLarge widget actions execute for pro usersManual + IntegrationP0AndroidPro account, widget configuredTap row and action controlsOpens task or executes action as expectedFree user should not see/execute pro actionsWidget passes task_id in intentManual🟢 encodeDecodeRoundTrip | decodedValuesMatch | taskIdReturnsCorrectValue | taskTitleReturnsCorrectValue (WidgetActionTests)
107WID-004WidgetsWidget refreshWidgets refresh after task state changesManualP1AndroidWidget presentComplete/cancel task in appWidget counts/list update within expected intervalBackground restrictionsWidget update manager triggers refreshManual
108SHR-001Sharing/ImportFile association.casera files open app import flowManualP1AndroidHave .casera fileOpen file from files app/share sheetImport confirmation dialog shownMultiple apps can open same MIMEIntent filter handles application/json with extensionManual
109SHR-002Sharing/ImportSecurityImport rejects when unauthenticatedManualP0AndroidLogged out, .casera file readyAttempt importError shown, no data mutationStale token in storageAuth check occurs before API callManual
110SHR-003Sharing/ImportCorrupt payloadCorrupt .casera payload fails safely without crashManualP0AndroidMalformed JSON fileAttempt importGraceful error dialogVery large payloadParser exceptions are caughtManual
111DATA-001Data layerLookups initSeeded lookup data loads once and marks initializedManual + IntegrationP0iOS, Android, Web, DesktopFresh loginObserve first data bootstrapLookups available for forms/templatesSlow network during bootstrapinitializeLookups has concurrency guardAutomate🟢 test06_lookupDataAvailable | setTaskCategoriesPopulatesList | setTaskCategoriesBuildsMappedLookup | setTaskPrioritiesPopulatesListAndMap | setTaskFrequenciesPopulatesListAndMap | setResidenceTypesPopulatesListAndMap | setContractorSpecialtiesPopulatesListAndMap | markLookupsInitializedSetsFlag (DataLayerTests)
112DATA-002Data layerETag refreshLookup refresh uses ETag and handles 304 not modifiedManual + IntegrationP1iOS, Android, Web, DesktopLookups already loaded + ETagForeground app or force refreshNo unnecessary data churn on 304ETag lost between sessionsETag persisted in storageAutomate🟢 staticDataEndpointReturnsETag | conditionalRequestReturns304WhenDataUnchanged | staleETagReturns200 (DataLayerETagTests)
113DATA-003Data layerLegacy fallbackIf seeded-data endpoint fails, fallback static data path worksManual + IntegrationP1iOS, Android, Web, DesktopMock seeded endpoint failureInitialize lookupsCore lookups still availableTemplates missing in fallbackFallback endpoint still reachableAutomate🟢 staticDataContainsAllRequiredLookupTypes | allLookupItemsHaveIdAndName | taskCategoriesHaveColorAndIcon | taskPrioritiesHaveLevelAndColor (DataLayerAPISchemaTests)
114DATA-004Data layerCache timeoutOne-hour cache timeout triggers fresh fetch after expiryManual + IntegrationP1iOS, Android, Web, DesktopCached data older/newer than timeoutRequest data with forceRefresh=falseValid cache reused; stale cache refetchedClock skew/device time changesTimeout constant is 3600000 msAutomate🟢 cacheTimeZeroIsInvalid | recentCacheTimeIsValid | expiredCacheTimeIsInvalid | cacheTimeoutConstantIsOneHour | allCacheTimestampsStartAtZeroAfterClear (DataLayerTests.CacheValidationTests)
115DATA-005Data layerCache invalidation on logoutLogout clears user data/cache/ETag but retains themeManual + IntegrationP0iOS, Android, Web, DesktopLogged in with populated dataLogout then inspect next launchNo user data remains; theme preference retainedPersistence clear implementation driftTheme stored separately from persistenceManager.clearAutomate🟢 testR206_postLogoutMainAppIsNoLongerAccessible | clearResetsAllCacheTimestamps | clearEmptiesLookupLists | clearResetsLookupsInitializedFlag | clearUserDataKeepsLookups | clearUserDataResetsCacheTimestamps (DataLayerTests.ClearTests)
116DATA-006Data layerDisk persistenceCurrent user and lookups reload correctly after app restartManual + IntegrationP1iOS, Android, Web, DesktopLogged in and data loadedKill and relaunch appState restored without full refetch where validPartial/corrupt persisted JSONDeserializer ignoreUnknownKeys is enabledAutomate🟢 test08_diskPersistencePreservesLookupsAfterRestart
117DATA-007Data layerMap/list consistencyLookup map IDs and list values remain consistent after updatesUnit + IntegrationP2iOS, Android, Web, DesktopLookup update operationCompare list and map representationsNo missing or mismatched IDsDuplicate IDs from backendMaps are built via associateBy(id)Automate🟢 setTaskCategoriesBuildsMappedLookup | getterReturnsNilForMissingId | getterReturnsNilForNilId | allIdsAreUniquePerLookupType (DataLayerTests.LookupSetterTests + DataLayerAPISchemaTests)
118OFF-001ResilienceOffline launchOffline launch with cached token/data behaves gracefullyManualP0iOS, Android, Web, DesktopPreviously logged in with cached dataLaunch with network offNo crash; clear messaging; cached UI where possibleToken validation cannot reach serverCurrent behavior may clear session on fetch failureManual
119OFF-002ResilienceOffline action handlingCreate/update actions fail with retriable errors when offlineManualP0iOS, Android, Web, DesktopNetwork disabledAttempt create/edit/delete flowsErrors shown; no phantom local successIntermittent network flapsNo offline queue currently assumedManual
120OFF-003ResilienceRetry behaviorRetry from error dialogs succeeds without stale UI stateManual + E2EP1iOS, Android, Web, DesktopForce transient API failureTap retry then restore networkAction succeeds and loading/error states resetDouble-tap retry raceApiResult state machine handles Idle/Loading/ErrorAutomate🟢 testP010_retryButtonExistsOnErrorState
121OFF-004ResilienceIdempotency UXDouble submit protection for create flowsManual + UIP1iOS, Android, Web, DesktopOpen any create formRapid tap saveSingle record createdVery slow API responseButtons disabled during loadingAutomate🟢 test19_doubleSubmitProtection
122SEC-001SecurityAuth boundariesProtected endpoints reject without token and UI handles 401Manual + IntegrationP0iOS, Android, Web, DesktopNo tokenAttempt protected operationsRedirect/login prompt or clear errorToken injected but expiredAPILayer checks token before API in many callsAutomate🟢 test05_crossUserAccessControl
123SEC-002SecuritySession cleanupSensitive data not accessible after logout and app restartManualP0iOS, Android, Web, DesktopLogged in then logoutForce close and relaunchNo protected screens/data accessibleWidget still showing stale dataWidget caches should be cleared on logout (iOS path)Manual🟢 testR206_postLogoutMainAppIsNoLongerAccessible
124SEC-003SecurityImport validationImported files cannot execute code or break parser boundariesManualP1AndroidCraft malicious JSON payloadImport payloadApp rejects safely, no crashOversized strings, deep nestingDeserializer should throw and be caughtManual
125SEC-004SecurityPII exposureLogs and analytics avoid leaking sensitive credential valuesManual + Code auditP1iOS, Android, Web, DesktopEnable debug loggingRun auth/payment flowsNo passwords/tokens in logs/eventsThird-party SDK auto-capture riskPostHog config reviewedManual
126PERF-001PerformanceCold startStartup time within target for logged-out and logged-in statesManual + PerfP1iOS, AndroidProfile build with instrumentationMeasure cold launchMeets agreed startup SLASlow network path for verified userAuth check performs network callAutomate perf
127PERF-002PerformanceLarge data renderingTask/document/contractor lists remain responsive with large datasetsManual + PerfP1iOS, Android, Web, DesktopSeed large datasetScroll and interact listsNo jank/crash; acceptable memoryThousands of items and imagesVirtualized list behavior depends on platformManual + benchmarks🟢 test17_residenceListPerformance | test14_taskListPerformance | test19_contractorListPerformance
128PERF-003PerformanceImage handlingLarge image capture/upload/compression memory stabilityManual + PerfP0iOS, AndroidUse high-resolution photosAttach multiple imagesNo OOM/crash; upload completes or fails gracefullyLow-memory deviceImageCompressor platform implementations are activeManual
129PERF-004PerformanceBackground operationsForeground/resume refresh does not block UI threadManual + PerfP2iOS, AndroidApp with valid sessionBackground then foreground repeatedlyUI remains interactive during refreshConcurrent refresh and navigationLookups refresh runs asyncManual🟢 test16_residencePersistsAfterBackgroundingApp | test13_taskPersistsAfterBackgroundingApp | test18_contractorPersistsAfterBackgroundingApp
130A11Y-001AccessibilityBasic semanticsAll primary controls have accessible labels/identifiersManualP0iOS, Android, Web, DesktopScreen reader onTraverse major flowsControls are announced clearlyCustom components lacking labelsAccessibility identifiers partly definedManual + lint🟢 testA001_OnboardingPrimaryControlsAreReachable | testA003_CoreControlsExposeIdentifiers | testA004_ValuePropsScreenControlsAreReachable | testA005_NameResidenceScreenControlsAreReachable | testA006_CreateAccountScreenControlsAreReachable
131A11Y-002AccessibilityDynamic typeText scales correctly without clipping in key screensManualP1iOS, AndroidLarge accessibility font settingsOpen forms/lists/dialogsLayout remains usableLong localized stringsDesign system supports flexible layoutManual
132A11Y-003AccessibilityKeyboard navigationTab/focus order valid on web/desktop formsManualP1Web, DesktopHardware keyboardNavigate forms using keyboard onlyLogical focus traversal and visible focus statesModal dialogs focus trapCompose/web focus handling may differManual
133A11Y-004AccessibilityColor contrastTheme variants meet minimum contrast requirementsManual + ToolingP1iOS, Android, Web, DesktopCycle themesInspect text/icon contrastWCAG contrast thresholds metError/success states on tinted backgroundsMultiple custom themes supportedManual + automated audit
134I18N-001LocalizationString coverageNo missing keys/placeholders across supported localesManual + Static checkP1iOS, Android, Web, DesktopRun app in each localeTraverse major screensNo raw keys, no placeholder mismatchesPluralization and gender stringsLocales include es/fr/de/it/ja/ko/nl/pt/zh etc.Automate (lint + screenshot)
135I18N-002LocalizationLayout expansionLong translations do not break onboarding/forms/buttonsManualP1iOS, Android, Web, DesktopSwitch to longest-string localeReview high-density screensNo clipping/overlapRTL future locale supportCurrent locales may be LTR onlyManual
136THEME-001ThemingTheme persistenceTheme choice persists across app restartsManual + IntegrationP1iOS, Android, Web, DesktopLogged in or logged outChange theme then relaunchSelected theme reappliedTheme ID missing/corrupt in storageTheme stored separately from auth dataAutomate🟢 defaultThemeIdIsDefault | setThemeIdUpdatesValue | clearDoesNotResetTheme | themeIdIsPreservedAsOceanAfterClear (ThemePersistenceTests) | test09_themePersistsAcrossRestart
137THEME-002ThemingTheme switch live updateChanging theme updates active screen without broken statesManual + UIP2iOS, Android, Web, DesktopOpen app on any tabChange theme in profile/settingsImmediate UI recolor with legible componentsTransition while modal openTheme manager publishes updatesManual🟢 allCasesCountIsEleven | allDisplayNamesAreNonEmpty | allDescriptionsAreNonEmpty | rawValueRoundTripsForAllCases | allRawValuesAreUnique | brightDisplayNameIsDefault | oceanRawValueIsOcean (ThemeIDTests)
138NAV-001NavigationBottom tabsResidences/Tasks/Contractors/Documents tabs navigate and preserve expected stateManual + E2E UIP0iOS, AndroidLogged inSwitch tabs repeatedlyCorrect screens shown; no stuck navigationPush navigation then tab switch backNested nav stacks differ per platformAutomate🟢 test03_navigationBetweenTabs | test10_navigateBetweenTabs | testR309_navigationAcrossPrimaryTabsAndBackToResidences
139NAV-002NavigationBack stack safetyBack from details/forms returns to correct parentManual + E2E UIP0iOS, Android, Web, DesktopNavigate into detail/edit screensUse back gestures/buttonsParent state intact and refreshed as expectedDirect deep-link entry without parentSaved-state refresh flags used in KMP navAutomate🟢 test02_cancelRegistration | test04_cancelResidenceCreation | test02_cancelTaskCreation | test19_CancelDocumentCreation
140NAV-003NavigationDuplicate routesAvoid duplicate screen instances from repeated tap/navigation actionsManualP2iOS, Android, Web, DesktopRapidly tap nav actionsObserve back stack and UINo duplicate stacking or loopsDouble tap race conditionsNavHost popUpTo rules appliedManual🟢 testP003_RapidDoubleTapOnValuePropsContinueLandsOnNameResidence | testP004_StartFreshThenBackToWelcomeThenJoinExistingDoesNotCorruptState | testP005_RepeatedLoginNavigationRemainsStable
141ANL-001AnalyticsAuth eventsLogin/register/logout/verify events fire once with correct propertiesManual + IntegrationP2iOS, AndroidAnalytics enabled in test envPerform auth flowsExpected events emitted onceRetries causing duplicate eventsEvent taxonomy defined in analytics layerAutomate with mocked sink
142ANL-002AnalyticsCore feature eventsResidence/task/document/contractor create-edit-delete events trackedManual + IntegrationP2iOS, AndroidAnalytics test workspacePerform CRUD actionsEvents mapped to correct featureFailed actions should not emit successPostHog wrappers used consistentlyAutomate
143ANL-003AnalyticsSubscription eventsUpgrade prompt open, purchase, restore, verification outcomes trackedManual + IntegrationP2iOS, AndroidStore sandbox + analyticsRun subscription flowsLifecycle events present and correctly attributedPurchase canceled pathNo sensitive receipt data in eventsManual
144QA-001Cross-platform parityFeature parityCore flows behave equivalently between KMP UI and iOS native UIManual regressionP0iOS, Android, Web, DesktopSame seeded accountRun same scenarios on each platformEquivalent outcomes and data integrityKnown UX differences documentediOS native app is source for iOS UXManual
145QA-002Cross-platform parityAPI contract consistencyAll clients handle new/unknown JSON fields gracefullyIntegrationP1iOS, Android, Web, DesktopBackend adds extra fieldsRun major endpointsNo crash; fields ignored where unknownType changes breaking parsingKotlin serializers set ignoreUnknownKeysAutomate🟢 widgetTaskDecodesWithExtraFields | widgetTaskIgnoresUnknownNestedObjects (JSONUnknownFieldsResilienceTests)
146QA-003Release qualitySmoke suiteMinimal release gate across auth, residence, task, document, contractor, notification, subscriptionManual + AutomatedP0iOS, AndroidRelease candidate buildRun smoke checklistNo blockers before releaseEnvironment instabilitySmoke should run against stable test backendAutomate + manual signoff🟢 test01_authenticationFlow | test02_residenceCRUDFlow | test03_taskLifecycleFlow | test08_contractorCRUD | test01_NavigateToDocumentsScreen
147QA-004Release qualityData migrationUpgrade app version preserves critical local state safelyManualP1iOS, Android, Web, DesktopInstall old build with data then upgradeLaunch and use appNo corruption; expected resets onlySchema/key changes in persistencePersistence keys remain compatibleManual