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
2 changed files with 1557 additions and 224 deletions

View file

@ -1,36 +0,0 @@
import 'dart:async';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_todo_flutter/src/feature/project/data/project_gateway.dart';
/// [ProjectGateway] in memory, whose rows a test changes as an instance could.
class MemoryProjectGateway() implements ProjectGateway {
final rows = <String, Envelope>{};
final _remote = StreamController<void>.broadcast();
/// As a sync bringing others' changes.
void bringRemoteChanges() => _remote.add(null);
@override
Future<List<ProjectRow>> projects() async => [
for (final MapEntry(:key, :value) in rows.entries)
(id: key, envelope: value),
];
@override
Future<void> insert(ProjectRow project) async =>
rows[project.id] = project.envelope;
@override
Future<void> update(String id, Envelope envelope) async {
if (rows.containsKey(id)) {
rows[id] = envelope;
}
}
@override
Future<void> delete(String id) async => rows.remove(id);
@override
Stream<void> get remoteChanges => _remote.stream;
}

View file

@ -0,0 +1,37 @@
import 'dart:async';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_todo_flutter/src/core/sealed/sealed_row_gateway.dart';
/// [SealedRowGateway] in memory, whose rows a test changes as an instance
/// could, and shares between "devices" as the sync engine would.
class MemorySealedRowGateway() implements SealedRowGateway {
/// The rows, as the instance holds them.
final byId = <String, Envelope>{};
final _remote = StreamController<void>.broadcast();
/// As a sync bringing others' changes.
void bringRemoteChanges() => _remote.add(null);
@override
Future<List<SealedRow>> rows() async => [
for (final MapEntry(:key, :value) in byId.entries)
(id: key, envelope: value),
];
@override
Future<void> insert(SealedRow row) async => byId[row.id] = row.envelope;
@override
Future<void> update(String id, Envelope envelope) async {
if (byId.containsKey(id)) {
byId[id] = envelope;
}
}
@override
Future<void> delete(Iterable<String> ids) async => ids.forEach(byId.remove);
@override
Stream<void> get remoteChanges => _remote.stream;
}