Commit Graph

272 Commits

Author SHA1 Message Date
Trey T
224f6643bf P6 Stream U: AuthenticatedImage composable + CoilAuthInterceptor
Token-aware image loading matching iOS AuthenticatedImage.swift.
Bearer header attachment, 401-triggered refresh+retry, placeholder on error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:10:59 -05:00
Trey T
19471d780d P2 Stream H: standalone TaskSuggestionsScreen
Port iOS TaskSuggestionsView as a standalone route reachable outside
onboarding. Uses shared suggestions API + accept/skip analytics in
non-onboarding variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:10:47 -05:00
Trey T
7d71408bcc Fix: add WidgetDataRepository.isPendingCompletion predicate
Stream M's WidgetActionProcessorTest.kt references this predicate but
Stream J's initial repo only exposed mark/clear mutators. Trivial addition:
reads the pending-completion set and checks membership.

Unblocks :composeApp:testDebugUnitTest (now green across all streams).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:56:20 -05:00
Trey T
ee135c4673 P2 Stream G: TaskTemplatesBrowserScreen (replaces dialog/sheet)
Full browse-and-select experience matching iOS TaskTemplatesBrowserView.
Category filter, multi-select, bulk-create with templateId backlink.
Analytics events wired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:56:01 -05:00
Trey T
1fcb456ef1 P3 Stream K: Glance widgets (small/medium/large) matching iOS
- HoneyDueSmallWidget (2x2), HoneyDueMediumWidget (4x2),
  HoneyDueLargeWidget (4x4) rewritten to consume the
  iOS-parity WidgetDataRepository (Stream J).
- Free-tier shows a large count-only layout (matches iOS
  FreeWidgetView); premium shows task list + complete buttons
  (Large widget also renders the Overdue / 7 Days / 30 Days
  stats row from WidgetDataRepository.computeStats()).
- WidgetFormatter mirrors iOS formatWidgetDate: "Today" /
  "in N day(s)" / "N day(s) ago".
- WidgetColors maps priority levels (1-4) to primary/yellow/
  accent/error, matching iOS OrganicTaskRowView.priorityColor.
- WidgetUi shared Glance composables (TaskRow, WidgetHeader,
  EmptyState, TaskCountBlock, StatPill, StatsRow, CompleteButton)
  wired to Stream M's CompleteTaskAction for interactive rows.
- JVM tests: WidgetFormatterTest + WidgetColorsTest covering
  10 formatter assertions and 11 color mapping assertions.

