Mobile app for Android - #20
Open
wdembinski wants to merge 14 commits into
Open
wdembinski wants to merge 14 commits into
wdembinski wants to merge 14 commits into
Conversation
… 27) Step 1 of 12. The interactive prompt for these went unanswered in a headless session, so they are recorded here instead of guessed: a new apps/mobile (not a responsive apps/web), an installable PWA (not Capacitor/TWA, since there is no Android SDK/JDK/keystore on this machine), its own SWA on its own subdomain, and a one-time human infra setup that blocks no coding step.
…ep 2) Step 2 of 12. Applies the rule already used at the desktop/apps/web line in Phase 26 one layer down: share when a file has no host in it, fork when sharing means threading optional props through. A new packages/cloud absorbs apps/web's sync layer (auth, presence, the board's cloud plumbing) since two browser clients cannot each own a copy; @tm/ui's card/detail/chat/dialog components are already host-agnostic and stay put; the shell, board navigation, move interaction and detail route fork because a phone has no rail, no grid, and no drag; the chain overlay and drag handle drop, the latter for free since TaskCard.tsx already gates it on onLinkStart.
Step 3 of 12. Moves everything step 2 marked shared — auth/, presence.ts, and out of board/ the poll/SSE loop, HTTP transport, boardSelectors, useBoardExtras and the three connection-state banners, plus settings/SettingsScreen.tsx — out of apps/web/src into a new packages/cloud (@tm/cloud), copying @tm/ui's tsup/exports/peer-deps conventions exactly. apps/web imports everything back through @tm/cloud/* and is down to the six files that stay host-bound: App.tsx, main.tsx, env.ts, vite-env.d.ts, BoardScreen.tsx and BoardToolbar.tsx. env.ts and vite-env.d.ts stay in apps/web on purpose — import.meta.env is a Vite build-time replacement esbuild cannot emit in CJS. @tm/cloud exports the WebConfig interface (packages/cloud/src/config.ts) and takes the config as a parameter instead, which is already how useCloudBoard and CloudAuth are called. @tm/ui is externalized in @tm/cloud's tsup build (alongside its subpaths) so useBoardExtras's runtime useTransport() reads the host's own TransportContext rather than a second bundled copy — @tm/ui must never import @tm/cloud in return, or the two externals cycle. test/shell-parity.test.ts's WEB_TREE became WEB_TREES (apps/web/src and packages/cloud/src both), since apps/web/src alone dropped from 27 to 6 non-test sources and the ">10" breach guard would otherwise pass while scanning a tree too small to ever fail. The SettingsScreen path it reads moved with the file. .github/workflows/deploy.yml's web path filter gained packages/cloud/** — without it, a change here would stop deploying web with nothing red in CI. pnpm-lock.yaml regenerated for the new workspace package.
Step 4 of 12. A new @tm/mobile — package.json, tsconfig, vite/vitest config and index.html (viewport-fit=cover), modelled on apps/web's own. Its shell is a compact top bar (title, ClientPicker, sync dot, sign out) and a bottom tab bar with the same five destinations in the same order as web/desktop, Scratch run dimmed "desktop only" — MobileShell is deliberately not AppShell/NavRail, a phone has no rail and no mouse to hover it. main.tsx mounts the shared theme (scaleTheme(appDarkTheme, BASE_FONT_PX), useGlobalStyles, Toaster) the same way both other hosts do, at 100dvh; TransportProvider wraps the tree in @tm/cloud's HttpTransport, and sign-in reuses SignInScreen/useCloudAuth unchanged. Performance, Attention and Settings route to their shared components as-is; My Tasks is a placeholder until step 6 builds the tap-to-move board. Extends test/shell-parity.test.ts's HOST_TREES/HOST_DOCUMENTS to cover mobile from this commit, and adds a nav-parity assertion — mobile and web must expose the same five destination ids in the same order — confirmed red against a reordered NAV before landing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
html/body/#root at 100% resolves against the large viewport in a phone browser tab, leaving MobileShell's tab bar under the address bar and unreachable — switch to 100dvh, a no-op on desktop and web. Stack Performance's rail and SettingsScreen's nav below a 599px breakpoint, and cap AddTaskDialog/ArchivedCardsDialog to the viewport width, so none of the three overflow a 360px phone. Asserted as source text in test/shell-parity.test.ts, the same way the file already asserts scaleTheme(appDarkTheme, — there is no DOM harness in this repo, and a CSS rule nobody asserts is a rule that silently reverts.
A chip row (ColumnChips) picks one column at a time; TaskCard renders each card unchanged, with a Move-to... menu (BoardCardRow) wired to useCloudBoard's setStatus in place of drag-and-drop. TaskCard's draggable/dragging/onDragStart/onDragEnd become optional so a phone never has to pass no-ops for them. Also wires the toolbar's phone form: a FAB opening the shared AddTaskDialog, the Show-Done switch, archived cards, JIRA sync, and the commit graph as a full-screen sheet (GitGraphSheet) rather than the desktop's 340px pane.
Step 7 of 12. A tap on a card now pushes TaskScreen — @tm/ui's TaskDetail, the same component the desktop draws in its 40% pane, wrapped for a phone in a full-screen fixed surface with a back chevron instead of a side-by-side layout. TaskDetail itself needed no forking: its root is already flex: 1; minWidth: 0 with no fixed width, and 24 of its ~25 props are optional. BoardScreen wires selectedTaskId through to it exactly as apps/web's own BoardScreen does: the pending-overlaid selected task, its chain (subtasks or step siblings), its parent for the breadcrumb, its merge requests and attachments (byTask over useBoardExtras, which already carries attachFiles through @tm/cloud's HttpTransport — no host-only attachment:pick path for a phone to reach), and chainLinks/chainTasksById/onUnlinkChain so TaskDetail's own TaskChain section stands in for the chain overlay step 2 dropped. Passes the same RELAY_NOTICE apps/web's own BoardScreen does, since mobile edits travel the identical relay. onStatusChanged only records the optimistic overlay (onStatusNoted, threaded from App.tsx's board.noteStatus) rather than resending a command the pane's own State dropdown already sent. index.html's viewport meta gains interactive-widget=resizes-content (Chrome 108+, which is what an installed WebAPK runs on) so 100dvh — already relied on for MobileShell's tab bar — also shrinks for the on-screen keyboard, keeping TaskDetail's fixed composer band above it rather than under it.
…step 8) Push a browser history entry for every navigation Back should undo — tab switch, task opened, sheet/dialog opened — and unwind it on popstate, so an installed PWA's hardware Back no longer exits the app from an open task or settings pane. What Back means given a stack lives in a pure navStackReducer with its own test; the history wiring around it (useBackStack) is untested plumbing. BoardScreen's task/dialog/sheet state is lifted into the shared nav stack so every close (in-app "x" or hardware Back) goes through the same onBack path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tep 9) manifest.webmanifest (standalone display, #1f1f1f theme/background matching useGlobalStyles, portrait orientation) plus two dependency-free PNG icons generated by scripts/make-mobile-icons.mjs via Node's own zlib. A service worker caches content-hashed /assets/* first and falls back navigations to cache, with same-origin-GET-only routing in a pure, tested shouldHandle() so the cloud API's SSE stream and OIDC exchange are never touched. Built by a second Vite config (vite.sw.config.ts) so the fixed sw.js name and the hashed main bundle don't have to share one Rollup output. The service worker's own tsconfig (WebWorker libs) is split from the app's (DOM libs) — mixing the two in one program conflicts on `self`. staticwebapp.config.json now excludes webmanifest/json from the SPA fallback and pins /sw.js to no-cache. scripts/verify-mobile-build.mjs builds the app and asserts the manifest, icons and sw.js are all real and wired together.
Add a `mobile` job to deploy.yml mirroring `web`: its own paths-filter entry, a turbo build with the taskmanager-mobile IAM client id, the staticwebapp.config.json copy, and Azure/static-web-apps-deploy@v1 into its own Static Web App. AZURE_STATIC_WEB_APPS_API_TOKEN_MOBILE is checked in a step rather than a job-level `if` (secrets aren't available there), so the job stays inert with a warning until the one-time Azure setup exists, instead of failing the whole workflow on every push that touches apps/mobile. Document that one-time setup — the SWA, the DNS record, the secret, and the taskmanager-mobile IAM client/redirect URI — in docs/09, and update docs/11's secrets table and deploy matrix to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…p 11) Step 11 of 12. Re-opened all ten files/areas the plan named on the finished tip (9c8eabd) and re-ran every gate there rather than trusting an earlier step's numbers on the same commit. Two real breakages, both the same shape: step 3 moved httpTransport.ts, polledEvents.ts, eventBus.ts and sseEvents.ts out of apps/web/src and into packages/cloud/src, and anything that named their OLD location by path rather than by import specifier went stale silently, since neither a prose comment nor a script reading a source file as text sits on the module graph typecheck or build walks. verify-remote-ipc.mjs and verify-remote-sse.mjs no longer ran at all — both bundle the moved modules by a literal apps/web/src/board/* path. Neither is wired into ci.yml or RELEASE.md's gates, so nothing red ever surfaced across eight steps of this branch. Repointed both at packages/cloud/src and dropped the now-unused @web alias; 16 remote-IPC checks and 36 push-channel checks pass clean. test/shell-parity.test.ts's global-CSS guard silently lost packages/cloud/src: SettingsScreen.tsx moved out of the apps/web/src entry HOST_TREES already covered, into a path nothing named. Nothing had actually declared a stray rule there, which is what makes it a coverage hole rather than a caught bug. packages/cloud/src now joins HOST_TREES, on the same "covered from day one" reasoning already written for apps/mobile/src. TaskDetail.tsx's readOnlyNotice docstring named the old path and, more substantively, still described the pre-Phase-27 three-tier transport ("relays only a status change and a new card") that httpTransport.ts's own header says stopped being true before this phase. Fixed both, since the file sits on this step's named list; left half-corrected would have been worse than left alone. Two more stale apps/web/src references turned up in packages/shared (ipcRelay.ts, ipcEventFanout.ts) — outside this step's named list, so recorded in the plan doc rather than edited. pnpm format:check also caught two pre-existing Prettier violations in apps/mobile/src/board (BoardCardRow.tsx, GitGraphSheet.tsx) from steps 6-7, whitespace-only. development sits exactly at this branch's merge-base and has not moved, so the merge ahead is a plain fast-forward with nothing to reconcile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Step 12 of 12. Re-ran the full gate list fresh on 9db1f5b (step 11's own commit, one past the tip its own numbers were measured on): pnpm format:check, turbo typecheck --force, turbo build --force, pnpm test, verify-mobile-build.mjs, and both ad hoc remote-IPC/SSE harnesses step 11 repointed. Every count matches step 11's independently-measured ones exactly — 12/12 typecheck, 8/8 build, 180 test files (3005 tests) passed, 16 and 36 checks on the two harnesses. Derived the per-package test sum from `vitest exec vitest list --filesOnly` rather than the workspace layout, per the plan's own instruction: 181 files across nine directories, with apps/mobile contributing exactly the two pure- module tests the "no component tests" constraint predicts (navStack, shouldHandle) and packages/cloud's 13 confirming the board modules step 3 moved are still exercised, not just no-longer-flagged by shell-parity's HOST_TREES fix. Recorded what stays unverifiable from a headless session: installing the PWA, pressing Back on a device, tap-to-move against a live desktop, and a completed CI deploy run — none of which any command here can exercise. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
development moved 100 commits ahead of this branch's fork point (PR #18's single-board/native-tickets feature, PR #19's sync-error fix, and everything those PRs themselves carried) while this branch did Phase 27's twelve steps. Six real content conflicts plus one file-location conflict, resolved as follows: - apps/web/src/App.tsx, board/BoardScreen.tsx: import-path conflicts against step 3's apps/web/src -> packages/cloud/src extraction. Kept the @tm/cloud paths, folded in development's genuinely new imports (BoardScope, syncGate, UnreachableBanner, selectAgentProjects). - packages/cloud/src/settings/ProjectsSection.tsx: git's directory-rename heuristic already placed development's new file at the extracted location; confirmed and staged as-is (package-specifier imports only, no path fixes needed). - .github/workflows/deploy.yml: NOT flagged as a conflict, but the auto-merge placed apps/client/package.json under the wrong filter (mobile: instead of web:), silently reintroducing the "web frozen on the old version" bug docs/11 describes fixing. Moved it to the web: filter; test/workflow-invariants.test.ts's own assertion now actually exercises it. - docs/11-ci-cd-pipeline.md, docs/plan/README.md: narrative docs where both sides appended after the same anchor. Merged the deploy-filter table (kept the mobile row, fixed to match deploy.yml) and reordered README.md so development's fixes/phases precede this branch's own Phase 27 section, ahead of the shared "Conventions" tail both sides already had. - test/shell-parity.test.ts: three describe-block conflicts (step 5's phone-fit block vs development's renamed agent-projects block, an EDITING-pane test using a WEB_TREE variable that no longer exists post-merge, and the HOST_ONLY_SECTIONS/ProjectsSection assertions) — kept both sides' tests, repointed every apps/web/src/settings/* reference the merge left stale to packages/cloud/src/settings/*. None of the above wired mobile into the merge's new features on their own — that surfaced only once the gates ran on the merged tree: - packages/cloud/src/board/useCloudBoard.ts (shared, unmodified by this branch) already depended on a sibling ./syncGate module that development had only added under apps/web/src/board — a build break, not a conflict. Moved syncGate.ts/.test.ts into packages/cloud/src/board alongside it, repointed apps/web/src/App.tsx's import. UnreachableBanner.tsx stays apps/web-local; nothing shared needs it and mobile has no sync-curtain treatment yet (noted, not built here). - shell-parity's NAV-parity test asserts apps/web and apps/mobile expose the same destinations. development added a Projects tile to apps/web; mobile's own NAV predates that PR and didn't have it, so the assertion would have gone red. Added the same tile to apps/mobile/src/App.tsx, rendering the shared <Projects/> component unmodified (same treatment as Performance and Attention) with a phone-fit media query added to its two-column layout (packages/ui/src/projects/Projects.tsx), matching step 5's own precedent. Also fixed the regex the test's own navIds() helper used: NavRail's accountItems prop (`{ id: 'signout', ... }`, new on development's side) collided with a whole-file scan for `{ id: '...' }`; scoped it to the NAV array literal specifically. - selectBoardTasks/selectArchivedTasks (packages/cloud/src/board/ boardSelectors.ts) gained a required `scope` parameter for the single-board feature. apps/mobile/src/board/BoardScreen.tsx has no scope-picker UI (only apps/web's BoardToolbar does) — passed the literal 'all' scope to preserve mobile's existing show-everything behaviour; a mobile scope switcher is a follow-up, not part of this merge. - packages/cloud/src/settings/SettingsScreen.tsx's `projects` prop went from absent to required; apps/mobile/src/App.tsx's call site wasn't touched by either branch's diff so it went stale silently. Passed board.state.projects, matching apps/web's own call. Gates run fresh on the merged tree, forced: pnpm format:check clean; turbo typecheck --force 12/12; turbo build --force 8/8; pnpm test 192 files / 3256 tests passed (11 skipped), 0 failed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
development moved another 13 commits ahead since the last merge (d93cf0b) — five PRs (#21-#27): PAT-based cloud connection, icon toggles replacing header switches, a narrower nav rail, clipboard-paste-to-attach, GitHub PR pipeline sync-status fix, Linux releases discontinued, and a projects/settings fix — plus four releases (v0.90.1 through v0.97.4). Conflicts, all textual or file-location, same shape as the last merge: - docs/09-deploying-the-cloud-service.md, docs/11-ci-cd-pipeline.md: both sides edited the same deploy-matrix tables. Kept the apps/mobile row (ours) and folded in development's real changes — Linux dropped from release.yml's table (feat/stop-linux-releases removed the whole job), matching what release.yml itself now has (no `linux:` job, no §6). - docs/plan/README.md: both sides appended narrative after the same anchor again. Same resolution as before — development's new fix section ("projects miss settings, and a plan-less project could not add tasks") precedes this branch's Phase 27 section, ahead of the shared "Conventions" tail. - packages/cloud/src/settings/{TokensSection.tsx,tokensApi.ts,tokensApi.test.ts, tokensView.ts,tokensView.test.ts}: git's directory-rename heuristic again placed development's new PAT-management files (added under apps/web/src/settings) at the extracted packages/cloud/src/settings location. Confirmed and staged as-is — package-specifier and relative- sibling imports only. - test/shell-parity.test.ts: the same WEB_TREE-vs-WEB_TREES collision as the last merge, recurring because development's own "projects miss settings" fix touched this file independently and re-diffed the same line. Same fix: kept WEB_TREES.flatMap(...). Not flagged as conflicts, but broken by the merge and only surfaced once the gates ran on the merged tree: - packages/cloud/src/settings/SettingsScreen.tsx's SettingsScreenProps gained two required fields — apiBase and getAccessToken — for the new TokensSection. Neither branch's diff touched apps/mobile/src/App.tsx's <SettingsScreen projects={...} /> call site, so it went stale silently. Passed config.cloudApiBase and () => auth.getAccessToken(), matching apps/web's own call. packages/ui/src/projects/Projects.tsx, AddTaskDialog.tsx and theme.ts all auto-merged cleanly (ProjectAdmin's new repo-capability prop is optional, paste-to-attach and the nav-rail width change don't touch anything mobile overrides). Gates run fresh on the merged tree, forced: pnpm format:check clean; turbo typecheck --force 12/12; turbo build --force 8/8; pnpm test 204 files / 3382 tests passed (11 skipped), 0 failed. scripts/verify-mobile-build.mjs (21 checks), verify-remote-ipc.mjs (16 checks) and verify-remote-sse.mjs (36 checks) all still pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Let's design a mobile app for Android.
It should have the same features as in the web cloud - to control tasks on the desktop client.
The UI should be designed for mobile though (be responsive).