Files
InkNote/e2e/run.sh
T
marcandClaude Opus 5 3acb8b66a4 Free unused attachments, and keep versions by count rather than by age
Two rules governed version retention: the newest 50 per note, and a sweep
of anything past 90 days. The second was wrong. The count already bounds
what a note can accumulate, so age only ever deleted history nothing had
replaced — and it bit hardest exactly where history is most wanted, a
note left alone for a quarter of a year losing its whole past for having
done nothing. It is off unless VERSION_RETENTION_DAYS is set.

How many versions to keep is now a notebook's own setting, falling back
to the server default when left empty. A reference notebook can keep
fifty of everything while a scratch one keeps three.

That makes freeing attachments answerable. A picture taken out of a note
cannot be deleted straight away: the versions from before still show it,
and restoring one would find a hole. It is released once no current note
and no kept version refers to it — which, with retention by count, is
when the last version holding it is pushed out.

The server cannot look for itself, bodies being encrypted, so the client
reports a note's attachments on every save as it already does for links,
and a version inherits what the note held when it was snapshotted — by
definition what that version contains.

Two things make it safe rather than merely plausible. Silence is not
"uses nothing": a note written before this existed has no rows, which
looks identical to one with no pictures, so nothing is released for a
user while any of their notes has yet to report — the prefetch that fills
the search index reports for them on its first pass. And an upload has a
row before the note using it does, so recent attachments are left alone.

POST /api/admin/housekeeping runs the sweep on demand.

Caught while testing: the same block of markup had been pasted into the
create-notebook dialog as well, where the state it referenced did not
exist — the dialog crashed on open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:22:46 +02:00

49 lines
1.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Runs the browser suites against a running InkNote.
#
# ./e2e/run.sh # all suites
# ./e2e/run.sh editor drawing # only these
#
# Needs the dev stack up (docker compose -f docker-compose.dev.yml up -d) and an
# admin account to create throwaway users with — marc/geheim123 by default,
# override with INKNOTE_ADMIN / INKNOTE_ADMIN_PASS.
set -uo pipefail
cd "$(dirname "$0")"
IMAGE="mcr.microsoft.com/playwright:v1.49.0-noble"
URL="${INKNOTE_URL:-http://localhost:3000}"
SUITES=("$@")
[ ${#SUITES[@]} -eq 0 ] && SUITES=(admin editor search-attachments history drawing export conflict pdf attachments-lifecycle)
mkdir -p shots
if [ ! -d node_modules ]; then
echo "→ installing playwright once"
docker run --rm -v "$PWD:/w" -w /w "$IMAGE" npm install --no-audit --no-fund >/dev/null
fi
if ! curl -sf -o /dev/null "$URL"; then
echo "✗ $URL is not answering — start the stack first:"
echo " docker compose -f docker-compose.dev.yml up -d --build"
exit 1
fi
failed=()
for s in "${SUITES[@]}"; do
echo
echo "═══ $s ═══"
docker run --rm --network host \
-v "$PWD:/w" -v "$PWD/shots:/out" -w /w \
-e INKNOTE_URL="$URL" \
-e INKNOTE_ADMIN="${INKNOTE_ADMIN:-marc}" \
-e INKNOTE_ADMIN_PASS="${INKNOTE_ADMIN_PASS:-geheim123}" \
"$IMAGE" node "$s.mjs" || failed+=("$s")
done
echo
if [ ${#failed[@]} -eq 0 ]; then
echo "═══ all suites passed ═══"
else
echo "═══ FAILED: ${failed[*]} ═══"
exit 1
fi