Files
honeyDueKMP/docs/android_greenfield_test_plan.csv
treyt fc0e0688eb Add comprehensive iOS unit and UI test suites for greenfield test plan
- Create unit tests: DataLayerTests (27 tests for DATA-001–007), DataManagerExtendedTests
  (20 tests for TASK-005, TASK-012, TCOMP-003, THEME-001, QA-002), plus ValidationHelpers,
  TaskMetrics, StringExtensions, DoubleExtensions, DateUtils, DocumentHelpers, ErrorMessageParser
- Create UI tests: AuthenticationTests, PasswordResetTests, OnboardingTests, TaskIntegration,
  ContractorIntegration, ResidenceIntegration, DocumentIntegration, DataLayer, Stability
- Add UI test framework: AuthenticatedTestCase, ScreenObjects, TestFlows, TestAccountManager,
  TestAccountAPIClient, TestDataCleaner, TestDataSeeder
- Add accessibility identifiers to password reset views for UI test support
- Add greenfield test plan CSVs and update automated column for 27 test IDs
- All 297 unit tests pass across 60 suites

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 15:37:56 -06:00

45 KiB

1Test_IDDomainFeatureScenarioTest_MethodPriorityPlatformsPreconditionsStepsExpected_ResultEdge_CasesAssumptionsAutomation_Recommendation
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)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
18AUTH-017AuthenticationPassword resetMismatched password confirmation blockedManual + UIP1iOS, Android, Web, DesktopReset password screenEnter mismatchInline error; no reset requestTrailing spacesClient validates before submitAutomate
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
77CON-002ContractorsCreateCreate contractor minimal required fieldsManual + E2E UIP0iOS, Android, Web, DesktopLogged inCreate contractor with nameContractor appears in list/detailSpecial characters in namesName is requiredAutomate
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
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
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
81CON-006ContractorsDeleteDelete contractor removes from caches and residence associationsManual + IntegrationP0iOS, Android, Web, DesktopExisting contractorDelete contractorRemoved from all viewsDeleting favorite contractorAssociation cleanup server-sideAutomate
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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