Commit graph

124 commits

Author SHA1 Message Date
le king fu
d38ddab0f0 chore: bump version to 1.6.4 (versionCode 16)
Includes Expo SDK 54 patch alignment from #87.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 14:48:46 -04:00
le king fu
8ee9f9918e state: sync after #87 2026-05-10 13:42:25 -04:00
2eed0415b9 Merge pull request 'chore(deps): align Expo SDK 54 patches' (#88) from issue-87-align-expo-sdk-patches into master 2026-05-10 17:41:42 +00:00
le king fu
ea4a516174 chore(deps): align Expo SDK 54 patches via expo install --fix
Bumps 6 patch versions inside SDK 54 lockstep:
- expo 54.0.33 -> 54.0.34
- expo-auth-session 7.0.10 -> 7.0.11
- expo-crypto 15.0.8 -> 15.0.9
- expo-linking 8.0.11 -> 8.0.12
- expo-notifications 0.32.16 -> 0.32.17
- expo-web-browser 15.0.10 -> 15.0.11

expo-doctor: 17/17 checks pass.
Smoke test (tests/smoke.test.cjs): 6/6 OK.

Closes #87

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 08:28:06 -04:00
le king fu
297acac768 state: sync after #81 2026-05-07 21:36:50 -04:00
le king fu
1d7388f9ff chore: bump version to 1.6.3 (versionCode 15)
Includes uuid override fix for GHSA-w5hq-g745-h8pq.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:37:13 -04:00
le king fu
70211fcad7 fix(security): bump uuid override to ^11.1.1 to close GHSA-w5hq-g745-h8pq
The previous override ^11.0.0 allowed the vulnerable range 11.0.0 - 11.1.0.
npm resolved on 11.1.0, leaving the buffer-bounds-check CVE active in
v3/v5/v6 with buf arg. Bumping to ^11.1.1 stays in the 11.x major (CJS
compat preserved per past revert at 800f777) and fixes the advisory.

npm audit: 0 vulnerabilities. smoke tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:35:46 -04:00
097d3f2d35 test(smoke): add non-regression smoke for uuid + package overrides (#84) 2026-05-02 15:59:29 +00:00
le king fu
cfedde0fa6 test(smoke): add non-regression smoke for uuid + package overrides
Plain-node script invoked via `npm test`. Catches the buffer-bounds
regression area from GHSA-w5hq-g745-h8pq (uuid v3/v5 with buffer arg)
and validates package.json structure. No jest/Expo runtime needed —
runs in seconds, suitable for the defenseur-auto chain to gate auto-PRs.
2026-05-02 11:49:13 -04:00
le king fu
54ed29c50f docs(eas-build): document APK upload retry pattern for transient 502/504
Captures lesson from v1.6.2 release: when curl reports HTTP 502/504 ~60s
into the upload of a 90+ MB APK, the cause is client-side bandwidth dropping
under ~1.5 MB/s, not Traefik or Forgejo config. Retry — bandwidth recovers.

Adds: retry loop, diagnostics checklist, correct DELETE asset path
(/releases/{release_id}/assets/{asset_id}, not /releases/assets/{asset_id}).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 07:17:51 -04:00
le king fu
22f96bc9a9 chore: bump version to 1.6.2 (versionCode 14)
Security release: 5 CVE resolved in build-time dep chain via overrides
(@xmldom/xmldom, uuid, postcss). 4 HIGH + 1 MEDIUM cleared.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 19:48:49 -04:00
2245484407 Merge pull request 'fix(security): override postcss to ^8.5.10' (#80) from fix/vuln-postcss-override into master 2026-04-28 01:26:11 +00:00
le king fu
08cba37775 fix(security): override postcss to ^8.5.10
Resolves GHSA-qx2v-qp2m-jg93 (PostCSS XSS via Unescaped </style> in CSS
Stringify Output) in the @expo/metro-config + tailwindcss build chain.
Build-time only, not runtime-exploitable in RN, but cleared for audit hygiene.

Defenseur scan post-override: 13/13 passed, 0 findings (the residual uuid
cascade is suppressed via defenseurs allowlist for GHSA-w5hq-g745-h8pq).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:37:19 -04:00
cc1e187c85 Merge pull request 'verify(security): seed STATE+SECURITY + defenseur rescan (#76)' (#79) from fix/vuln-C-verification into master 2026-04-24 18:14:34 +00:00
ced900b191 Merge pull request 'fix(security): override uuid to ^11.0.0 (#75)' (#78) from fix/vuln-B-uuid-override into master 2026-04-24 18:14:25 +00:00
dfe5214b57 Merge pull request 'fix(security): override @xmldom/xmldom to ^0.8.13 (#74)' (#77) from fix/vuln-A-xmldom-override into master 2026-04-24 18:13:56 +00:00
le king fu
f52e1e9e06 docs(security): seed STATE.md and SECURITY.md after vuln remediation
STATE.md follows the 3-section monorepo pattern (Position actuelle, Decisions
recentes, Blockers actifs). SECURITY.md tracks resolved CVE (4 HIGH xmldom)
and residuals (GHSA-w5hq-g745-h8pq uuid, non-exploitable in practice).

Refs #76

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:30:41 -04:00
le king fu
ed4c10f29c fix(security): override uuid to ^11.0.0
Resolves GHSA-w5hq-g745-h8pq in the transitive chain (xcode + @expo/ngrok).
Per spec decision D3, we pin ^11.0.0 (not ^14.0.0) to avoid ESM-only breaking
CJS consumers. Actual vulnerable code paths (v3/v5/v6 with buf param) are not
used by xcode or @expo/ngrok — they only call uuid.v4() — so the override is
safe in practice even though npm advisory range is <14.0.0.

Refs #75

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:16:35 -04:00
le king fu
5842a686b2 fix(security): override @xmldom/xmldom to ^0.8.13
Resolves 4 HIGH CVE in the xmldom transitive dep chain (Expo CLI + xcode/plist).
Not runtime-exploitable in APK (build-time deps only) but cleaned for audit hygiene.

- GHSA-2v35-w6hq-6mfw (DoS — uncontrolled recursion in XML serialization)
- GHSA-f6ww-3ggp-fr8h (XML injection via DOCTYPE serialization)
- GHSA-x6wf-f3px-wcqx (XML injection via processing instruction serialization)
- GHSA-j759-j44w-7fr8 (XML injection via comment serialization)

Refs #74

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:13:40 -04:00
8a0cc97018 Merge PR #73 — fix: widget render-optimiste (#71) 2026-04-19 20:24:18 +00:00
le king fu
af43a3f1a8 fix: render-optimiste + timing instrumentation for widget toggles (#71)
Widget tap-to-expand felt slow (several seconds). Inverts the order in all
three click handlers so the widget re-renders BEFORE awaiting the
AsyncStorage write — the user sees the change immediately, persistence
finishes in the background.

- TOGGLE_COMPLETE / TOGGLE_EXPAND / TOGGLE_SUBTASK : render before persist
- EXPAND_DEBOUNCE_MS 2000 -> 600 (still blocks accidental double-taps,
  no longer feels laggy when collapsing right after expanding)
- persistState() wraps setWidgetState in try/catch — on failure the next
  handler call re-reads the prior state from AsyncStorage, UI self-heals
- Dev-only timed() helper logs each step to logcat for measurement:
  adb logcat -s ReactNativeJS | grep '\[widget\]'

Out of scope: cold start of the Android headless task service (suspected
main contributor to perceived slowness, unfixable from JS).
2026-04-19 16:17:41 -04:00
le king fu
9cf507429a docs: archive spec-simpl-liste-web (milestone 12/12 done)
Design document for the Simpl-Liste Web frontend, Logto integration,
and hybrid mobile/web sync. Milestone spec-simpl-liste-web is fully
delivered — preserving the spec as historical reference.
2026-04-19 15:57:00 -04:00
le king fu
7e7a518b74 chore: sync package-lock.json to version 1.6.1
Lockfile version field was left at 1.5.1 after the 1.6.1 bump in 9a53022.
2026-04-19 15:56:49 -04:00
le king fu
9a53022421 chore: bump version to 1.6.1 (versionCode 13)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 09:44:19 -04:00
fe43b65cfd Merge pull request 'fix: replace broken swipe-to-refresh with toolbar button (#61)' (#67) from issue-61-refresh-button-toolbar into master 2026-04-09 13:44:08 +00:00
le king fu
5b0d27175c fix: replace broken swipe-to-refresh with toolbar refresh button (#61)
The RefreshControl on DraggableFlatList never worked because the
library wraps its FlatList in a GestureDetector with Gesture.Pan(),
which intercepts vertical swipes before RefreshControl can detect
them — particularly with activationDistance=0 in position sort mode.

Replace with a toolbar refresh button (RefreshCw icon) on inbox and
list detail screens. The button uses an Animated spin during refresh,
matching the web UX. Removes all dead RefreshControl code and the
useless refreshControl prop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 09:37:26 -04:00
1a1eddfd68 Merge pull request 'fix: refresh Android widget after sync push and pull (#65)' (#66) from issue-65-widget-sync-refresh into master 2026-04-09 13:37:06 +00:00
le king fu
23f3144dc4 fix: refresh Android widget after sync push and pull (#65)
The sync client writes directly to the DB via drizzle, bypassing the
repository functions that normally trigger syncWidgetData(). As a
result, changes coming from the web (or any remote source) never
refreshed the home screen widget.

Call syncWidgetData() once at the end of pullChanges (after all remote
changes are applied) and after a successful pushChanges (to reflect
synced state). Single call per cycle avoids spamming widget updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 09:01:29 -04:00
le king fu
1df41cef1f fix: auto-apply migrations on startup + cleanup duplicate inboxes (#60)
- Add migration 0002 to soft-delete duplicate inboxes per user, keeping
  the oldest one and reassigning tasks to it.
- Run drizzle migrations on server startup via drizzle-orm/node-postgres
  migrator.
- Update Dockerfile to copy the migrations folder into the runtime image
  and externalize pg/drizzle-orm from the esbuild bundle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:53:09 -04:00
le king fu
2a0dd01307 chore: bump version to 1.6.0 (versionCode 12)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:37:50 -04:00
137dc83bf8 Merge pull request 'fix: issues #60 #61 #62 #63 — inbox, refresh, subtask depth, chevron/detail' (#64) from issue-60-fix-duplicate-inbox into master 2026-04-09 01:33:40 +00:00
le king fu
78471543c3 fix: separate subtask expand chevron from detail view icon (#63)
Split TaskItem into two independent states:
- `expanded` (chevron): toggles subtask visibility, only shown when
  subtasks exist
- `detailOpen` (search icon + title click): opens detail panel with
  notes, priority, edit/delete actions

The two actions are fully independent — expanding subtasks does not
open the detail view and vice versa.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:15:59 -04:00
le king fu
21020406b2 fix: prevent sub-subtask creation, limit nesting to 2 levels (#62)
Web: hide "Add subtask" button when depth >= 1 in TaskItem.
API: reject task creation if parentId points to a task that already
has a parentId (max depth validation).
Mobile: hide subtask section in task detail when viewing a subtask.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:13:43 -04:00
le king fu
894ac03072 feat: add refresh button on web + swipe-to-refresh on mobile (#61)
Web: add a RefreshCw button next to the list title in TaskList that
calls router.refresh() with a spin animation.

Mobile: add RefreshControl to DraggableFlatList on both inbox and
list detail screens, using the app's blue accent color.

Also deduplicate list insert values in sync/route.ts (review feedback).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:04:55 -04:00
le king fu
6c36ebcce5 fix: wrap inbox merge in transaction, revert seed to random UUID (#60)
Address review feedback:
1. Wrap inbox deduplication (select, reassign tasks, soft-delete) in a
   db.transaction() for atomicity.
2. Revert seed.ts to use random UUID — a fixed ID shared across users
   would cause PK conflicts. The sync endpoint handles deduplication.
3. Subtasks share the same listId as their parent, so the reassign
   query already covers them (clarified in comment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:54:55 -04:00
le king fu
d9daf9eda4 fix: resolve duplicate inbox on web after mobile sync (#60)
When mobile syncs its inbox (fixed ID) to the web, check if an inbox
already exists for the user. If so, reassign tasks and soft-delete the
old inbox to prevent duplicates. Also harmonize seed.ts to use the same
fixed inbox ID as mobile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:50:12 -04:00
le king fu
71ee702739 chore: bump version to 1.5.2 (versionCode 11)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:42:22 -04:00
0893cea489 Merge pull request 'fix: resolve sync data inconsistency between mobile and web (#55)' (#58) from fix/simpl-liste-55-sync-data-inconsistency into master 2026-04-08 19:32:15 +00:00
le king fu
8f7204e4b1 fix: resolve sync data inconsistency between mobile and web (#55)
Three root causes fixed:

1. API GET /api/sync returned raw entities but mobile client expected
   {changes: [...], sync_token} format — pullChanges() iterated
   data.changes which was undefined, silently skipping all server data.
   Now transforms entities into the SyncPullChange format.

2. Mobile outbox writes used snake_case keys (due_date, list_id, etc.)
   but server processOperation spreads data directly into Drizzle which
   expects camelCase (dueDate, listId). Fixed all outbox writes to use
   camelCase. Also fixed task_tag → taskTag entity type.

3. Missing completedAt in task outbox payloads — completion state was
   lost during sync. Added completedAt to both create and update outbox
   entries, and added Date conversion in server update handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:28:36 -04:00
818f66205b Merge pull request 'fix: update deps for high vulnerabilities (#54)' (#57) from fix/simpl-liste-54-vulnerability-updates into master 2026-04-08 19:23:37 +00:00
le king fu
5b16882a83 fix: update drizzle-orm and @xmldom/xmldom to fix high vulnerabilities (#54)
- drizzle-orm 0.45.1 → 0.45.2 (SQL injection via improperly escaped identifiers)
- @xmldom/xmldom 0.8.11 → 0.8.12 (XML injection via unsafe CDATA serialization)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:22:42 -04:00
45d463c849 Merge pull request 'fix: rename .env.example to .env.template (#53)' (#56) from fix/simpl-liste-53-env-example-false-positive into master 2026-04-08 19:21:40 +00:00
le king fu
a5e9aa6f09 fix: rename .env.example to .env.template to avoid false positive (#53)
The defenseur flagged web/.env.example as a tracked secret file.
Renaming to .env.template avoids the .env* pattern match while
keeping the same purpose as a configuration template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:20:55 -04:00
le king fu
89b3dada4a fix: replace Link with anchor tags for Logto auth routes
Next.js <Link> components prefetch routes on render/hover. When used
for /api/logto/sign-out, this triggered the sign-out handler during
normal navigation, clearing the session cookie and causing auth loops.

Also: wrap getAuthenticatedUser with React cache() for deduplication,
clean up diagnostic logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:31:04 -04:00
le king fu
9933c3678e fix: pass full URL to handleSignIn for callback URI matching
The Logto SDK needs the full callback URL (not just searchParams) to
verify it matches the redirect URI registered during sign-in.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:28:08 -04:00
le king fu
f786947941 fix: resolve Logto auth crash on web — remove illegal cookie set in layout
The (app)/layout.tsx was calling cookieStore.set() which is forbidden in
Server Components under Next.js 16 (only allowed in Server Actions and
Route Handlers). This caused a 500 error immediately after Logto login.

Also includes: mobile sync client improvements, i18n updates, web API
rate limiting, Bearer token support for mobile clients, and Dockerfile
optimizations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:12:59 -04:00
14c208be46 Merge pull request 'fix: force widget refresh after subtask toggle (#32)' (#33) from fix/simpl-liste-32-widget-subtask-toggle into master 2026-04-08 16:44:46 +00:00
le king fu
6328a8d0d3 fix: correct Logto session cookie prefix in middleware
Cookie is named `logto_<appId>` not `logto:<appId>`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 08:56:21 -04:00
8462aa9ef4 Merge pull request 'feat: add mobile sync client with outbox pattern (#40)' (#47) from issue-40-sync-mobile into master 2026-04-06 16:59:00 +00:00
b7a090df71 Merge pull request 'feat: implement web frontend with full task management UI (#39)' (#46) from issue-39-frontend-web into master 2026-04-06 16:58:35 +00:00