Skip to content

feat(WingDex): complete iOS phases 5-8#261

Merged
jlian merged 9 commits into
mainfrom
dev
Jul 21, 2026
Merged

feat(WingDex): complete iOS phases 5-8#261
jlian merged 9 commits into
mainfrom
dev

Conversation

@jlian

@jlian jlian commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the native iOS work tracked in phases 5 through 8:

  • outing detail editing parity: location editing, taxonomy search, add/remove species, per-outing CSV export, and map links
  • species detail and WingDex parity: certainty/count metadata, notes, eBird links, and family sort
  • lifer celebrations: confetti, species-name banner, accessibility announcement, and haptics
  • system appearance audit: adaptive maps, attribution contrast, and live Light/Dark switching
  • session hardening: Better Auth 200 null, token-aware 401 invalidation, foreground validation, account-data isolation, and stale-request guards
  • native error recovery: typed errors, ContentUnavailableView, system alerts, retry-safe Add Photos, optimistic rollback, and safe quota feedback
  • retry-safe persistence: idempotent outing/photo/observation writes plus ordered web persistence
  • observability hardening: W3C tracing, timing, structured route coverage, severity fixes, and removal of credentials/user content from logs

Automated verification

  • npm run check: 40 test files, 713 tests passed
  • npx playwright test --grep-invert @live --workers=1: 46 tests passed
  • npm run build: Vite client and Cloudflare Worker compiled successfully
  • stable iOS XCTest suite passed (AuthIntegrationTests excluded from the combined run because repeated local anonymous sign-ins hit the dev limiter)
  • focused live auth/API integration cases passed separately
  • Xcode project regenerated and active iOS scheme built successfully
  • affected SwiftUI previews rendered successfully
  • git diff --check, workspace diagnostics, observability compliance tests, and static credential/content log searches are clean

The local Worker became unresponsive when Playwright used four workers. The same complete suite passed serially against a freshly restarted Worker, so the local E2E evidence above uses --workers=1.

User regression matrix

Phase 5: outing detail editing

Touched surface Status Evidence / follow-up
Open outing detail; inspect stats, species, notes, and actions ✅ Manually verified Simulator walkthrough with demo data in Light and Dark
Edit location; suggestions; save/reset ✅ Manually verified Simulator walkthrough and screenshot
Add species with taxonomy search ✅ Manually verified Search, selection, add, and resulting row exercised
Remove species with destructive confirmation ✅ Manually verified Confirmation and resulting removal exercised
Export one outing as eBird CSV ✅ Manually verified Native share sheet opened; web E2E verifies downloaded CSV
Tap outing map to open Apple Maps ⬜ Pending manual Verify external-app transition
Failed edit/add/remove/delete restores local state 🧪 Automated Rollback/error paths implemented; fault-inject offline/500 before TestFlight

Phase 6: species and WingDex parity

Touched surface Status Evidence / follow-up
Species hero, summary, attribution, external links, sightings ✅ Manually verified Light/Dark previews and live Simulator navigation
Confirmed/Possible metadata and count ✅ Manually verified Preview/model checks
Notes section ✅ Manually verified Realistic preview data
Family sort and direction 🧪 Automated Focused taxonomy XCTest coverage
Open eBird/Wikipedia in Safari ⬜ Pending manual URL generation is covered; external transition not exercised

Phase 7: celebrations and haptics

Touched surface Status Evidence / follow-up
Real eBird import with new species ✅ Manually verified Imported 91 observations / 69 new species
Three names plus +N more banner copy ✅ Manually verified Captured American Black Duck, American Crow, American Robin +66 more...
Confetti and banner auto-dismiss ✅ Manually verified Recorded video and extracted frame
No celebration for zero new species ✅ Manually verified Existing-species import correctly stayed quiet
Add Photos celebration trigger ⬜ Pending manual Exercise with a genuinely new species
Reduce Motion celebration behavior ⬜ Pending manual Enable Reduce Motion and trigger a real celebration
Success and selection haptics ⬜ Pending device Simulator cannot validate physical haptics

Phase 8: appearance, sessions, errors, observability

