Notechondria

Version: 0.1.39 Build Date: 2026-04-19T09:00

What's Changed

Editor per-note export filename

_exportNote in editor_app/lib/app_shell.dart previously suggested note.zip / note.md for single-note exports and only swapped in the title slug when the title was non-empty. User reports confirm that untitled notes landed on disk as a bare note.zip with no way to tell them apart. Fixed:

  • Single-note export: note-<uuid[0:6]>-<YYYYMMDD-HHMMSS> plus the format extension. First six chars of the stripped UUID + compact local-time timestamp so files sort naturally.
  • Recursive / category export: <category-slug>-<YYYYMMDD-HHMMSS> so category exports still read well but also carry a timestamp.
  • Local-only notes (no server-issued uuid): fall back to note-local-<timestamp> so the filename still contains enough info to disambiguate.

TODO.md cleanup

docs/TODO.md shrank from 409 to 219 lines. Every [x] completed round entry was removed (those already live in the relevant docs/versions/*.md round log). The remaining open items were regrouped into Bugs, Global reusable components, Editor, Planner, Backend sections with clearer subsection structure so the file reads as a real backlog instead of a changelog.

Two correctness-critical entries were promoted into the top-level Bugs section with full reproducer + backend-reference notes:

  • Note share / deep-link redirect failure. Audited the relevant code paths this round: the backend endpoint (NoteByUuidApiView at backend/notes/api.py:1044) is correctly AllowAny-gated; the frontend URL parser, deep-link handler, and post-frame dialog open all exist and wire correctly (_parseNoteUuidFromUrl, _openNoteByUuid, _bootstrapApp's deep-link branch). What is not in place yet is a regression test that exercises cold-start /#/notes/<uuid> with and without session and a coherent error message for private notes opened anonymously. Entry in Bugs captures the likely break points (OAuth browserReplaceState stripping the fragment; private-note 403 surfaced as raw text).

  • Category ownership UI mismatch. Audited the backend this round: DELETE /courses/<id>/ at backend/notes/api.py:690 correctly rejects non-owners with 403 (the course.creator_id_id != creator.id guard is there). The subscribe/unsubscribe endpoint CourseSubscribeApiView also exists. So backend is correct; the gap is in the editor sidebar, which calls _deleteCategory unconditionally and surfaces the 403 as a raw error. The TODO entry spells out exactly how to branch the _promptEditCategory action list based on course['is_owned'].

TODO.md new entries deferred this round

Added detailed spec rows for the user's 0.1.39 feedback that I couldn't finish in one round:

  • Attachment CDN rework — local-first storage via a new shared LocalAttachmentStore (IndexedDB on web, getApplicationSupportDirectory on native), local://<note-uuid>/<safe-filename> URL scheme replacing the inline base64 data URIs, upload-on-sync promoting from local blobs to CDN URLs, preview list in the editor toolbar, migration shim for existing base64 drafts, three-commit split plan.
  • Planner + Portal export/import — unchanged from 0.1.38 follow-up.
  • Cross-app export round-trip tests — unchanged.

Files Changed

New

  • docs/versions/0.1.39.md (this file).

Modified

  • VERSION: 0.1.38 \u2192 0.1.39.
  • docs/TODO.md: compacted from 409 to 219 lines; completed rounds removed; two new Bugs entries (note share redirect, category ownership UI); attachment CDN rework spec added under Editor / Note editor.
  • frontend/editor_app/lib/app_shell.dart: _exportNote now computes baseName from note-<uuid[0:6]>-<YYYYMMDD-HHMMSS> (single note) or <category-slug>-<YYYYMMDD-HHMMSS> (recursive).

Verification

  • editor_app: flutter analyze \u2014 52 issues (unchanged). flutter test test/smoke_test.dart -r compact \u2014 passes.

Notes / follow-ups

Audits from this round surfaced that the backend is already correct for both flagged concerns (note UUID stability via UUIDField(default=uuid4, unique=True) at backend/notes/models.py:237, and category-ownership delete gating at backend/notes/api.py:690). The remaining work on both concerns is frontend UX polish + regression test coverage, not backend rewrites. Those are now the top two entries in Bugs with concrete reproducer notes.

The attachment CDN rework remains the highest-value TODO item and is the one most likely to need a focused multi-round block of work. The spec in docs/TODO.md calls out the three-commit split so each commit stays reviewable.