refactor/simplify #53

Merged
eliott merged 5 commits from refactor/simplify into chore/refactor 2026-06-04 20:37:10 +02:00
Owner
No description provided.
From a full-codebase review:

- import: run wipe + import in a single transaction so a failed import can
  no longer destroy existing data with nothing restored; compensate orphaned
  accounts from a failed CreateNew import; make DataWipe atomic
- import: reject zip bombs before decompression (entry-count + declared and
  actual uncompressed-size caps) and lower the compressed upload cap
- import: structurally validate the cast-only export payload before any DB
  write, so malformed archives fail with 400 instead of a mid-tx 500
- import: per-route throttle on /import and /import/preview; stop echoing
  Better-Auth internals on account-creation failure
- crypto: version-tag random-IV ciphertext for unambiguous detection;
  document the deterministic-encryption leakage tradeoff
- http: ValidationPipe transform:true; expose X-Request-Id via CORS
- config: require SMTP vars in production; depth-guard the FK cause chain

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each importer looped issuing a separate tx.insert per row, so a sizable
import meant hundreds-to-thousands of sequential round-trips holding the
import transaction (and its locks) open. Every row already gets an explicit
v7() id and no importer uses .returning(), so the per-row reuse/dedup logic
is unchanged — rows are now collected and flushed via a single chunked
batchInsert(tx, table, rows) per table. Identical ids, counts and label
reuse; far fewer round-trips.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deleting any frame ran two full-shoot UPDATEs to recompact numbers to 1..N,
even when removing the highest-numbered frame. Numbers are distinct positive
integers, so the shoot is already gapless 1..N exactly when COUNT == MAX.
Check that cheaply after the delete and skip the rewrite when it holds (the
common case); only a gap left mid-sequence still falls back to the existing
negate-then-renumber two-pass. End state is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
planExport fired 11 COUNT(*) queries to populate meta.counts and then both
export paths re-read every row anyway. buildExport now derives counts from
the arrays it already collects; streamArchive tallies rows as they stream and
emits meta (with counts) last. Safe because the importer does a full
JSON.parse (key order irrelevant) and never reads meta.counts, so the archive
format is unchanged. Removes the now-dead countRows from PagedQuery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- reference-validator: collapse the duplicated global/non-global branches in
  checkRef into a single query with a conditional column.
- shoot: route update/setPinned/setDone through one updateOwnedOrThrow helper
  instead of repeating the update-then-404 block three times.
- changelog: drop the pre-select existence check in update (TOCTOU); the
  UPDATE ... RETURNING already reports a missing row, and throwing before the
  item rewrite rolls the transaction back.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eliott force-pushed refactor/simplify from 1e4cbaf83d to 4360096921 2026-06-04 20:37:05 +02:00 Compare
eliott merged commit 4bd6e53b63 into chore/refactor 2026-06-04 20:37:10 +02:00
eliott deleted branch refactor/simplify 2026-06-04 20:37:11 +02:00
Sign in to join this conversation.
No reviewers
No labels
run-ci
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
RollNote/rollnote-api!53
No description provided.