Commit faeaf76
committed
Prompt 1:
You are Codex (or a coding agent) working in a repository that currently contains ONLY an iOS app. Your job is
to (1) reorganize the repo into a clean monorepo structure, then (2) add Android (1:1 port) and (3) add a
presentation-only web site built with ONLY vanilla HTML/CSS/JS that uses REAL screenshots from the apps.
TARGET REPO STRUCTURE (MUST CREATE)
Create this structure at repo root:
root/
iOS/
android/
web/
docs/
The repository currently has only the iOS app at the root (or in its current location). You must move it into
root/iOS while keeping it buildable and keeping Git history as intact as possible (move/rename, do not copy).
NON-NEGOTIABLE REQUIREMENTS
- iOS is the canonical source of truth. Android must be 1:1 feature parity with the CURRENT iOS state after the
move.
- Android must follow platform standards/best practices (Kotlin + Jetpack Compose, lifecycle-safe,
accessibility, polished micro-interactions) and match iOS quality.
- Web is presentation-only and MUST use REAL screenshots captured from the iOS and Android apps (not mockups,
not placeholders).
- Web MUST be implemented using ONLY: HTML + CSS + JavaScript (no React/Next/Vite, no build tooling required).
- Do NOT redesign or add/remove features. Do NOT introduce cross-platform frameworks (no Flutter/KMM/React
Native). This is a native 1:1 port.
- Whenever the specification or architecture is changed, the corresponding .md documentation files MUST be
updated in the SAME PR/change set so docs remain consistent with code and spec.
PHASE 1 — CREATE MONOREPO STRUCTURE + MOVE iOS
1) Create folders: root/iOS, root/android, root/web, root/docs.
2) Move the existing iOS project into root/iOS:
- Preserve build settings and paths.
- Update any relative references (assets, scripts, CI configs) so iOS still builds.
- If there are CI files at root, adjust them to point to root/iOS.
3) Add a minimal root-level README.md describing the monorepo layout and how to build each platform.
PHASE 2 — DOCUMENT THE CURRENT iOS APP (SOURCE OF TRUTH)
Before implementing Android/Web:
1) Audit root/iOS and write docs/feature-parity-checklist.md containing:
- Screen-by-screen behavior (Setup, Timer, Summary, History, Settings)
- Navigation behavior (tabs, stacks, sheets/modals)
- Data models and persistence behavior
- Timer correctness rules + step schedule
- Micro-interactions and animations (what matters)
- Accessibility behaviors and settings behavior
- Edge cases (stop confirmation, discard confirmation, save confirmation, background/foreground behavior)
This checklist is the acceptance criteria for Android parity.
PHASE 3 — ANDROID (root/android) 1:1 PORT, PRODUCTION-READY
Create a new native Android app in root/android.
If there is no existing Android architecture to follow (likely), implement a clean, minimal, production-ready
structure:
- Kotlin, Jetpack Compose
- Navigation Compose with bottom bar tabs: Brew / History / Settings
- ViewModel for screen state (AndroidX lifecycle)
- Domain: BrewEngine (timer + state machine) mirroring iOS behavior exactly
- Persistence:
- Choose ONE consistent approach and document it:
- Option A (recommended): Room for BrewSession + DataStore for BrewSettings
- Option B: Room for both
- Haptics/sound equivalents respecting settings
- Keep screen awake while brewing if enabled, revert reliably
- Lifecycle correctness: timer remains accurate across background/foreground using elapsed-time model (not tick
count)
Android must match iOS flows and copy:
- Brew tab: Setup -> Timer -> Summary (Summary as modal/bottom sheet/dialog; match behavior)
- Same confirmations and edge cases per checklist
- No extra tabs, no extra features
Add docs:
- docs/android-architecture.md describing chosen structure and key decisions.
PHASE 4 — SCREENSHOTS (REAL) + WEB PRESENTATION SITE (root/web) (VANILLA ONLY)
Web is presentation-only.
1) Create a screenshot standard:
- Store screenshots at: web/assets/screenshots/ios/ and web/assets/screenshots/android/
- Naming per screen/state:
- brew-setup.png
- brew-timer-running.png
- brew-timer-paused.png
- brew-summary.png
- history.png
- settings.png
2) Capture REAL screenshots from both apps after Android parity is reached.
- Automation is optional; ONLY add it if it’s lightweight and does not add build tooling for web.
- Provide a clear manual screenshot checklist in docs/screenshots.md.
3) Build the web site in root/web using ONLY:
- index.html
- styles.css
- main.js (optional)
No frameworks, no bundlers.
Site requirements:
- Landing hero section: app name + one-sentence value prop
- “Screens” section showing iOS + Android screenshots side-by-side per screen
- “Feature parity” section linking/referencing docs/feature-parity-checklist.md (include a short summary on the
page)
- Responsive layout:
- Mobile: stacked screenshots
- Desktop: two-column comparison
- Performance:
- Use <img loading="lazy">, width/height attributes, and responsive CSS
- Use semantic HTML and accessible alt text
- Provide a simple way to open locally (double-click index.html) and optionally a tiny docs note for running a
local static server (python -m http.server), but do not require it.
Add docs:
- docs/web.md describing web structure and how to update
- docs/screenshots.md describing how to capture and update screenshots
PHASE 5 — DOC CONSISTENCY RULE
Whenever you change any spec or architecture while doing this work, update the relevant .md files in the SAME
PR/change set so docs remain consistent.
BUILD/RUN INSTRUCTIONS
Provide working instructions in README.md for:
- iOS (from root/iOS)
- Android (from root/android)
- Web (open web/index.html; optional local server command)
OUTPUT FORMAT
Return:
- A file-by-file summary of moves/renames and new files
- Updated/created documentation (.md)
- Build/run instructions
- Explicit statement that Android parity was validated against docs/feature-parity-checklist.md (do not claim
parity without checking each item)
STOP CONDITION
If you cannot build the iOS app after moving it into root/iOS, stop and fix that first before proceeding to
Android/Web.
Prompt 2:
You are Codex working in the Android app (root/android). The app crashes when the user changes the ratio slider
and/or taps the dose “+ / –” buttons. Your job is to diagnose the root cause(s) and fix it in a production-ready
way, while preserving 1:1 parity with iOS behavior and following Android standards.
NON-NEGOTIABLE
- Follow the existing Android module architecture, patterns, and guidelines in this repo. Do NOT introduce a new
architecture style or new heavy frameworks unless already used.
- Do NOT change product scope or UI flow. Fix the crash and improve robustness only.
- Keep behavior 1:1 with iOS: same allowed ranges, same defaults, same computed outputs, same navigation.
- If you change spec/architecture, update the corresponding .md docs in the SAME PR/change set.
REPRO + ROOT CAUSE (DO FIRST)
1) Reproduce the crash reliably:
- tap “+” and “–” rapidly
- drag the ratio slider quickly
- drag slider then tap +/- repeatedly
- rotate device (if supported)
- background/foreground while interacting
2) Capture evidence:
- logcat stack trace
- identify the exact line(s) and state leading to crash
- note device/OS and build type
3) Classify likely causes (investigate all relevant):
- invalid numeric values (dose <= 0, ratio out of bounds, NaN/Infinity)
- formatting crash (NumberFormat, locale decimal issues)
- Compose state bug (mutating state during composition, snapshot issues)
- recomposition leading to illegal state (e.g., steps list empty but indexed)
- concurrency/coroutines (updating Room/DataStore from main thread or racing writes)
- persistence on every slider tick (Room/DataStore backpressure, crash due to threading)
- slider step rounding producing out-of-range value (e.g., 14.999 -> 14.9)
- derived computations using Int overflow or division by zero
- using remember incorrectly (state resets, nulls, NPE)
FIX REQUIREMENTS (ROBUST INPUT HANDLING)
Implement a “single source of truth” for Setup inputs and enforce invariants:
- doseGrams must always be clamped to a safe range (e.g., 5.0..120.0). Never allow <= 0.
- ratio must always be clamped to 15.0..17.0 with step 0.1.
- Derived values (totalWater, bloomWater, targetTime) must never become invalid:
- totalWater = dose * ratio
- bloomWater = dose * 2
- targetTimeSeconds fixed
- If a steps list is derived from inputs, it must never be indexed unless non-empty and index is valid.
STATE MANAGEMENT & PERSISTENCE (PRODUCTION READY)
- Use the project’s established pattern (ViewModel + state flow, etc.).
- Do NOT write to persistence on every slider tick if that is contributing to crash:
- Use one of these approaches (pick the repo-standard one):
A) Keep “draft” UI state in memory and persist only on Start Brew
B) Debounce persistence updates (e.g., 250–400ms) for slider, immediate for +/- taps
- Ensure persistence operations are on proper dispatchers:
- Room writes on Dispatchers.IO
- DataStore edits in a safe coroutine context
- Avoid collecting flows in a way that causes rapid feedback loops (UI -> persist -> flow emit -> UI updates ->
crash).
COMPOSE-SPECIFIC SAFETY
- Ensure slider uses stable state and rounding:
- When user drags, map raw float to stepped double: roundToNearest(0.1) and clamp to [15.0, 17.0]
- Avoid updating multiple state holders in one frame if it causes snapshot conflicts.
- Ensure UI never reads null state (no !! on potentially absent values).
- If using derivedStateOf, ensure dependencies are correct and computations are pure.
REGRESSION CHECKS (WHOLE APP)
After fixing Setup crashes, verify:
- Starting brew uses current computed values correctly
- Timer doesn’t crash after repeated start/stop or after changing settings
- Summary save works; History list updates correctly
- Settings defaults don’t corrupt setup inputs
- App lifecycle doesn’t break state (background/foreground, configuration change)
TESTS (ONLY IF THE REPO ALREADY USES THEM)
- If tests exist, add minimal unit tests for:
- clamping dose/ratio
- rounding to step 0.1
- brew math and step schedule generation
- Otherwise do not add new infra; add a small debug-only “stress inputs” developer action if consistent with the
repo.
DELIVERABLES
- Root cause explanation referencing the logcat stack trace and the precise bug.
- Code changes implementing the fix, following repo conventions.
- Any relevant .md doc updates (same PR) if you changed assumptions/spec/architecture.
OUTPUT
Return a file-by-file change summary and the actual code modifications needed to fix the crash and prevent
regressions.1 parent 898eb00 commit faeaf76
560 files changed
Lines changed: 7480 additions & 494 deletions
File tree
- .github
- actions/cache-dependencies
- config
- sample-workflows
- workflows
- android
- .idea
- caches
- app
- src
- main
- java/com/strv/chemexcoach
- data
- local
- domain
- model
- ui
- brew
- setup
- timer
- common
- history
- settings
- theme
- res
- drawable
- mipmap-hdpi
- mipmap-mdpi
- mipmap-xhdpi
- mipmap-xxhdpi
- mipmap-xxxhdpi
- values
- test/java/com/strv/chemexcoach
- gradle/wrapper
- docs
- iOS
- .bundle
- .githooks
- App
- ChemexTimerTests
- ApplicationTests
- DeallocTests
- SnapshotTests/Example
- __Snapshots__/ExampleSnapshotTests
- ChemexTimer
- Application
- Resources
- Assets.xcassets
- AppIcon.appiconset
- AppIconOriginal.appiconset
- ChemexLogo.imageset
- ChemexSetupHero.imageset
- strvLogo.imageset
- en.lproj
- Common
- Configuration
- Coordinators
- App
- Scene
- InitialScene
- DependencyInjection
- Types
- Utilities
- Scenes
- ChemexCoach
- Brew
- Coordinator
- Setup
- Store
- Summary
- Store
- Timer
- Store
- Common
- Engine
- Formatting
- Models
- Persistence
- UI
- Utilities
- History
- Coordinator
- Store
- View
- Settings
- Store
- View
- LaunchScreen/Base.lproj
- MainTabBar/Coordinator
- Configurations
- Design
- active_brew_timer
- brew_setup
- brew_summary
- history
- settings
- Documentation
- Resources
- authentication
- Modules
- Feature
- AuthenticationFeature
- Example
- Resources
- TestData.xcassets
- 2024-12-02T11:57:56Z
- 2024-12-02T11:57:56Z_go-template-rest-agendrmhnq-uc.a.run.app_api_v1_sign-in_post_0.dataset
- 2024-12-02T11:57:56Z_go-template-rest-agendrmhnq-uc.a.run.app_api_v1_sign-in_post_1.dataset
- 2024-12-02T11:57:56Z_identitytoolkit.googleapis.com_v1_accounts:signinwithidp_key_aizasydg_ra20qgbvuk6oc5pzco_rgjcuhbxgv8_post_0.dataset
- 2024-12-02T11:57:56Z_identitytoolkit.googleapis.com_v1_accounts:signinwithpassword_key_aizasydg_ra20qgbvuk6oc5pzco_rgjcuhbxgv8_post_0.dataset
- 2024-12-02T11:57:56Z_identitytoolkit.googleapis.com_v1_token_key_aizasydg_ra20qgbvuk6oc5pzco_rgjcuhbxgv8_post_0.dataset
- 2024-12-02T11:57:56Z_identitytoolkit.googleapis.com_v1_token_key_aizasydg_ra20qgbvuk6oc5pzco_rgjcuhbxgv8_post_1.dataset
- AppIcon.appiconset
- AppIconOriginal.appiconset
- Sources
- DependencyInjection
- View
- Store
- Interface
- Sources
- AuthenticationView
- Store
- DependencyInjection
- TermsAndConditionsView
- Store
- TestResources
- Tests
- UITests
- DebugSettingsFeature
- Example
- Resources/TestData.xcassets
- AppIcon.appiconset
- AppIconOriginal.appiconset
- Sources
- Interface
- Sources
- Common
- DependencyInjection
- Scenes
- DebugSettingsView
- KeychainView
- UserDefaultsDetailView
- UserDefaultsView
- UITests
- Library
- CoreLibrary
- Sources
- Common
- Coordination
- Logging
- Stores
- TestResources/Mocks
- Tests
- PulseDependencyWrapper
- Sources
- StaticDependencyWrapper
- Sources
- UILibrary
- Resources
- Colors.xcassets
- background.colorset
- text.colorset
- tint.colorset
- Fonts
- Images.xcassets
- icons
- iconSwift.imageset
- en.lproj
- Sources
- Assets
- Colors
- Fonts
- Images
- Constants
- SwiftUI
- Components
- Extensions
- Styles
- UIKit
- Components
- Extensions
- Styles
- Tests
- __Snapshots__/SampleSnapshotTests
- Utilities
- Sources
- Common
- Configurations/SceneConfiguration
- PropertyListLoadable
- Extensions
- Combine
- Foundation
- TestResources/SnapshotTesting
- Cells
- Snapshotting
- Service
- AuthenticationService
- Interface
- Resources/en.lproj
- Sources
- DependencyInjection
- Models
- TestResources
- Extensions
- Protocols
- Tests
- MonitoringService
- Sources
- PersistenceService
- Interface
- Keychain
- SwiftData
- Resources/en.lproj
- Sources
- Keychain
- SwiftData
- TestResources
- Keychain
- SwiftData
- Tests
- Keychain
- SwiftData
- Tuist
- ProjectDescriptionHelpers
- Dependencies
- Extensions
- Module
- TargetDependency
- Schemes
- Targets
- Templates
- Assets
- Assets.xcassets
- color.colorset
- Example
- Interface
- Localizable
- Module
- Sources
- TestResources
- Tests
- UITests
- fastlane
- scripts
- web
- assets
- media
- screenshots
- android
- ios
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
| 11 | + | |
| 12 | + | |
13 | 13 | | |
14 | 14 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| |||
57 | 58 | | |
58 | 59 | | |
59 | 60 | | |
| 61 | + | |
60 | 62 | | |
61 | 63 | | |
62 | 64 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| |||
73 | 74 | | |
74 | 75 | | |
75 | 76 | | |
| 77 | + | |
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
| |||
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| 65 | + | |
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
68 | 70 | | |
69 | 71 | | |
| 72 | + | |
70 | 73 | | |
71 | 74 | | |
72 | 75 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
70 | 71 | | |
71 | 72 | | |
72 | 73 | | |
| 74 | + | |
73 | 75 | | |
74 | 76 | | |
75 | 77 | | |
| |||
99 | 101 | | |
100 | 102 | | |
101 | 103 | | |
| 104 | + | |
102 | 105 | | |
103 | 106 | | |
104 | 107 | | |
105 | 108 | | |
| 109 | + | |
106 | 110 | | |
107 | 111 | | |
108 | 112 | | |
| |||
133 | 137 | | |
134 | 138 | | |
135 | 139 | | |
| 140 | + | |
136 | 141 | | |
137 | 142 | | |
138 | 143 | | |
139 | 144 | | |
| 145 | + | |
140 | 146 | | |
141 | 147 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| |||
73 | 74 | | |
74 | 75 | | |
75 | 76 | | |
| 77 | + | |
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
70 | 71 | | |
71 | 72 | | |
72 | 73 | | |
| 74 | + | |
73 | 75 | | |
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
| 79 | + | |
77 | 80 | | |
78 | 81 | | |
79 | 82 | | |
| |||
82 | 85 | | |
83 | 86 | | |
84 | 87 | | |
| 88 | + | |
| 89 | + | |
85 | 90 | | |
86 | 91 | | |
87 | 92 | | |
| 93 | + | |
88 | 94 | | |
89 | 95 | | |
90 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
0 commit comments