xarmian
1b1068537c
feat(tags): workspace tag enumeration endpoint + cross-collection filter (TASK-1653) ( #658 )
...
* feat(tags): workspace tag enumeration endpoint + cross-collection filter (TASK-1653)
Foundation for the tags feature (PLAN-1652 / IDEA-1649). The write path and
per-collection ?tag= filter already existed; this adds tag enumeration and a
verified cross-collection read so a single tag can group items of any type.
- store: dialect.JSONArrayElements unnests a JSON text-array column
(json_each on SQLite, jsonb_array_elements_text on Postgres);
Store.ListWorkspaceTags returns distinct tags + item counts, ordered by
count desc then tag asc, with the same collection/item ACL filters as
ListItems so counts never leak hidden items.
- server: GET /workspaces/{ws}/tags (handleListTags), respecting collection
visibility + guest item grants.
- models: TagCount{tag,count}.
- cli: client.ListTags + `pad tag list`.
- web: api.tags.list + TagCount type (items.list already forwards `tag`).
- tests: store-level (cross-collection aggregation, collection scoping,
non-nil-empty = empty, archived excluded) and handler-level (a Task + an
Idea sharing one tag; GET /tags counts + ordering).
Parent: PLAN-1652.
* fix(tags): count distinct items per tag, not tag occurrences per Codex review (round 1)
COUNT(DISTINCT i.id) so an item with duplicate tags (e.g. ["ux","ux"]) is
counted once — the write path doesn't enforce per-item tag uniqueness.
Adds a regression test.
2026-05-29 23:43:02 -04:00
..
2026-04-29 15:41:12 -04:00
2026-05-06 08:40:11 -04:00
2026-05-06 13:27:12 -04:00
2026-05-18 00:43:46 -04:00
2026-05-18 00:43:46 -04:00
2026-04-28 12:26:39 -04:00
2026-05-02 22:56:10 -04:00
2026-04-25 11:35:19 -04:00
2026-04-25 11:35:19 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-05-27 10:09:30 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 16:21:43 -04:00
2026-04-29 17:56:19 -04:00
2026-05-20 18:10:25 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-29 15:41:12 -04:00
2026-04-29 14:35:49 -04:00
2026-04-29 14:35:49 -04:00
2026-04-29 19:25:55 -04:00
2026-04-29 15:02:07 -04:00
2026-04-29 19:25:55 -04:00
2026-05-20 16:39:23 -04:00
2026-04-28 12:26:39 -04:00
2026-05-06 13:27:12 -04:00
2026-05-06 08:40:11 -04:00
2026-04-21 19:33:47 -04:00
2026-04-21 20:52:03 -04:00
2026-04-22 12:21:34 -04:00
2026-05-25 13:18:43 -04:00
2026-05-25 13:18:43 -04:00
2026-05-27 10:37:30 -04:00
2026-05-27 10:37:30 -04:00
2026-05-21 13:08:02 -04:00
2026-05-21 13:08:02 -04:00
2026-04-29 14:35:49 -04:00
2026-04-25 11:53:31 -04:00
2026-05-18 15:25:27 -04:00
2026-05-18 10:25:08 -04:00
2026-04-22 09:27:45 -04:00
2026-04-22 09:27:45 -04:00
2026-05-25 11:46:41 -04:00
2026-05-09 21:45:46 -04:00
2026-05-27 10:09:30 -04:00
2026-05-16 10:15:59 -04:00
2026-05-20 16:39:23 -04:00
2026-05-18 08:33:39 -04:00
2026-05-18 03:32:42 -04:00
2026-05-18 08:33:39 -04:00
2026-05-21 13:08:02 -04:00
2026-05-17 13:40:15 -04:00
2026-05-19 13:17:57 -04:00
2026-05-14 22:10:12 -04:00
2026-05-20 16:39:23 -04:00
2026-04-28 12:26:39 -04:00
2026-05-18 18:29:28 -04:00
2026-05-27 10:09:30 -04:00
2026-04-29 18:30:43 -04:00
2026-04-29 18:30:43 -04:00
2026-05-24 16:12:38 -04:00
2026-04-29 22:03:27 -04:00
2026-04-29 20:24:25 -04:00
2026-05-15 00:36:41 -04:00
2026-05-15 00:36:41 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-05-11 20:29:50 -04:00
2026-05-09 21:45:46 -04:00
2026-05-16 10:15:59 -04:00
2026-05-27 13:21:57 -04:00
2026-05-17 00:15:52 -04:00
2026-05-11 13:42:11 -04:00
2026-05-29 23:43:02 -04:00
2026-05-21 16:59:57 -04:00
2026-05-21 16:59:57 -04:00
2026-05-02 22:56:10 -04:00
2026-05-02 22:56:10 -04:00
2026-05-14 15:45:51 -04:00
2026-05-03 17:40:18 -04:00
2026-05-05 08:52:05 -04:00
2026-05-05 08:52:05 -04:00
2026-04-28 16:21:43 -04:00
2026-05-18 00:43:46 -04:00
2026-05-18 00:43:46 -04:00
2026-05-02 13:33:53 -04:00
2026-05-18 17:17:42 -04:00
2026-05-18 07:51:12 -04:00
2026-05-21 13:08:02 -04:00
2026-05-12 18:29:11 -04:00
2026-05-12 18:29:11 -04:00
2026-04-28 12:26:39 -04:00
2026-05-16 18:20:17 -04:00
2026-05-16 18:20:17 -04:00
2026-05-29 08:24:05 -04:00
2026-05-29 17:47:25 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 16:21:43 -04:00
2026-05-02 21:31:48 -04:00
2026-05-02 21:31:48 -04:00
2026-04-29 17:44:12 -04:00
2026-04-30 16:06:08 -04:00
2026-05-29 23:43:02 -04:00
2026-05-03 00:12:50 -04:00
2026-04-28 12:26:39 -04:00
2026-04-21 22:53:27 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-05-16 10:15:59 -04:00
2026-05-16 10:15:59 -04:00
2026-04-28 12:26:39 -04:00
2026-05-02 18:36:55 -04:00
2026-05-25 11:46:41 -04:00
2026-05-03 00:35:31 -04:00
2026-05-18 00:43:46 -04:00
2026-04-28 12:26:39 -04:00
2026-05-12 10:01:14 -04:00
2026-04-28 16:21:43 -04:00
2026-05-27 10:09:30 -04:00
2026-05-07 20:01:34 -04:00
2026-05-27 10:09:30 -04:00
2026-04-22 12:21:34 -04:00
2026-05-01 11:51:28 -04:00
2026-05-06 08:40:11 -04:00
2026-05-06 08:40:11 -04:00
2026-05-14 15:45:51 -04:00
2026-05-03 17:40:18 -04:00
2026-05-18 00:03:20 -04:00
2026-05-18 00:03:20 -04:00
2026-05-03 17:40:18 -04:00
2026-05-03 17:40:18 -04:00
2026-05-03 17:40:18 -04:00
2026-04-28 12:26:39 -04:00
2026-04-28 12:26:39 -04:00
2026-04-05 10:26:00 -04:00
2026-05-14 15:45:51 -04:00
2026-04-25 11:35:19 -04:00
2026-04-21 19:33:47 -04:00
2026-04-25 11:35:19 -04:00
2026-04-21 23:59:54 -04:00
2026-04-28 12:26:39 -04:00
2026-05-09 18:19:33 -04:00
2026-05-09 18:19:33 -04:00
2026-04-29 19:25:55 -04:00
2026-04-29 19:25:55 -04:00
2026-04-22 12:21:34 -04:00
2026-04-22 12:21:34 -04:00
2026-04-28 17:20:03 -04:00
2026-05-29 23:43:02 -04:00
2026-05-09 07:13:10 -04:00
2026-04-29 14:35:49 -04:00
2026-04-29 14:35:49 -04:00
2026-05-02 13:33:53 -04:00
2026-05-02 14:29:17 -04:00
2026-04-08 20:30:39 +00:00
2026-04-10 23:12:59 +00:00