Touched surface Status Evidence / follow-up
Live system Light/Dark switching ✅ Manually verified Home, Outing Detail, Species Detail
Map thumbnails regenerate in Dark ✅ Manually verified Changed in place without relaunch
Sign In contrast ✅ Manually verified Paired previews plus live screen
Initial-load error with Retry ✅ Manually verified Settled native state captured
Cached refresh alert ✅ Manually verified Settled native alert captured
Add Photos quota/failure alert ✅ Manually verified Retry / Close Upload / Cancel captured
Mutation failure alert ✅ Manually verified Screenshot plus accessibility hierarchy
Passkey unavailable/failure copy ✅ Manually verified No entitlement/debug details shown
eBird import happy path and conflicts ✅ Manually verified Full native file picker/import plus E2E
Offline/timeout/401/429/500 mapping 🧪 Automated AppError XCTest and API/E2E coverage
Startup invalid session returns to Sign In once 🧪 Automated / ⬜ manual fault injection Session classification tests; authenticated Simulator fault still pending
Foreground invalidation after backgrounding 🧪 Automated / ⬜ manual fault injection Lifecycle implementation covered; authenticated fault still pending
Offline/500 foreground validation preserves session 🧪 Automated / ⬜ manual fault injection Classification covered; authenticated fault still pending
Logout then second account shows no prior data ⬜ Pending manual Store reset tested; perform two-account visual check
Profile/export/import/passkey/data-delete failures re-enable controls 🧪 Automated / ⬜ manual fault injection Safe states implemented; inject each failure before TestFlight
Structured trace/timing logs ✅ Manually verified Local Worker logs inspected
No credentials/user-authored content in logs 🧪 Automated Compliance tests, static searches, safe metadata policy; inspect deployed log tail after release

Pending manual QA checklist

Phase 5: outing detail

  • Tap an outing map and confirm Apple Maps opens at the correct coordinates.
  • Fault-inject offline/500 during outing edit, add species, remove species, and delete; confirm local state rolls back and the native error UI appears.

Phase 6: external links

  • Open an eBird species link from iOS and confirm the correct Safari page.
  • Open a Wikipedia species link from iOS and confirm the correct Safari page.

Phase 7: celebrations and haptics

  • Complete Add Photos with a genuinely new species and confirm the lifer celebration fires.
  • Enable Reduce Motion, trigger a celebration, and confirm confetti is skipped.
  • Verify success and sort-selection haptics on a physical device.

Phase 8: sessions and failure recovery

  • Launch with an authenticated but invalid/revoked session; confirm one session-expired message and cleared account data.
  • Background the authenticated app, invalidate the session, then foreground; confirm return to Sign In.
  • Background the authenticated app, fault session validation with offline/500, then foreground; confirm the cached session remains.
  • Log out, sign in as a second account, and confirm no prior-account data flashes or remains.
  • Fault profile save; confirm safe copy and controls re-enable.
  • Fault sightings/outing export; confirm safe copy and controls re-enable.
  • Fault eBird preview and confirm import; confirm safe copy, preserved preview state, and controls re-enable.
  • Fault passkey list/add/delete; confirm cancellation stays silent and failures remain recoverable.
  • Fault clear-data/account-delete; confirm no false success or local data loss.
  • Fault Add Photos metadata, identification, and save requests; confirm Retry preserves progress and Close Upload exits safely.
  • Inspect deployed structured logs and confirm trace continuity with no credentials or user-authored content.

Screenshots

Outing editing Species detail
Dark outing detail Lifer celebration
Initial load failure Cached refresh failure
Add Photos failure Mutation failure

Known local-only warnings

  • Vite reports the existing large taxonomy chunk warning.
  • Wrangler reports the existing node:async_hooks / nodejs_compat warning from Better Auth.
  • Repeated live anonymous sign-ins can hit the local limiter; this is why focused iOS live integration cases are run separately.

Copilot AI review requested due to automatic review settings July 21, 2026 05:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Delivers phases 5 through 8 of the native iOS parity plan (outing editing, species/WingDex parity, celebrations, appearance audit), alongside session hardening, retry-safe persistence, and tightened observability guarantees across web, iOS, and the Cloudflare Worker API.

Changes:

  • Hardened observability and log safety by removing response/exception text from many logs, adding W3C trace propagation, and aligning handlers with createRouteResponder.
  • Made web data mutations retry-safe and rollback-capable (photos, outings, observations), and added local-auth retry wrapper usage for selected fetches.
  • Expanded iOS parity: outing detail editing (location/species/export), new error UI patterns, lifer celebration overlay, family sort, and token-aware session invalidation.

Reviewed changes

