Skip to content

Release v1.7.0 - #147

Merged
Muawiya-contact merged 21 commits into
mainfrom
develop
Sep 7, 2026
Merged

Release v1.7.0#147
Muawiya-contact merged 21 commits into
mainfrom
develop

Conversation

@Muawiya-contact

Copy link
Copy Markdown
Member

Release v1.7.0 — JS-only, ships over the air on the production channel (runtimeVersion stays 1.3.0; no new APK).

Headline: Offline mode (#133)

  • Browse offline — today's concept, History, Saved, Stats from cache.
  • Act offline — like, save, follow topics, mark-as-learned apply instantly and persist.
  • Auto-sync — a durable, coalescing mutation queue replays when connectivity returns or the app foregrounds, then reconciles with the server.
  • Never hangs offline (hardened startup) + a global offline banner.
  • No native module — inferred connectivity keeps it OTA.

Also in this release

On merge to main, release.yml will

  1. Publish production + preview OTA → phones auto-update to 1.7.0 (What's New card highlights offline mode)
  2. Cut the v1.7.0 tag + Release; the APK build skips (runtimeVersion unchanged)
  3. Auto-deploy the api service from main

Required check

The Migrations applied check must pass — it will, since 0008/0009 are recorded in applied.txt (and already applied to prod).

Merge pull request #137 from Coding-Moves/develop
Deploys don't auto-migrate — migrations are run on Supabase by hand — so a
released migration nobody ran leaves the app querying a missing column (the
pool-topup 'column claimed_at does not exist' crash). Add an applied.txt ledger
of prod-applied migrations and a workflow that fails on main / release PRs when
any backend/migrations/*.sql isn't listed. Seeded with 0001-0007 (actually
applied); 0008/0009 are intentionally absent so the check flags the current
real gap until they're run on prod and recorded.
CI check for unapplied production migrations
The job had no name, so GitHub reported the check as 'check'. Name it
'Migrations applied check' so it can be added as a required status check on
main with a clear, unambiguous context.
Captures the develop->main release flow, the JS-only vs native (runtimeVersion)
rule, the features-only What's New policy, and — the part that keeps biting —
that backend/migrations must be applied to prod by hand and recorded in
applied.txt, enforced by the required Migrations applied check.
Adds concept_backlog.claimed_at (fixes the pool-topup 'column claimed_at does
not exist' crash) and the by-concept like-count index to the applied ledger.

MERGE ONLY AFTER these have actually been run on the prod Supabase DB — the
ledger asserts prod state, and the Migrations applied check goes green off it.
- Bold header ('Check your email') above the body, for scannable hierarchy.
- Show the entered email back (bold) so typos are obvious, while staying
  neutral about whether an account exists ('if it's registered').
- Body in the primary text colour instead of green-on-green, for readable
  contrast on the success surface in both light and dark themes; banner marked
  accessibilityRole='alert'.
- Clear the banner when the email field is edited again.
- Same treatment applied to the sign-up 'check your email' notice.
The notice banner got accessibilityRole='alert'; give the error banner the
same so errors are announced consistently.
Improve Forgot Password confirmation banner (#136)
No native connectivity module (keeps the app JS-only / OTA). The API client
flips to offline when a fetch throws and back to online the moment any request
reaches the server; ConnectivityContext exposes it app-wide via useOnline().
A thin strip above the navigator (signed-in and auth screens) that appears
while offline — 'Offline — changes will sync when you reconnect' — replacing
the single per-screen Today notice as the app-wide indicator.
The app-level spinner is gated on auth loading, which only cleared inside
getSession()'s .then — a rejection or hang left it spinning forever (the
infinite-spinner-offline report). Add a .catch (treat as signed out) and an
8s failsafe timeout so loading always resolves.
- Use useSyncExternalStore so the provider reads current connectivity on mount
  and can't drop a flip that happens before subscription — fixes the banner
  not showing when the app is opened offline (child providers fire the first
  requests before the parent provider's effect would subscribe).
- Wrap NavigationContainer in a flex:1 View so it fills beneath the banner.
- clearTimeout the auth failsafe on unmount.
Offline mode — Phase 1: never-hang + global offline banner (#133)
AsyncStorage-backed outbox keyed by (kind, target) so only the latest intent
per key is kept — safe because the server ops are idempotent/whole-list
(like/save PUT/DELETE, topics whole-list PUT, daily-complete idempotent). A
like→unlike→like offline collapses to one 'like'.
Each mutation now, on a network failure (ApiError status 0), enqueues the
desired intent and PERSISTS the optimistic change instead of throwing (which
made the context roll it back). A real HTTP error still throws → rolls back.
On success it supersedes any stale queued intent for that key. flushQueue()
replays the queue (stop on offline, drop 4xx poison, keep 5xx) then reloads
/me/state to reconcile. forget() clears the queue on sign-out. markLearned
carries title/topic so an offline completion keeps a proper History row.
ProgressProvider drains repository.flushQueue() when connectivity returns
(subscribeConnectivity) or the app foregrounds (AppState), and once on mount
for leftovers from a previous session, applying the reconciled state.
Serialised so overlapping triggers don't double-replay.
…ist (#145)

- Offline mark-learned now bumps the streak/stats to match the optimistic
  update, so the streak no longer reverts after an offline completion.
- The 'learn' queue entry carries its date; a completion queued on a previous
  day is dropped on flush rather than wrongly completing today's concept
  (/v1/daily/complete only targets 'today').
- Guarded dequeue: after replaying an intent, only remove it if the stored
  entry still equals it, so a same-key mutation made mid-flush isn't clobbered.
- Offline save adds a minimal savedConcepts row (title/topic threaded through
  toggleBookmark) so it shows in the Saved list immediately, not just the count.
Offline mode — Phase 2: mutation queue + reconnect sync (#133)
JS-only release (runtimeVersion stays 1.3.0, ships OTA). Headline: offline
mode (#133) — cached browsing, offline like/save/follow/mark-learned with a
durable queue that auto-syncs on reconnect, plus the never-hang startup and
global offline banner.

@Muawiya-contact Muawiya-contact left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ok

@Muawiya-contact
Muawiya-contact merged commit 9b010bc into main Sep 7, 2026
2 checks passed
Muawiya-contact added a commit that referenced this pull request Sep 7, 2026
Merge pull request #147 from Coding-Moves/develop
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.

1 participant