Glance caveats: no radial/linear gradients or custom shapes, so
iOS's "organic" glows are dropped in favor of cream background +
tinted TaskRow cards. Colors, typography, and priority semantics
match iOS exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:55:08 -05:00
Trey T
dbff329384 P3 Stream L: widget refresh scheduler (WorkManager, iOS cadence)
WidgetRefreshSchedule: 30-min day / 120-min overnight (6am–11pm split).
WidgetRefreshWorker: CoroutineWorker fetches via APILayer -> repo -> widget.update.
WidgetUpdateManager: chained one-time enqueue pattern (WorkManager PeriodicWork
can't vary cadence).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:54:35 -05:00
Trey T
58b9371d0d P3 Stream M: CompleteTaskAction (widget interactive completion)
Glance ActionCallback wires to WidgetActionProcessor: premium marks pending +
calls API + refreshes; free tier opens paywall deep link instead. Idempotent,
rollback-safe on API failure.

Also fixes a one-line compile error in WidgetTaskActionReceiver.kt where
updateAllWidgets() had been removed by Stream L — swapped for forceRefresh()
so the build stays green. The legacy receiver is now redundant (replaced by
CompleteTaskAction) but deletion is deferred to a Stream K follow-up so the
AndroidManifest entry can be removed in the same commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:52:01 -05:00
Trey T
6b3e64661f P2 Stream D: ThemeSelectionScreen (replaces ThemePickerDialog)
Full-screen theme picker with 11 theme previews matching iOS
ThemeSelectionView. Live preview on tap. Old dialog deleted and
call-sites migrated to the new route.

Tests use the state-logic fallback pattern (plain kotlin.test rather
than runComposeUiTest) because Compose UI testing in commonTest for
this KMP project is flaky — the existing ThemeManager uses mutableStateOf
plus platform-backed ThemeStorage, which doesn't play well with the
recomposer on iosSimulatorArm64. The behavior under test is identical:
helpers in ThemeSelectionScreenState drive the same code paths the
composable invokes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:50:00 -05:00
Trey T
0d50726490 P4 Stream N: FCM service + NotificationChannels matching iOS categories
FcmService + NotificationPayload + 4 NotificationChannels (task_reminder,
task_overdue, residence_invite, subscription) parity with iOS
NotificationCategories.swift. Deep-link routing from payload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:45:37 -05:00
Trey T
6d7b5ee990 P3 Stream J: widget data repository (DataStore-backed)
Ports iOS WidgetDataManager.swift semantics. DTO + JSON serialization +
pending-completion tracking + stats (overdueCount / dueWithin7 / dueWithin8To30).
Same-process DataStore is sufficient for Glance widgets.

Unblocks Streams K (widgets) / L (scheduler) / M (actions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:40:48 -05:00
Trey T
7aab8b0f29 P1 Stream B: port iOS brand assets to Android
- outline, tab_view, app_icon_mark, widget_icon: rasterized from iOS
  PDF/PNG sources at 1024px (gradients/shadows would flatten via SVG trace)
- honeycomb_texture: hand-authored VectorDrawable, seamless hex tiling
  verified at 4x4 render
- widget_icon: adaptive icon (mipmap-anydpi-v26) + density-specific
  mipmap + foreground bitmaps (mdpi..xxxhdpi)
- Source PDFs preserved in docs/ios-parity/source-assets/ for future
  re-rasterization

AssetInventoryTest asserts all 5 Res.drawable entries resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:35:31 -05:00
Trey T
db181c0d6a P1 Stream C: organic design primitives (BlobShape, RadialGlow, HoneycombOverlay)
Ports iOS OrganicDesign.swift primitives to Compose Multiplatform:
- BlobShape: seeded deterministic irregular shape
- RadialGlow: radial-gradient backdrop composable
- HoneycombOverlay: tiled hex pattern modifier
- OrganicRadius constants matching iOS

Determinism guaranteed by parametrized tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:34:47 -05:00
Trey T
dcab30f862 P1 Stream A: design tokens — verify color parity with iOS + typography
11 themes x 9 colors x 2 modes (198 values) now parametrized-tested against
docs/ios-parity/colors.json as ground truth. Typography scale matches iOS
dynamic-type defaults.

118 of 198 color values were off before — mostly off-by-one RGB rounding
errors introduced during a prior hand-copy from iOS. Default TextSecondary
(light+dark) also lost its 0x99 alpha channel — now restored via
Color(0xAARRGGBB) packed literals. Added SansSerif fontFamily and source
citations on every Typography size so the iOS dynamic-type mapping is
explicit.

Tests: ThemeColorsTest (4), TypographyTest (5), SpacingTest (1) — all
green. `everyColorMatchesIosGroundTruth` walks the embedded JSON and
asserts 198 hex values match exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:32:52 -05:00
Trey T
74adaab6df P0.2: Android test infrastructure (TDD foundation)
- Add androidUnitTest source set: JUnit 4, Robolectric 4.14.1, mockk, androidx.test
- Add androidInstrumentedTest source set: androidx.test.ext, espresso, mockk-android
- Pin Robolectric to SDK 34 (Robolectric 4.14.1 doesn't yet support compileSdk 36)
- Enable includeAndroidResources for Robolectric
- Canary tests green on both source sets

Verifies:
  ./gradlew :composeApp:testDebugUnitTest
  ./gradlew :composeApp:compileDebugAndroidTestSources

Part of Android -> iOS parity plan (rc-android-ios-parity.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:25:50 -05:00
Trey T
42b7392f39 P0.1: iOS reference artifacts (colors, assets, screens inventory) 2026-04-18 12:22:41 -05:00
Trey T
a4d66c6ed1 Stabilize UI test suite — 39% → 98%+ pass rate
Fix root causes uncovered across repeated parallel runs:

- Admin seed password "test1234" failed backend complexity (needs
  uppercase). Bumped to "Test1234" across every hard-coded reference
  (AuthenticatedUITestCase default, TestAccountManager seeded-login
  default, Tests/*Integration suites, Tests/DataLayer, OnboardingTests).

- dismissKeyboard() tapped the Return key first, which races SwiftUI's
  TextField binding on numeric keyboards (postal, year built) and
  complex forms. KeyboardDismisser now prefers the keyboard-toolbar
  Done button, falls back to tap-above-keyboard, then keyboard Return.
  BaseUITestCase.clearAndEnterText uses the same helper.

- Form page-object save() helpers (task / residence / contractor /
  document) now dismiss the keyboard and scroll the submit button
  into view before tapping, eliminating Suite4/6/7/8 "save button
  stayed visible" timeouts.

- Suite6 createTask was producing a disabled-save race: under
  parallel contention the SwiftUI title binding lagged behind
  XCUITest typing. Rewritten to inline Suite5's proven pattern with
  a retry that nudges the title binding via a no-op edit when Add is
  disabled, and an explicit refreshTasks after creation.

- Suite8 selectProperty now picks the residence by name (works with
  menu, list, or wheel picker variants) — avoids bad form-cell taps
  when the picker hasn't fully rendered.

- run_ui_tests.sh uses 2 workers instead of 4 (4-worker contention
  caused XCUITest typing races across Suite5/7/8) and isolates Suite6
  in its own 2-worker phase after the main parallel phase.

- Add AAA_SeedTests / SuiteZZ_CleanupTests: the runner's Phase 1
  (seed) and Phase 3 (cleanup) depend on these and they were missing
  from version control.
2026-04-15 08:38:31 -05:00
Trey t
9ececfa48a Wire onboarding task suggestions to backend, delete hardcoded catalog
Both "For You" and "Browse All" tabs are now fully server-driven on
iOS and Android. No on-device task list, no client-side scoring rules.
When the API fails the screen shows error + Retry + Skip so onboarding
can still complete on a flaky network.

Shared (KMM)
- TaskCreateRequest + TaskResponse carry templateId
- New BulkCreateTasksRequest/Response, TaskApi.bulkCreateTasks,
  APILayer.bulkCreateTasks (updates DataManager + TotalSummary)
- OnboardingViewModel: templatesGroupedState + loadTemplatesGrouped;
  createTasks(residenceId, requests) posts once via the bulk path
- Deleted regional-template plumbing: APILayer.getRegionalTemplates,
  OnboardingViewModel.loadRegionalTemplates, TaskTemplateApi.
  getTemplatesByRegion, TaskTemplate.regionId/regionName
- 5 new AnalyticsEvents constants for the onboarding funnel

Android (Compose)
- OnboardingFirstTaskContent rewritten against the server catalog;
  ~70 lines of hardcoded taskCategories gone. Loading / Error / Empty
  panes with Retry + Skip buttons. Category icons derived from name
  keywords, colours from a 5-value palette keyed by category id
- Browse selection carries template.id into the bulk request so
  task_template_id is populated server-side

iOS (SwiftUI)
- New OnboardingTasksViewModel (@MainActor ObservableObject) wrapping
  APILayer.shared for suggestions / grouped / bulk-submit with
  loading + error state (mirrors the TaskViewModel.swift pattern)
- OnboardingFirstTaskView rewritten: buildForYouSuggestions (130 lines)
  and fallbackCategories (68 lines) deleted; both tabs show the same
  error+skip UX as Android; ForYouSuggestion/SuggestionRelevance gone
- 5 new AnalyticsEvent cases with identical PostHog event names to
  the Kotlin constants so cross-platform funnels join cleanly
- Existing TaskCreateRequest / TaskResponse call sites in TaskCard,
  TasksSection, TaskFormView updated for the new templateId parameter

Docs
- CLAUDE.md gains an "Onboarding task suggestions (server-driven)"
  subsection covering the data flow, key files on both platforms,
  and the KotlinInt(int: template.id) wrapping requirement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:25:01 -05:00
Trey T
d545fd463c Fix 10 failing UI tests: kanban scroll, menu-based edit, form submit reliability
- Screens.swift: findTask() now scrolls through kanban columns (swipe left/right)
  to locate tasks rendered off-screen in LazyHGrid
- Suite5: test06/07 use refreshTasks() instead of pullToRefresh() (kanban is
  horizontal), add API call before navigate for server processing delay
- Suite6: test09 opens "Task actions" menu before tapping edit (no detail screen)
- Suite8: submitForm() uses coordinate-based keyboard dismiss, retry tap, and
  longer timeout; test22/23 re-navigate after creation and use waitForExistence

Test results: 141/143 passed (was 131/143). Remaining 2 failures are pre-existing
(Suite1 test11) and flaky/unrelated (Suite3 testR307).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 17:21:31 -05:00
Trey T
5bb27034aa Fix UI test failures: registration dismiss cascade, onboarding reset, test stability
- Fix registration flow dismiss cascade: chain fullScreenCover → sheet onDismiss
  so auth state is set only after all UIKit presentations are removed, preventing
  RootView from swapping LoginView→MainTabView behind a stale sheet
- Fix onboarding reset: set hasCompletedOnboarding directly instead of calling
  completeOnboarding() which has an auth guard that fails after DataManager.clear()
- Stabilize Suite1 registration tests, Suite6 task tests, Suite7 contractor tests
- Add clean-slate-per-suite via AuthenticatedUITestCase reset state
- Improve test account seeding and screen object reliability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 16:11:47 -05:00
Trey T
00e9ed0a96 Add localization strings and iOS test infrastructure
- Expand Localizable.xcstrings with 426 new localization entries
- Add xctestplan files (CI, Cleanup, Parallel, Seed) for structured test runs
- Add run_ui_tests.sh script for UI test execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 20:32:09 -05:00
Trey T
05ee8e0a79 Fix picker capsule clipping and replace custom tab bar with native segmented control
Picker: moved .fixedSize(), .padding, .background, .clipShape outside the Menu
label so the capsule sizing is stable and never clips rounded corners during
menu open/close animation.

Tab bar: replaced custom HStack+underline tab bar with native SwiftUI
Picker(.segmented) for "For You" / "Browse All" tabs.
2026-03-30 11:32:08 -05:00
Trey T
266d540d28 Remove ZIP code step from onboarding, use home profile instead
ZIP code was US-only and redundant now that the suggestion engine
uses home profile features (heating, pool, etc.) for personalization.

Onboarding flow: Welcome → Value Props → Name → Account → Verify →
Home Profile → Task Selection (was: ...Verify → ZIP → Home Profile...)

Removed regionalTemplates references from task selection view.
Both iOS and Compose flows updated.
2026-03-30 11:15:06 -05:00
Trey T
4609d5a953 Smart onboarding: home profile, tabbed tasks, free app
New onboarding step: "Tell us about your home" with chip-based pickers
for systems (heating/cooling/water heater), features (pool, fireplace,
garage, etc.), exterior (roof, siding), interior (flooring, landscaping).
All optional, skippable.

Tabbed task selection: "For You" tab shows personalized suggestions
based on home profile, "Browse All" has existing category browser.
Removed 5-task limit — users can add unlimited tasks.

Removed subscription upsell from onboarding flow — app is free.
Fixed picker capsule squishing bug with .fixedSize() modifier.

Both iOS and Compose implementations updated.
2026-03-30 09:02:27 -05:00
Trey T
8f86fa2cd0 Fix 12 iOS issues: race conditions, data flow, UX
Critical bugs:
- RootView: auth check deferred to .task{} modifier (after DataManager init)
- DataManagerObservable: map conversion failures now logged with key details
- ContractorViewModel: replace stuck boolean flag with time-based suppression
- DocumentViewModel: guard full success.data before image upload

Logic fixes:
- AllTasksView: 300ms delay before animation flag release
- ResidenceViewModel: trigger initializeLookups() if not ready
- TaskFormView: hasDueDate toggle prevents defaulting to today
- OnboardingState: guard isAuthenticated before completing onboarding

UX fixes:
- ResidencesListView: 10-second refresh timeout
- AllTasksView: add button disabled while sheet presented
- TaskViewModel: actionState auto-resets after 3s, explicit reset on consume
2026-03-26 18:01:49 -05:00
Trey T
4d363ca44e Fix API contract mismatches with Go backend
- Document.purchasePrice: String? → Double? (matches Go decimal.Decimal)
- TaskTemplate: add regionId/regionName (Go returns these, KMM was ignoring)
- TaskResponse.completions: add comment explaining separate fetch pattern
- Document: add comments clarifying fileUrl vs mediaUrl usage
2026-03-26 17:06:36 -05:00
Trey T
e4dc3ac30b Add PostHog exception capture for crash reporting
Android: uncaught exception handler sends $exception events with stack
trace to PostHog, flushes before delegating to default handler.
iOS: NSSetUncaughtExceptionHandler captures crashes via PostHogSDK,
avoids @MainActor deadlock by calling SDK directly.
Common: captureException() available for non-fatal catches app-wide.
Platform stubs for jvm/js/wasmJs.
2026-03-26 16:49:30 -05:00
Trey T
af73f8861b iOS VoiceOver accessibility overhaul — 67 files
New framework:
- AccessibilityLabels.swift: centralized A11y struct with VoiceOver strings
- AccessibilityModifiers.swift: reusable .a11yHeader, .a11yDecorative,
  .a11yButton, .a11yCard, .a11yStatValue View extensions

Shared components: decorative elements hidden, stat views combined,
status/priority badges labeled, error views announced, empty states grouped

Cards: ResidenceCard, TaskCard, DynamicTaskCard, ContractorCard,
DocumentCard, WarrantyCard — all grouped with combined labels,
chevrons hidden, action buttons labeled

Main screens: Login, Register, Residences, Tasks, Contractors, Documents —
toolbar buttons labeled, section headers marked, form field hints added

Onboarding: all 10 views — header traits, button hints, task selection
state, progress indicator, decorative backgrounds hidden

Profile/Subscription: toggle hints, theme selection state, feature
comparison table accessibility, subscription button labels

iOS build verified: BUILD SUCCEEDED
2026-03-26 14:51:29 -05:00
Trey T
0d80df07f6 Add biometric lock and rate limit handling
Biometric lock: opt-in Face ID/Touch ID/fingerprint app lock with toggle
in ProfileScreen. Locks on background, requires auth on foreground return.
Platform implementations: BiometricPrompt (Android), LAContext (iOS).

Rate limit: 429 responses parsed with Retry-After header, user-friendly
error messages in all 10 locales, retry plugin respects 429.
ErrorMessageParser updated for both iOS Swift and KMM.
2026-03-26 14:37:04 -05:00
Trey T
334767cee7 Production hardening: password complexity, token refresh, network resilience
Password complexity: real-time validation UI on register, onboarding, and reset screens
  (uppercase, lowercase, digit, min 8 chars) — Compose + iOS Swift
iOS privacy descriptions: camera, photo library, photo save usage strings
Token refresh: Ktor interceptor catches 401 "token_expired", refreshes, retries
Retry with backoff: 3 retries on 5xx/IO errors, exponential delay (1s base, 10s max)
Gzip: ContentEncoding plugin on all platform HTTP clients
Request timeouts: 30s request, 10s connect, 30s socket
Validation rules: split passwordMissingLetter into uppercase/lowercase (iOS Swift)
Test fixes: corrected import paths in 5 existing test files
New tests: HTTP client retry/refresh (9), validation rules
2026-03-26 14:05:33 -05:00
Trey T
af45588503 Add delete account feature to mobile app
- DELETE /api/auth/account/ API call in AuthApi + APILayer
- authProvider field on User model for email vs social auth detection
- DeleteAccountDialog with password (email) or "type DELETE" (social) confirmation
- Red "Delete Account" card on ProfileScreen
- Navigation wired in App.kt (clears data, returns to login)
- 10 i18n strings in strings.xml
- ViewModel unit tests for delete account state
2026-03-26 10:41:17 -05:00
Trey T
2e5dbaea50 Switch API environment to LOCAL for UI test development
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:06:28 -05:00
Trey T
4df8707b92 UI test infrastructure overhaul — 58% to 96% pass rate (231/241)
Major infrastructure changes:
- BaseUITestCase: per-suite app termination via class setUp() prevents
  stale state when parallel clones share simulators
- relaunchBetweenTests override for suites that modify login/onboarding state
- focusAndType: dedicated SecureTextField path handles iOS strong password
  autofill suggestions (Choose My Own Password / Not Now dialogs)
- LoginScreenObject: tapSignUp/tapForgotPassword use scrollIntoView for
  offscreen buttons instead of simple swipeUp
- Removed all coordinate taps from ForgotPasswordScreen, VerifyResetCodeScreen,
  ResetPasswordScreen (Rule 3 compliance)
- Removed all usleep calls from screen objects (Rule 14 compliance)

App fixes exposed by tests:
- ContractorsListView: added onDismiss to sheet for list refresh after save
- AllTasksView: added Task.RefreshButton accessibility identifier
- AccessibilityIdentifiers: added Task.refreshButton
- DocumentsWarrantiesView: onDismiss handler for document list refresh
- Various form views: textContentType, submitLabel, onSubmit for keyboard flow

Test fixes:
- PasswordResetTests: handle auto-login after reset (app skips success screen)
- AuthenticatedUITestCase: refreshTasks() helper for kanban toolbar button
- All pre-login suites use relaunchBetweenTests for test independence
- Deleted dead code: AuthenticatedTestCase, SeededTestData, SeedTests,
  CleanupTests, old Suite0/2/3, Suite1_RegistrationRebuildTests

10 remaining failures: 5 iOS strong password autofill (simulator env),
3 pull-to-refresh gesture on empty lists, 2 feature coverage edge cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:05:37 -05:00
Trey t
0ca4a44bac Update DocumentApi for backend activate/deactivate response change
Backend now returns Document directly instead of wrapped
DocumentActionResponse. Remove unused DocumentActionResponse class.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 23:10:05 -05:00
treyt
5c360a2796 Rearchitect UI test suite for complete, non-flaky coverage against live API
- Migrate Suite4-10, SmokeTests, NavigationCriticalPathTests to AuthenticatedTestCase
  with seeded admin account and real backend login
- Add 34 accessibility identifiers across 11 app views (task completion, profile,
  notifications, theme, join residence, manage users, forms)
- Create FeatureCoverageTests (14 tests) covering previously untested features:
  profile edit, theme selection, notification prefs, task completion, manage users,
  join residence, task templates
- Create MultiUserSharingTests (18 API tests) and MultiUserSharingUITests (8 XCUI
  tests) for full cross-user residence sharing lifecycle
- Add cleanup infrastructure: SuiteZZ_CleanupTests auto-wipes test data after runs,
  cleanup_test_data.sh script for manual reset via admin API
- Add share code API methods to TestAccountAPIClient (generateShareCode, joinWithCode,
  getShareCode, listResidenceUsers, removeUser)
- Fix app bugs found by tests:
  - ResidencesListView join callback now uses forceRefresh:true
  - APILayer invalidates task cache when residence count changes
  - AllTasksView auto-reloads tasks when residence list changes
- Fix test quality: keyboard focus waits, Save/Add button label matching,
  Documents tab label (Docs), remove API verification from UI tests
- DataLayerTests and PasswordResetTests now verify through UI, not API calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:32:13 -05:00
Trey t
cf2e6d8bcc Fix honeycomb grid sizing, alpha, and stroke styling
- Fix hex sizing to use aspectRatio layout instead of GeometryReader
- Remove hardcoded height estimation that caused gap between header and grid
- Set fill alpha to 0.3 and add 0.7 alpha stroke on colored hexagons
- Use 12 rows consistently
- Add forceRefresh parameter to getResidence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:44:41 -05:00
Trey t
7689027bdd Add honeycomb completion heatmap and dev API environment
- Add HoneycombSummaryView component with colored hexagon grid
- Display completion summary on residence detail screen
- Add CompletionSummary model to KMP shared layer
- Add DEV/PROD environment split in ApiConfig
- Fix ResidenceResponse initializers for completionSummary parameter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:05:11 -05:00
Trey t
b8360a2e86 Reformat Localizable.xcstrings whitespace
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:23:44 -05:00
Trey t
affc45e1b1 Add honeycomb pattern to widgets and fix PostHog anonymous user tracking
- Widget containerBackground now shows honeycomb texture when toggle is enabled
- Change PostHog personProfiles from .never to .always so anonymous sessions
  and unique visitors are properly counted without identifying users

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:13:19 -06:00
Trey t
73dd440d7b Add honeycomb pattern toggle and make theme switching reactive
Adds a toggleable honeycomb hexagonal grid overlay (matching the website pattern)
that can be enabled independently of any theme via the Appearance screen. Uses a
cached tiled UIImage approach consistent with the existing grain texture system.

Replaces the destructive refreshID-based theme switching (which destroyed all
NavigationStacks and dismissed sheets) with @Observable AppThemeSource. Color
resolution now happens through Swift's Observation framework, so all views using
Color.appPrimary etc. automatically re-render when the theme changes — no view
identity reset needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:36:24 -06:00
Trey t
28339544e5 Update API URL to myhoneydue.com, fix missing translations, and UI polish
- Update DEV API URLs from treytartt.com to api.myhoneydue.com
- Add rounded corners to app icon in login, register, and onboarding screens
- Add 9 missing English translations in Localizable.xcstrings
- Fix property feature pills to use equal height for balanced layout
- Remove duplicate honeyDue user scheme

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:00:52 -06:00
Trey t
e9f80075c1 Rename Xcode project to honeyDue and fix all bundle IDs
- Rename iosApp.xcodeproj → honeyDue.xcodeproj
- Rename Casera schemes → HoneyDue, HoneyDueExtension, HoneyDueUITests
- Split bundle IDs per-config: Debug=com.tt.honeyDue.dev, Release=com.tt.honeyDue
- Split app groups per-config: Debug=group.com.tt.honeyDue.dev, Release=group.com.tt.honeyDue
- Fix com.t-t. typo → com.tt. in test bundle IDs
- Add APP_GROUP_IDENTIFIER build setting with variable substitution in entitlements
- Replace all hardcoded app group strings in Swift with Info.plist runtime reads
- Remove stale PRODUCT_BUNDLE_IDENTIFIER from Config.xcconfig
- Update test plan container references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 07:45:12 -06:00
Trey t
8941d4f458 Remove docs, guides, and readmes relocated to old_files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 07:09:37 -06:00
Trey t
d3b6b14e78 Fix build failures from rebrand: restore pbxproj exceptions, fix Kotlin casing, move missed source dirs
- Restore 6 missing PBXFileSystemSynchronizedBuildFileExceptionSet entries
  and exceptions arrays on 5 root groups (lost during sed rename)
- Rename extension WidgetIconView.swift to avoid stringsdata collision
  (original had different names: MyCribIconView vs CaseraIconView)
- Rename CaseraExtension.entitlements → HoneyDueExtension.entitlements
- Fix Kotlin object casing: honeyDueShareCodec → HoneyDueShareCodec,
  honeyDuePackageType → HoneyDuePackageType
- Move missed Kotlin source dirs (jsMain, webMain, androidMain/com/casera)
  to com/tt/honeyDue
- Rename remaining Casera widget files to HoneyDue
- Rename CaseraTests.swift → HoneyDueTests.swift

All 4 projects (Go API, iOS, Android, Web) now compile clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 06:58:56 -06:00
Trey t
1e2adf7660 Rebrand from Casera/MyCrib to honeyDue
Total rebrand across KMM project:
- Kotlin package: com.example.casera -> com.tt.honeyDue (dirs + declarations)
- Gradle: rootProject.name, namespace, applicationId
- Android: manifest, strings.xml (all languages), widget resources
- iOS: pbxproj bundle IDs, Info.plist, entitlements, xcconfig
- iOS directories: Casera/ -> HoneyDue/, CaseraTests/ -> HoneyDueTests/, etc.
- Swift source: all class/struct/enum renames
- Deep links: casera:// -> honeydue://, .casera -> .honeydue
- App icons replaced with honeyDue honeycomb icon
- Domains: casera.treytartt.com -> honeyDue.treytartt.com
- Bundle IDs: com.tt.casera -> com.tt.honeyDue
- Database table names preserved

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 06:33:57 -06:00
Trey t
9c574c4343 Harden iOS app with audit fixes, UI consistency, and sheet race condition fixes
Applies verified fixes from deep audit (concurrency, performance, security,
accessibility), standardizes CRUD form buttons to Add/Save pattern, removes
.drawingGroup() that broke search bar TextFields, and converts vulnerable
.sheet(isPresented:) + if-let patterns to safe presentation to prevent
blank white modals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 09:59:56 -06:00
Trey t
61ab95d108 Polish UI consistency across all CRUD forms and fix data display issues
- Rewrite ResidenceFormView to use standard Form/Section pattern matching TaskFormView
- Remove unused organic form components (OrganicFormSection, OrganicFormTextField, etc.)
- Fix DocumentFormView: NavigationView→NavigationStack, WarmGradientBackground→appBackgroundPrimary, listRowBackground→sectionBackground
- Add Required footer to residence name field and task title/property fields
- Remove redundant Required footers from pickers that always have values
- Fix grey priority dots on kanban cards by guarding PriorityBadge in DynamicTaskCard and TaskCard
- Fix empty frequency labels showing on task cards
- Fix contractor Maps URL building to filter empty strings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:00:40 -06:00
Trey t
48081c0cc8 Add regional task templates to onboarding with multiple bug fixes
- Fetch regional templates by ZIP during onboarding and display categorized
  task suggestions (iOS + KMM shared layer)
- Fix multi-expand for task categories (toggle independently, not exclusive)
- Fix ScrollViewReader auto-scroll to expanded category sections
- Fix UUID stability bug: cache task categories to prevent ID regeneration
  that caused silent task creation failures
- Fix stale data after onboarding: force refresh residences and tasks in
  RootView onComplete callback
- Fix address formatting: show just ZIP code when city/state are empty
  instead of showing ", 75028" with leading comma

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:15:47 -06:00
Trey t
98dbacdea0 Add task completion animations, subscription trials, and quiet debug console
- Completion animations: play user-selected animation on task card after completing,
  with DataManager guard to prevent race condition during animation playback.
  Works in both AllTasksView and ResidenceDetailView. Animation preference
  persisted via @AppStorage and configurable from Settings.
- Subscription: add trial fields (trialStart, trialEnd, trialActive) and
  subscriptionSource to model, cross-platform purchase guard, trial banner
  in upgrade prompt, and platform-aware subscription management in profile.
- Analytics: disable PostHog SDK debug logging and remove console print
  statements to reduce debug console noise.
- Documents: remove redundant nested do-catch blocks in ViewModel wrapper.
- Widgets: add debounced timeline reloads and thread-safe file I/O queue.
- Onboarding: fix animation leak on disappear, remove unused state vars.
- Remove unused files (ContentView, StateFlowExtensions, CustomView).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:35:08 -06:00
Trey t
c5f2bee83f Harden iOS app: fix concurrency, animations, formatters, privacy, and logging
- Eliminate NumberFormatters shared singleton data race; use local formatters
- Add reduceMotion checks to empty-state animations in 3 list views
- Wrap 68+ print() statements in #if DEBUG across push notification code
- Remove redundant .receive(on: DispatchQueue.main) in SubscriptionCache
- Remove redundant initializeLookups() call from iOSApp.init()
- Clean up StoreKitManager Task capture in listenForTransactions()
- Add memory warning observer to AuthenticatedImage cache
- Cache parseContent result in UpgradePromptView init
- Add DiskSpace and FileTimestamp API declarations to Privacy Manifest
- Add FIXME for analytics debug/production API key separation
- Use static formatter in PropertyHeaderCard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:15:42 -06:00
Trey t
bf5d60ca63 Fix iOS analytics by calling Swift AnalyticsManager instead of Kotlin no-op stub
PostHogAnalytics.shared.initialize() was calling the Kotlin actual object which
is a no-op on iOS. Replaced with AnalyticsManager.shared.configure() so the
PostHog SDK actually initializes. Also switched to anonymous-only person profiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:28:27 -06:00