Copilot reviewed 66 out of 74 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/lib/client-log.ts Gate debug logs in prod; safer client failure summaries
src/hooks/use-wingdex-data.ts Retry-safe optimistic writes with rollback and idempotency support
src/hooks/use-auth-gate.tsx Use local-auth retry wrapper for finalize passkey
src/ErrorFallback.tsx Structured logging for error boundary in dev
src/components/pages/SettingsPage.tsx Local-auth retry for import preview; structured failure logging
src/components/pages/OutingsPage.tsx Prevent double-add species; await mutation and surface errors
src/components/flows/OutingReview.tsx Guard confirm; stable outing IDs; switch to debug logger
src/components/flows/AddPhotosFlow.tsx Debug logger; async persistence; better error surfacing
src/App.tsx Local-auth retry for linked providers fetch
src/tests/observability-compliance.test.ts Tighten handler compliance expectations (fewer exemptions)
src/tests/client-log.test.ts Update expected level/description for safer failure logging
ios/WingDexTests/TaxonomyOrderTests.swift Unit tests for bundled taxonomic sort behavior
ios/WingDexTests/CelebrationTests.swift Unit tests for celebration banner copy
ios/WingDexTests/AuthServiceTests.swift Session validation, datastore reset, and AppError mapping tests
ios/WingDexTests/AuthIntegrationTests.swift Integration coverage for Phase 5 outing editing roundtrip
ios/WingDex/Views/WingDexView.swift Family sort, cached-refresh alert, and empty-state errors
ios/WingDex/Views/SpeciesDetailView.swift Certainty/count metadata, notes section, attribution contrast
ios/WingDex/Views/SignInView.swift One-time session-expired message consumption; safer auth errors
ios/WingDex/Views/SharedComponents.swift Sighting metadata rows; dark-mode map snapshots; preview variants
ios/WingDex/Views/SettingsView.swift Typed errors; celebration trigger after import; session-safe profile sync
ios/WingDex/Views/PasskeyManagementView.swift Typed error mapping for passkey management
ios/WingDex/Views/OutingsView.swift Cached-refresh alert + empty-state errors
ios/WingDex/Views/OutingDetailView.swift Location edit, add/remove species, export CSV, typed alerts
ios/WingDex/Views/NativeErrorPreviews.swift Previews for key native error UI states
ios/WingDex/Views/HomeView.swift Cached-refresh alert + empty-state errors
ios/WingDex/Views/EBirdImportView.swift Typed errors; callback with new-species names after import
ios/WingDex/Views/DataManagementView.swift Typed error mapping for data deletion flows
ios/WingDex/Views/CelebrationOverlay.swift Confetti + banner + accessibility announcement modifier
ios/WingDex/Views/AddPhotosFlow/PerPhotoConfirmView.swift Avoid logging localized error details
ios/WingDex/Views/AddPhotosFlow/OutingReviewView.swift Idempotent outing creation; typed error mapping; retry safety
ios/WingDex/Views/AddPhotosFlow/AddPhotosFlow.swift Add Photos alert recovery + celebration trigger
ios/WingDex/ViewModels/AddPhotosViewModel.swift Typed errors, retry-safe recovery state, new-species name tracking
ios/WingDex/Services/PasskeyService.swift Centralized request instrumentation and timing logs
ios/WingDex/Services/DataStore.swift Generation guards, typed errors, idempotent mutations with rollback
ios/WingDex/Services/DataService.swift Safe HTTP errors, token-aware 401 invalidation, taxonomy search/export
ios/WingDex/Services/AuthService.swift Session validation hardening; token-aware invalidation; one-time sign-in message
ios/WingDex/Services/AuthenticatedRequest.swift Trace instrumentation + timed request wrapper; no response body logging
ios/WingDex/Preview Content/PreviewData.swift Preview data enriched for counts/possible/notes
ios/WingDex/Models/AppError.swift Central typed error mapping for UX-safe copy
ios/WingDex/Extensions/DateFormatting.swift Taxonomic order lookup + comparator helpers
ios/WingDex/App/WingDexApp.swift Foreground session validation; datastore reset on sign-out
ios/WingDex.xcodeproj/project.pbxproj Add new Swift sources/tests; bump marketing version
functions/lib/auth.ts Remove dev-only origin debug log block
functions/api/species/wiki-title.ts Begin migration to shared route responder
functions/api/species/search.ts Use route responder; improved 401 handling
functions/api/species/ebird-code.ts Use route responder; improved 401 handling
functions/api/import/ebird-csv/confirm.ts Safer 5xx logging detail (no exception text)
functions/api/import/ebird-csv.ts Safer 5xx logging detail (no exception text)
functions/api/identify-bird.ts Safer error reporting; clearer 4xx/5xx detail
functions/api/health.ts Safer error reporting (no exception text)
functions/api/export/sightings.ts Safer 5xx logging detail (no exception text)
functions/api/export/outing/[id].ts Safer 5xx logging detail (no exception text)
functions/api/export/dex.ts Safer 5xx logging detail (no exception text)
functions/api/data/photos.ts Idempotent photo writes; conflict validation; safer 5xx logs
functions/api/data/outings/[id].ts Safer 5xx logging detail (no exception text)
functions/api/data/outings.ts Idempotent outing upsert; ID conflict validation; safer logs
functions/api/data/observations.ts Idempotent observation writes; conflict validation; safer logs
functions/api/data/dex.ts Safer 5xx logging detail; reduce sensitive properties
functions/api/data/clear.ts Safer 5xx logging detail (no exception text)
functions/api/data/all.ts Safer 5xx logging detail (no exception text)
functions/api/auth/linked-providers.ts Safer 5xx logging detail (no exception text)
functions/api/auth/finalize-passkey.ts Safer 403/5xx details; avoid leaking IDs in messages
functions/_middleware.ts Safer completion/error logs; include duration on early rejects
docs/OBSERVABILITY.md Expand safe-metadata policy and client-safety guidance
docs/IOS_APP_PLAN.md Mark phases 5-8 as completed; document implemented behaviors
.github/AGENTS.md Add iOS UI verification guidance and parity expectations

