feat: studysets record when they last changed; the library lists them so

Decided 2026-10-01: after the starred ones, the library lists the most
recently changed studysets first. That needs a change date, so studyset
gains updatedAt (ADR 0004): when the studyset itself last changed, its
content, place, star or archive date, written by the device making the
change in the same update as the change; the last writer wins. Studysets
from before have none and come last, the newest of them first.

The branch's migration is still unreleased (not merged, not deployed), so it
is recreated rather than followed by a second one:
20261001064926911-tree-tags-assets replaces 20260930213716558 and differs
only by one line on the server, ALTER TABLE "studyset" ADD COLUMN
"updatedAt" timestamp without time zone (nullable, so existing rows keep
null and no data changes), the same column in the table devices rebuild,
and its version. The model's comment on the payload no longer lists schema
1's fields alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-01 08:51:33 +02:00
commit 85c028fe3c
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -29,6 +29,7 @@ class FakeStudysetGateway() implements StudysetGateway {
String position = 'a0',
DateTime? archivedAt,
DateTime? starredAt,
DateTime? updatedAt,
}) {
_rows[id] = (
id: id,
@ -37,6 +38,7 @@ class FakeStudysetGateway() implements StudysetGateway {
position: position,
archivedAt: archivedAt,
starredAt: starredAt,
updatedAt: updatedAt,
);
_remoteChanges.add(null);
}
@ -57,7 +59,7 @@ class FakeStudysetGateway() implements StudysetGateway {
}
@override
Future<String> insert(ByteData payload) async {
Future<String> insert(ByteData payload, DateTime updatedAt) async {
final id = 'studyset-${_nextId++}';
_rows[id] = (
id: id,
@ -66,13 +68,18 @@ class FakeStudysetGateway() implements StudysetGateway {
position: 'a0',
archivedAt: null,
starredAt: null,
updatedAt: updatedAt,
);
writes.add((id, payload));
return id;
}
@override
Future<void> updatePayload(String id, ByteData payload) async {
Future<void> updatePayload(
String id,
ByteData payload,
DateTime updatedAt,
) async {
if (_rows[id] case final row?) {
_rows[id] = (
id: id,
@ -81,13 +88,18 @@ class FakeStudysetGateway() implements StudysetGateway {
position: row.position,
archivedAt: row.archivedAt,
starredAt: row.starredAt,
updatedAt: updatedAt,
);
writes.add((id, payload));
}
}
@override
Future<void> updateStarredAt(String id, DateTime? starredAt) async {
Future<void> updateStarredAt(
String id,
DateTime? starredAt,
DateTime updatedAt,
) async {
if (_rows[id] case final row?) {
_rows[id] = (
id: id,
@ -96,12 +108,17 @@ class FakeStudysetGateway() implements StudysetGateway {
position: row.position,
archivedAt: row.archivedAt,
starredAt: starredAt,
updatedAt: updatedAt,
);
}
}
@override
Future<void> updateArchivedAt(String id, DateTime? archivedAt) async {
Future<void> updateArchivedAt(
String id,
DateTime? archivedAt,
DateTime updatedAt,
) async {
if (_rows[id] case final row?) {
_rows[id] = (
id: id,
@ -110,6 +127,7 @@ class FakeStudysetGateway() implements StudysetGateway {
position: row.position,
archivedAt: archivedAt,
starredAt: row.starredAt,
updatedAt: updatedAt,
);
}
}