Skip to content

Commit faeaf76

Browse files
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

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/cache-dependencies/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ runs:
88
id: dependencies_cache
99
with:
1010
path: |
11-
vendor
12-
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
11+
iOS/vendor
12+
key: ${{ runner.os }}-gems-${{ hashFiles('iOS/Gemfile.lock') }}
1313
restore-keys: |
1414
${{ runner.os }}-gems-

.github/config/.swiftlint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
child_config: ../../.swiftlint.yml
1+
child_config: ../../iOS/.swiftlint.yml
22

33
disabled_rules:
44
# E.g:
55
# - todo
66

77
excluded:
8-
# In case you want to exclude folders for the swiftlint running in the CI
8+
# In case you want to exclude folders for the swiftlint running in the CI

.github/sample-workflows/enterprise-deployment.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ jobs:
4545
- name: Install Dependencies
4646
run: |
4747
./setup.swift install
48+
working-directory: iOS
4849

4950
# uncomment Run tests step to test before deployment
5051
# - name: Run tests
@@ -57,6 +58,7 @@ jobs:
5758
# run enterprise_deployment lane, use branch name to select env file
5859
- name: Enterprise deployment
5960
run: bundle exec fastlane enterprise_deployment
61+
working-directory: iOS
6062
env:
6163
WORKSPACE: ChemexTimer.xcworkspace
6264
SCHEME: ChemexTimer

.github/sample-workflows/testflight-deployment.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
- name: Install Dependencies
5151
run: |
5252
./setup.swift install
53+
working-directory: iOS
5354

5455
# uncomment Dependencies cache step when running on macos-latest
5556
# - name: Dependencies cache
@@ -73,6 +74,7 @@ jobs:
7374
# run testflight_deployment lane
7475
- name: Testflight deployment
7576
run: bundle exec fastlane testflight_deployment
77+
working-directory: iOS
7678
env:
7779
WORKSPACE: ChemexTimer.xcworkspace
7880
TARGET: ChemexTimer

.github/workflows/post-merge-integrations.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ jobs:
5151
- name: Install Dependencies
5252
run: |
5353
./setup.swift install
54+
working-directory: iOS
5455

5556
# uncomment if you are using SwiftLint via SPM plugin
5657
# Set SwiftLint version for Danger
@@ -61,12 +62,14 @@ jobs:
6162
- name: Run Danger
6263
run: |
6364
bundle exec danger --fail-on-errors=true
65+
working-directory: iOS
6466
env:
6567
GITHUB_TOKEN: ${{ github.token }}
6668

6769
# run tests (SnapshotTestPlan + UITestPlan after merge)
6870
- name: Run tests
6971
run: bundle exec fastlane tests without_dependencies:true
72+
working-directory: iOS
7073
env:
7174
WORKSPACE: ChemexTimer.xcworkspace
7275
TEST_PLAN: UITestPlan

.github/workflows/pr-integrations.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ jobs:
6161
# Install dependencies (run install script)
6262
- name: Install Dependencies
6363
run: ./setup.swift install
64+
working-directory: iOS
6465

6566
# uncomment if you are using SwiftLint via SPM plugin
6667
# Set SwiftLint version for Danger
@@ -70,6 +71,7 @@ jobs:
7071
# Run Danger
7172
- name: Run Danger
7273
run: bundle exec danger --fail-on-errors=true
74+
working-directory: iOS
7375
env:
7476
GITHUB_TOKEN: ${{ github.token }}
7577

@@ -99,10 +101,12 @@ jobs:
99101
# Install dependencies (run install script)
100102
- name: Install Dependencies
101103
run: ./setup.swift install
104+
working-directory: iOS
102105

103106
# Run Unit Tests
104107
- name: Run Unit Tests
105108
run: bundle exec fastlane tests without_dependencies:true
109+
working-directory: iOS
106110
env:
107111
TEST_PLAN: UnitTestPlan
108112

@@ -133,9 +137,11 @@ jobs:
133137
# Install dependencies (run install script)
134138
- name: Install Dependencies
135139
run: ./setup.swift install
140+
working-directory: iOS
136141

137142
# Run Snapshots Tests
138143
- name: Run Snapshot tests
139144
run: bundle exec fastlane tests without_dependencies:true
145+
working-directory: iOS
140146
env:
141147
TEST_PLAN: SnapshotTestPlan

.github/workflows/testflight-deployment.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
- name: Install Dependencies
5151
run: |
5252
./setup.swift install
53+
working-directory: iOS
5354

5455
# uncomment Dependencies cache step when running on macos-latest
5556
# - name: Dependencies cache
@@ -73,6 +74,7 @@ jobs:
7374
# run testflight_deployment lane
7475
- name: Testflight deployment
7576
run: bundle exec fastlane testflight_deployment
77+
working-directory: iOS
7678
env:
7779
WORKSPACE: ChemexTimer.xcworkspace
7880
TARGET: ChemexTimer

.gitignore

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,16 @@ fastlane/Preview.html
6767
fastlane/screenshots/**/*.png
6868
fastlane/test_output
6969
fastlane/.env*
70+
iOS/fastlane/.env*
7071

7172
# Ruby gems + tooling Binaries
7273
vendor/
74+
iOS/vendor/
7375

7476
# Because our self-hosted runner is an Apple Silicon machine some Ruby dependencies need binaries for the ARM architecture
7577
# but the .lock file captures the x64 versions. So we rather have specific versions in Gemfile and do not commit the .lock file
7678
Gemfile.lock
79+
iOS/Gemfile.lock
7780

7881
.DS_Store
7982

@@ -82,9 +85,18 @@ Gemfile.lock
8285
# Tuist generates the .xcodeproj and .xcworkspace files from definition files so there is no need to store them in the git repo.
8386
**/*.xcodeproj
8487
**/*.xcworkspace
88+
iOS/**/*.xcodeproj
89+
iOS/**/*.xcworkspace
8590

8691
# Tuist managed dependencies
8792
Tuist/Dependencies/*
93+
iOS/Tuist/Dependencies/*
8894

8995
# Tuist derived files
90-
Derived/
96+
Derived/
97+
iOS/Derived/
98+
99+
# Android
100+
android/.gradle/
101+
android/**/build/
102+
android/local.properties

0 commit comments

Comments
 (0)