fix: four-perspective audit remediation (student flow, security, UX, AI) - #24
Merged
Merged
Conversation
- plan scheduler: cap schedule horizon at today+365d and clamp task dueDate to <=today+3y (DoS via far-future deadline); degenerate session-config guard + slot-loop backstop; expandAbsences clamps range to <=400 days - plan tasks: validate client goalId belongs to the module (IDOR) - availability: strict HH:mm regex + from<to refine - auth: disableImplicitSignUp on social/OIDC when registration is closed/invite (bypass fix); explicit session expiry, rate limit, min password length - /api/health: default GET no longer writes storage; full probe gated behind ?full=1 + HEALTH_TOKEN, 30s cache - tus uploads: PATCH/HEAD/DELETE verify the stamped userId owns the upload - audit undo: scope create/update-undo deletes by userId for user-owned tables Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
The study plan now enforces "learn early, consolidate before the exam": - migration 0041 (additive): plan_session.kind (study|review|cards), semester_plan.week_overrides/stale_at/last_warnings, event.goal_id, and GoalConfig.reviewDays - tasks: learning tasks are due exam-reviewDays; a spaced review series + companion FSRS/mistakes "cards" tasks + a mock fill the window - scheduler: no learn task inside the consolidation window (assignment due in-window excepted), only review/cards there, no session on exam day, per-week capacity caps, horizon_clipped warning, earliestDue hoisted - recompute uses collectReplannableTasks (keeps pinned/done future sessions, catches up past-undone tasks); session kind persisted; warnings persisted - toggleSession completes/uncompletes its tasks; staleness flag on every plan mutation; auto-replan only on availability save, exam-date change, session done - exam goals sync an all-day exam calendar event (blocks the exam day) - task regeneration reconciles stale/removed generated tasks - reminders use local today; calendar bounds its plan-session query Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
- setup-checklist: derives the exam-date -> availability -> tasks -> compute
sequence from data; shown on module plan tab, strategy board first run,
onboarding CTA
- plan banners: "plan is stale" one-click replan + "N missed sessions - catch
up"; recompute shows a summary toast with humanized warnings
- readiness (pure, tested): exam goal card shows on-track/at-risk/unreachable
from remaining task minutes vs capacity-to-exam, plus persisted warnings
- week capacity override ("less time this week") in the availability editor
- shared module-plan-prefs component (save-on-change) used by both the strategy
board and the module plan tab
- deterministic actions drop the Sparkles icon; AiBadge on AI-generated tasks;
bonus 0-1 fraction + weight helper text; outline nudge
- i18n plan.* additions (de/en parity)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
- action-errors: typed ERR:<code> layer + toastActionError/useActionErrorToast client mapping (mirrors the AI_ERROR pattern); user-facing throws across plan/goal/writing/thesis/materials/usage actions now emit stable codes, localized client-side (de/en), unknown -> GENERIC - reminders: drop hardcoded de-DE; translatable notification templates via a job-safe createTranslator + reminderLocale() seam (R5 wires per-user locale) - formatters: grade-goal + mini-calendar use the active locale (lib/grades keeps the fixed German grade-scale convention, documented) - wording: drop "BYOK"/"Token-Verbrauch" jargon and the "Embedding-Modell" hint from user-facing strings - mistakes deck: language-independent identity via deck.kind, localized label + "Auto" badge/tooltip; reviewCard now revalidates (comment fixed) - errors coverage test (every code has de+en keys) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
…udit R5) - migration 0042 (additive): material.text_content_tsv (GIN) for full-text search, user_prefs.locale, event.skip_dates - materials: processing/error banner on detail page, ask-document gated on ready, chunk N/M progress, zip-unpack failure surfaced as a failed material - decks: log partial minutes on leave, FSRS next-interval preview on ratings - quizzes: parallel free-text grading with progress, "N cards to mistakes deck" link, honest "not graded" instead of 0%, retry-wrong only when wrong exists, prev/skip navigation, estimated progress for large single-shot generation - dashboard: NextExam scoped to active program, TodayFocus fallback CTA - calendar: delete single recurring occurrence via skip_dates, palette deep-link to a focused event, consistent server-local datetime handling - search: tsvector (GIN) material match + flashcard/question union - notifications: category push toggles reconciled with subscription state - reminders now follow the persisted user locale - tests: recurrence skip-dates, search query builder, FSRS interval preview Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
- writing project + retryThesis + createModule: transactional / onConflict so concurrent get-or-create can't violate the partial unique indexes or leave goalless modules - first-admin promotion moved to a post-commit hook under a pg advisory lock - material file route returns 416 for unsatisfiable ranges - cascade delete of program/semester/module enqueues a sweep-orphan-files job to remove the underlying storage objects (crash-safe, chunked) - cron schedules honor CRON_TZ; db pool gets explicit max/idle/connect timeouts and prepare:false for a transaction pooler - background AI paths respect the usage cap (embedding/OCR skip, search/title degrade gracefully) - getSetting gets a 30s in-process TTL cache (invalidated on write) - enforcing Content-Security-Policy (KaTeX/pdf.js/AI-safe) + HSTS - chat route rejects oversized bodies (413) before buffering - new ttl-cache + storage-paths helpers with unit tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
…dit R7 part 1) - chat stack (ai-sdk, markdown, katex) and FullCalendar are now dynamically imported (ssr:false), out of the shared app-shell first-load bundle - FormDialog gains a scrollable/contentClassName prop; goal-card attempt dialog migrated to it; goal-card delete uses ConfirmDeleteDialog (no native confirm) - goal-card attempts render as a stacked layout instead of a wide table - shared EmptyState component - calendar adds a listWeek agenda view, defaulted on phones (E21) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
…udit R7 part 2) - module tabs: scrollable tab strip with a pinned, non-scrolling "more tools" button so it stays reachable on phones (D5) - module-plan prefs row stacks its fields under sm (D4) - session dialog + today-plan card disable toggles while a mutation is in flight (useTransition) to prevent double-fire; localized errors (D13) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
- generation calls (writing outline/milestones/sources, deck cards, thesis brainstorm) now pass GEN_PARAMS + an explicit output budget (no mid-JSON truncation); added maxTokensForText helper - BYOK dead-end closed at request time: detect usable key presence; chat and generation surface an actionable "add your API key in Settings" message/link instead of a generic auth error - /ai short-circuits to a friendly "not configured" state and the command palette hides the AI entry when no model is available - generation-job failures show a friendly message (raw error kept as tooltip) - write-tool confirmation cards whitelist + localize fields and resolve moduleId to the module name (no raw uuids/ids) - AI-generated calendar events get a provenance marker in every view - usage feature keys are localized (cost estimate intentionally skipped) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
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.
Warum
Nach dem Merge des zielbasierten Lern-Workflows (v1.2.0) wurde die gesamte App aus vier Perspektiven auditiert (Student, Backend-, Frontend-, AI-Developer): sechs parallele Code-Audits, ~90 belegte Findings. Dieser PR behebt sie in 8 verifizierten Phasen — jede grün auf typecheck + Tests + Lint, Migrations-Phasen zusätzlich mit
db:generateohne Drift, plus erfolgreichemnext build.Was sich ändert
Student — der Lernplan erfüllt jetzt „vor der Prüfung wiederholen statt Neues lernen"
reviewDays): Lern-Tasks sind aufPrüfung − reviewDaysfällig; im Fenster landen nur noch Wiederholung + Probeklausur + FSRS-/Fehler-Deck-Sessions, kein neuer Stoff; der Prüfungstag ist frei und blockiert.Backend — Sicherheit, Korrektheit, Performance
goalId-IDOR geschlossen; tus-Upload-Ownership; transaktionale get-or-create/createModule; CSP + HSTS;getSetting-Cache; DB-Pool-Limits; AI-Nutzungslimits auf Hintergrundpfaden; Storage-Cleanup bei Kaskadenlöschung; UTC/Lokalzeit-Fix.Frontend — Konsistenz, Mobile, Performance
listWeek-Agenda, gestapelte Versuchstabelle); optimistische Toggles.ERR:<code>-Fehler statt roher deutsch/englisch gemischter Toasts; Reminder folgen der User-Sprache; de-DE-Formatierung/Jargon entfernt.AI — nativ, kostenbewusst, transparent
/ai& Palette bei fehlender AI ausgeblendet; Confirm-Cards zeigen Modulnamen statt UUIDs; AI-Herkunft im Kalender markiert.Lern-Kern
Migrationen (additiv)
0041— Konsolidierung:plan_session.kind,semester_plan.week_overrides/stale_at/last_warnings,event.goal_id,GoalConfig.reviewDays.0042— Suche & Locale:material.text_content_tsv(GIN),user_prefs.locale,event.skip_dates.Verifikation
npm run typecheck→ 0 ·npm run test→ 222 bestanden (u. a. erweiterte Scheduler-Property-Tests fürs Konsolidierungsfenster/Wochen-Override/Horizont-Cap,replan-, Readiness-, Suche-, Recurrence-Tests) ·npm run lint→ 0 ·npm run build→ erfolgreich (CSP verifiziert) · beide Migrationendb:generateohne Drift, additiv.Note
Dev-Umgebung: bewusste additive Schema-Änderungen. Ein Teil von Phase R7 (goal-card-Dialog-Migration + Mobile/Optimistik) wurde nach einem Agent-Abbruch manuell fertiggestellt und ist grün.
🤖 Generated with Claude Code
https://claude.ai/code/session_012Nrz9bERddhwVXWuZyVBn7
Generated by Claude Code