feat(goals): M4.c — goals adopt the unified visibility system

Fifth consumer of @mana/shared-privacy, completing the M4 trio
(Calendar + Todo + Goals). Goals live under $lib/companion/goals/
(legacy path, pre-rename to 'ai') instead of the standard /modules/
tree, so the adoption lands in its own commit.

Enables the "public progress page" use case — a fitness / learning /
build-in-public goal with its current-period progress inlined on the
owner's website, rendered as "4 / 5 · Woche".

Changes:
- companion/goals/types: visibility + unlistedToken +
  visibilityChangedAt + visibilityChangedBy on LocalGoal (LocalGoal
  doubles as the UI type here, no separate plaintext variant)
- companion/goals/store: createFromTemplate and create both stamp
  defaultVisibilityFor(activeSpace.type) at insert; new
  setVisibility(id, level) mints/clears the unlisted token on the
  transition boundary and emits cross-module VisibilityChanged
- modules/goals/ListView: <VisibilityPicker compact> on each active
  goal card, sitting between the title and the pause button (goals
  have no dedicated detail view — list-inline is the natural spot)

website embed:
- website-blocks/moduleEmbed/schema: 'goals.goals' added to
  EmbedSourceSchema; filter docstring describes the active-vs-
  completed split that power users can use to section their progress
  page
- website/embeds: resolveGoals gates hard on canEmbedOnWebsite,
  filters by optional status ('active' | 'completed' | 'paused' |
  'abandoned'), sorts active-first then by target descending so
  milestone goals land on top. Inlined EmbedItem is whitelist-only —
  title + compact progress line like "4 / 5 · Woche". Description,
  metric configuration (event types, filter fields), and internal
  tracking state stay out of the snapshot; the goal's implementation
  detail leaks what the user is measuring, not just the milestone

Verified:
- pnpm check (web): 7450 files, 0 errors
- pnpm test goals + website: 29/29
- pnpm run validate:all green

M4 is done. Next: M5 — Places + Events + Recipes + Habits + Quiz +
Wardrobe + Invoices-Clients. Same pattern, one module at a time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-24 02:41:27 +02:00
parent 015a2c18ee
commit 95e85bdffd
5 changed files with 105 additions and 0 deletions

View file

@ -31,6 +31,7 @@ export const EmbedSourceSchema = z.enum([
'library.entries',
'calendar.events',
'todo.tasks',
'goals.goals',
]);
export type EmbedSource = z.infer<typeof EmbedSourceSchema>;
@ -52,6 +53,9 @@ export const ModuleEmbedSchema = z.object({
* todo.tasks: { status?, tagIds? } typical public-roadmap
* shape: status='completed' filters to shipped
* items; tagIds restricts to a "public" label
* goals.goals: { status? } 'active' | 'completed' filter;
* useful for "currently working on" vs "things
* I've hit" progress sections
*/
filter: z
.object({