feat(todo): the person's tasks, sections and labels, sealed and synced (ADR 0033, D6)

A table's rows are sealed for their table and row by one SealedRows,
which the repositories of projects, sections, tasks and labels share,
each table with its own sync gateway, a deletion blanking its rows first
in one transaction. A task's payload holds its title, description,
project, section, parent, place, date (a day, an optional wall-clock
time and duration), deadline, priority, labels and when it was done;
deleting a task deletes its sub-tasks, and a project or a section goes
with its tasks. Rows that don't open show locked; a device without the
account's keys writes nothing.

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

View file

@ -4,12 +4,15 @@ import 'package:halkyon_app/testing.dart';
import 'package:halkyon_todo_flutter/src/app/todo_app.dart';
import 'package:halkyon_todo_flutter/src/app/todo_dependencies.dart';
import 'package:halkyon_todo_flutter/src/core/privacy/todo_keys.dart';
import 'package:halkyon_todo_flutter/src/feature/label/data/label_repository.dart';
import 'package:halkyon_todo_flutter/src/feature/project/data/project_repository.dart';
import 'package:halkyon_todo_flutter/src/feature/section/data/section_repository.dart';
import 'package:halkyon_todo_flutter/src/feature/task/data/task_repository.dart';
import 'package:halkyon_ui/halkyon_ui.dart';
import 'package:material_ui/material_ui.dart';
import '../support/memory_content_key_gateway.dart';
import '../support/memory_project_gateway.dart';
import '../support/memory_sealed_row_gateway.dart';
void main() {
final builtIn = Instance.parse('todo.example.org')!;
@ -17,8 +20,34 @@ void main() {
late FakeAuthGateway gateway;
late List<SignedIn> opened;
late MemorySignInAddresses addresses;
late TodoKeys keys;
late SyncService sync;
late MemorySealedRowGateway projectRows;
late MemorySealedRowGateway sectionRows;
late MemorySealedRowGateway taskRows;
late MemorySealedRowGateway labelRows;
tearDown(() async {
await sync.dispose();
keys.dispose();
});
setUp(() {
// The account's keys on this device, sealing with halkyon_app's fake
// cipher; each table's rows in memory.
keys = TodoKeys(
MemoryContentKeyGateway(),
FakeContentCipher(),
() async => FakeAccountCrypto().keysNumbered(1),
);
sync = SyncService(
({required onMerge}) async {},
debounce: const Duration(days: 1),
);
projectRows = MemorySealedRowGateway();
sectionRows = MemorySealedRowGateway();
taskRows = MemorySealedRowGateway();
labelRows = MemorySealedRowGateway();
store = MemoryInstanceStore();
gateway = FakeAuthGateway();
addresses = MemorySignInAddresses();
@ -91,25 +120,13 @@ void main() {
'https://code.halkyon.app/project-halkyon/halkyon',
openPerson: (person) async {
opened.add(person);
final keys = TodoKeys(
MemoryContentKeyGateway(),
SodiumContentCipher(),
() async => null,
);
final sync = SyncService(
({required onMerge}) async {},
debounce: const Duration(days: 1),
);
final projects = ProjectRepository(MemoryProjectGateway(), keys);
return TodoPerson(
person,
sync: sync,
projects: projects,
onDispose: () async {
await projects.dispose();
await sync.dispose();
keys.dispose();
},
projects: ProjectRepository(projectRows, keys),
sections: SectionRepository(sectionRows, keys),
tasks: TaskRepository(taskRows, keys),
labels: LabelRepository(labelRows, keys),
);
},
),