It was a heading over some rows: a name, a colour, and whether it was folded.
Enough to tidy a list, and not enough to be what people mean by it — "Arbejde" is
a body of work with context of its own, and documents that belong to all of it
rather than to any one project inside it.
`/gruppe/{id}` carries three things a heading cannot. The projects in it, each
with what is still open — open tasks, not all of them, because "12" beside a
project somebody finished last year is a number that means nothing. A description,
written in place and saved on blur, the same shape a task's description has. And
the files that govern the whole group: the contract, the drawing, the agreement
everything else rests on.
The name in the sidebar is a link to it and the chevron beside it still folds.
Two intentions, two targets — the single one they used to share could only ever
serve the smaller.
Migration 0012 rebuilds `attachments`, because its CHECK spelled out exactly which
parent columns may be set and SQLite cannot alter a CHECK. The rule is still
"exactly one parent", counted rather than written out as pairwise comparisons:
with three columns that is three clauses, with four it is six, and the version
that is wrong looks exactly like the one that is right.
A group's file is reachable by its owner and nobody else. A group belongs to one
person and is never shared, so `reachAttachment` asks about ownership rather than
a project role — both old callers resolved straight to a task, so a group's
attachment answered 404 for the person who uploaded it.
Three tests also stopped racing their own navigation. Creating a project navigates
and `goto` is a promise nobody was holding, so a quick add fired straight after
could land in the Inbox instead — intermittent, and it read as the quick add
having failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
54 lines
2.6 KiB
SQL
54 lines
2.6 KiB
SQL
-- A group becomes somewhere you can go, rather than only a heading.
|
|
--
|
|
-- Until now a project group was a label over some rows in the sidebar: a name, a
|
|
-- colour, and whether it was folded. That is enough to tidy a list and not enough
|
|
-- to be the thing people actually mean by it — "Arbejde" is a body of work with
|
|
-- context of its own: what it is, and the documents that belong to all of it
|
|
-- rather than to any one project inside it.
|
|
--
|
|
-- Two changes. A description on the group, and attachments that can hang on one.
|
|
--
|
|
-- The attachments table has to be rebuilt for the second, because its CHECK spells
|
|
-- out exactly which parent columns may be set, and SQLite cannot alter a CHECK.
|
|
-- Foreign keys go off for the length of it — see the marker below and the note in
|
|
-- `applyMigration` — because dropping the old table with them on is a cascading
|
|
-- delete of every attachment in the instance.
|
|
--
|
|
-- The rule stays "exactly one parent": an attachment belongs to a task, a comment
|
|
-- or a group, never two. An attachment with two parents is one that gets deleted
|
|
-- once and stays visible in the other place.
|
|
--
|
|
-- verdande:rebuild-tables
|
|
|
|
ALTER TABLE project_groups ADD COLUMN description TEXT NOT NULL DEFAULT '';
|
|
|
|
CREATE TABLE attachments_rebuilt (
|
|
id TEXT PRIMARY KEY,
|
|
task_id TEXT REFERENCES tasks (id) ON DELETE CASCADE,
|
|
comment_id TEXT REFERENCES comments (id) ON DELETE CASCADE,
|
|
group_id TEXT REFERENCES project_groups (id) ON DELETE CASCADE,
|
|
filename TEXT NOT NULL,
|
|
mime_type TEXT NOT NULL DEFAULT 'application/octet-stream',
|
|
size INTEGER NOT NULL,
|
|
path TEXT NOT NULL,
|
|
uploaded_by TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
|
created_at INTEGER NOT NULL,
|
|
-- Exactly one parent, counted rather than spelled out as a chain of pairwise
|
|
-- comparisons: with three columns that is three clauses, with four it is six,
|
|
-- and the version that is wrong looks exactly like the version that is right.
|
|
CHECK ((task_id IS NOT NULL) + (comment_id IS NOT NULL) + (group_id IS NOT NULL) = 1)
|
|
);
|
|
|
|
INSERT INTO attachments_rebuilt
|
|
(id, task_id, comment_id, filename, mime_type, size, path, uploaded_by, created_at)
|
|
SELECT id, task_id, comment_id, filename, mime_type, size, path, uploaded_by, created_at
|
|
FROM attachments;
|
|
|
|
DROP TABLE attachments;
|
|
|
|
ALTER TABLE attachments_rebuilt RENAME TO attachments;
|
|
|
|
CREATE INDEX idx_attachments_task ON attachments (task_id) WHERE task_id IS NOT NULL;
|
|
CREATE INDEX idx_attachments_comment ON attachments (comment_id) WHERE comment_id IS NOT NULL;
|
|
CREATE INDEX idx_attachments_group ON attachments (group_id) WHERE group_id IS NOT NULL;
|