Comment thread ios/WingDex/Services/DataService.swift
Comment thread functions/api/species/wiki-title.ts
Comment thread src/components/flows/OutingReview.tsx Outdated
Comment thread src/components/flows/AddPhotosFlow.tsx Outdated
Comment thread src/lib/client-log.ts Outdated
Comment thread src/hooks/use-wingdex-data.ts
Comment thread src/ErrorFallback.tsx Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 05:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 68 out of 76 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

functions/api/species/wiki-title.ts:8

  • route is created but never used, which will typically fail noUnusedLocals / lint and also means no route-scoped log entry is emitted. Either remove it or use it for a safe debug/info log (without including the raw species name).

Copilot AI review requested due to automatic review settings July 21, 2026 05:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 68 out of 76 changed files in this pull request and generated 5 comments.

Comment thread ios/WingDex/Models/AppError.swift
Comment thread src/App.tsx
Comment thread src/hooks/use-wingdex-data.ts
Comment thread src/hooks/use-wingdex-data.ts
Comment thread src/hooks/use-wingdex-data.ts
Copilot AI review requested due to automatic review settings July 21, 2026 05:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 68 out of 76 changed files in this pull request and generated 6 comments.

Comment thread functions/api/data/outings.ts Outdated
Comment thread functions/api/data/outings.ts Outdated
Comment thread functions/api/data/outings.ts Outdated
Comment thread functions/api/data/photos.ts Outdated
Comment thread functions/api/data/observations.ts Outdated
Comment thread src/components/pages/SettingsPage.tsx
Copilot AI review requested due to automatic review settings July 21, 2026 05:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 77 changed files in this pull request and generated 2 comments.

Comment thread ios/WingDex/Views/CelebrationOverlay.swift
Comment thread src/components/flows/OutingReview.tsx
Copilot AI review requested due to automatic review settings July 21, 2026 06:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 77 changed files in this pull request and generated 1 comment.

Comment thread functions/api/data/outings.ts Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 06:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 77 changed files in this pull request and generated 1 comment.

Comment thread ios/WingDex/Views/OutingDetailView.swift
Copilot AI review requested due to automatic review settings July 21, 2026 07:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 73 out of 81 changed files in this pull request and generated 2 comments.

Comment thread functions/api/data/photos.ts
Comment thread functions/api/data/observations.ts
Copilot AI review requested due to automatic review settings July 21, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 73 out of 81 changed files in this pull request and generated 1 comment.

Comment thread ios/WingDex/Views/CelebrationOverlay.swift
Copilot AI review requested due to automatic review settings July 21, 2026 19:37
jlian added 6 commits July 21, 2026 12:42
Add a reusable celebration overlay that plays a confetti burst and a
lifer banner with a success haptic when new species are added, wired
into the AddPhotos done screen and the eBird import flow. Confetti and
the banner slide are skipped under Reduce Motion, and the banner is
announced to VoiceOver. Add a selection haptic on WingDex sort changes.
Cover the banner message builder with unit tests.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 73 out of 81 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 21, 2026 19:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 73 out of 81 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

functions/api/data/photos.ts:104

  • The hasOwnedOutings call arguments are not indented consistently, which reduces readability in this already complex validation/persistence flow.
    const allOwned = await hasOwnedOutings(
    context.env.DB,
    userId,
    body.map(photo => photo.outingId)
    )

Comment on lines 106 to 108
const failOutingIds = [...new Set(body.map(p => p.outingId))]
return route.fail(400, 'Invalid outing reference', `One or more outing IDs are not owned by user or do not exist`, { outingIds: failOutingIds })
}
Comment on lines 148 to +152
return Response.json(
body.map(photo => ({
...photo,
dataUrl: '',
thumbnail: '',
@jlian
jlian merged commit 38bd021 into main Jul 21, 2026
6 checks passed
@jlian
jlian deleted the dev branch July 21, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants