108 Commits

Author SHA1 Message Date
37a01e4d96 fix(ui): mobile layout — no horizontal page scroll, truncate names, scrollable card table
- Page scroll container is overflow-x-hidden so the interface stays fixed; long
  content can no longer push the page wider than the viewport (tree was ~50% cut off).
- CardTable wrapped in overflow-x-auto with a min-width so only the table scrolls
  horizontally on small screens.
- Sublesson and lesson-tree rows get min-w-0 so truncate works in flex; long names
  now ellipsize instead of overflowing. Tree drag handle + hover actions hidden on
  mobile (were unusable via touch anyway), freeing width for the name.
- Lesson detail title wraps and scales down on mobile.
2026-05-21 10:59:55 +02:00
eaed138e38 fix(auth): don't 500 / orphan accounts when verification email fails
Registration now rolls back the just-created user (token cascades) and returns a
clear 502 EMAIL_SEND_FAILED if the verification email can't be sent, instead of a
500 leaving an unverifiable orphan account. resend-verification and
forgot-password swallow mail failures (log + still return generic 200) so a broken
mailer can't break the flow or leak account existence. Adds regression tests.
2026-05-21 10:52:28 +02:00
5e7b60dfce chore(deploy): expose flashcards on host port 4100 (4000 was taken) 2026-05-21 10:25:11 +02:00
102cbcb01a chore(deploy): pull image from Gitea registry + manual buildx push flow 2026-05-21 10:13:31 +02:00
fe44e393b3 chore(deploy): expose flashcard on host port 4000 (4000:3000) 2026-05-21 09:58:59 +02:00
34b6c8d945 chore(deploy): Dockerfile + Dockge compose + deploy guide 2026-05-21 09:51:52 +02:00
34431331e9 fix(practice): update session counters client-side after each answer
The in-session progress bar reads session.cardsShown/cardsCorrect/cardsIncorrect,
but the session store's answer() never refreshed the session object — the backend
tracked the counters but the client kept the stale start values (all 0), so the bar
appeared frozen. answer() now mirrors the backend's increment locally; end() still
replaces with authoritative server totals. Adds an E2E regression test.
2026-05-21 07:54:15 +02:00
f5000d3c58 fix(import): set owner on auto-created lessons + nest lesson_path under started lesson
Two bugs surfaced by Excel import on a lesson with a lesson_path column:
1. resolveLesson created lessons without owner_id, so after the ownership
   model (sub-project B) they never appeared in getLessonTree — import
   reported success but nothing was visible.
2. lesson_path was resolved at the root; cards landed in new root lessons
   instead of under the lesson the import was started from.

Now: auto-created lessons get ownerId + visibility 'private'; lesson_path is
resolved relative to the started lesson (each segment a sublesson). Also drop
the stale eager card_progress insert (progress is per-user and lazy since B).
2026-05-21 07:45:49 +02:00
2890e19953 fix(frontend): wrap lesson tree sibling groups in SortableContext for drag feedback 2026-05-21 07:27:12 +02:00
8499c60acb test(e2e): search palette + lesson detail + stats + legacy redirect
Add e2e/ux.spec.ts covering the ⌘K search palette, lesson detail page,
stats sections, and the legacy /admin → /lessons redirect.

Also fixes two issues uncovered by running the full suite:
- Skip auth rate limiter in e2e by running the backend with NODE_ENV=test
  (registration limit of 5 was tripping later tests).
- Render the card table for lesson owners even when the lesson has zero
  cards, so the first card can be added from the detail page.
2026-05-21 07:24:42 +02:00
99c55c1dba chore(frontend): remove obsolete Admin/AdminLesson pages 2026-05-21 07:17:04 +02:00
9928390946 feat(frontend): router restructure /admin → /lessons with redirects 2026-05-21 07:16:17 +02:00
d5dfc0d2db feat(frontend): ⌘K search trigger in layout + /lessons nav 2026-05-21 07:15:02 +02:00
4b9ff4b783 feat(frontend): ⌘K search palette modal 2026-05-21 07:13:50 +02:00
5754bec679 feat(frontend): lessons page with filter (replaces Admin.tsx) 2026-05-21 07:12:27 +02:00
0529e2a5e8 feat(frontend): lesson tree with filter + dnd-kit drag reorder 2026-05-21 07:11:13 +02:00
3254e225e9 feat(frontend): rich lesson detail page 2026-05-21 07:09:26 +02:00
d9b913aab7 feat(frontend): lesson stats panel + sublesson list + recent sessions list 2026-05-21 07:07:46 +02:00
2a6d048b65 feat(frontend): rewritten stats page with heatmap + progress + due 2026-05-21 07:06:37 +02:00
4c2d42779f feat(frontend): due-overview card with start-review CTA 2026-05-21 07:05:35 +02:00
a10d02cbaf feat(frontend): lesson progress list with sorting 2026-05-21 07:04:34 +02:00
5df6b240d9 feat(frontend): 12-month heatmap component 2026-05-21 07:03:50 +02:00
ab382a2c62 feat(frontend): API clients for search + stats extensions + due session 2026-05-21 07:02:57 +02:00
65dcd185b8 test(ux): integration coverage for search + stats + due session 2026-05-21 07:02:13 +02:00
9bfcb02c25 feat(stats): /lessons-progress and /due routes + heatmap default 52 weeks 2026-05-21 07:00:50 +02:00
754f8b6fc6 feat(sessions): startDueSession + POST /api/sessions/due 2026-05-21 07:00:00 +02:00
fb25f48f04 feat(stats): lessons-progress and due-overview services 2026-05-21 06:58:30 +02:00
f9912a7a8d feat(search): /api/search route 2026-05-21 06:56:44 +02:00
b1e5d5f276 feat(search): global search service with library/marketplace + cards 2026-05-21 06:55:35 +02:00
aab1b4fdc2 docs: implementation plan for sub-project C — UX extensions (20 tasks) 2026-05-21 02:40:32 +02:00
cdd54d3745 docs: spec for sub-project C — UX extensions 2026-05-21 02:31:23 +02:00
c04b857c10 test(e2e): multi-user sharing + subscribe + practice flow 2026-05-21 00:42:52 +02:00
44622442de feat(frontend): marketplace route 2026-05-21 00:40:31 +02:00
9fdadca529 feat(dashboard): subscriptions section 2026-05-21 00:39:36 +02:00
6a65c5cf96 feat(frontend): marketplace page with subscribe + fork 2026-05-21 00:38:20 +02:00
3356767d21 feat(admin): visibility toggle, fork/unsubscribe, readonly CardTable for subscribers 2026-05-21 00:36:51 +02:00
7eabd667ce feat(frontend): lesson badges + marketplace nav link 2026-05-21 00:34:31 +02:00
01f7df3735 feat(frontend): API for visibility/fork/subscribe/marketplace/curated 2026-05-21 00:32:50 +02:00
4d4001e202 test(ownership): multi-user integration coverage 2026-05-21 00:31:23 +02:00
5822dbc8ae feat(app): mount sharing routes + post-migration backfill 2026-05-21 00:28:29 +02:00
fb95ccd772 feat(routes): thread userId through routes + visibility/fork/curated endpoints 2026-05-21 00:26:49 +02:00
181a757323 refactor(marketplace): substring-only q filter, fix test to use real substring 2026-05-21 00:24:01 +02:00
9dcce76f01 feat(marketplace): list shared roots with filters + sort + pagination 2026-05-21 00:23:10 +02:00
4339728326 feat(fork): subtree fork service + tests 2026-05-21 00:19:46 +02:00
f378c0fdb0 feat(subs): subscribe/unsubscribe/list service + routes 2026-05-21 00:17:16 +02:00
28321c6f84 feat(stats): per-user filtering across all aggregations 2026-05-21 00:15:24 +02:00
a0c11d8e21 feat(sessions): per-user sessions and progress 2026-05-21 00:13:15 +02:00
2d37aee32c feat(cards): permission-aware CRUD 2026-05-21 00:11:00 +02:00
9aaba94b95 feat(lessons): ownership-aware CRUD + tree filtering + visibility/curated 2026-05-21 00:09:32 +02:00
66363b8094 feat(perms): canRead/canEdit with ancestor walk + tests 2026-05-21 00:07:05 +02:00