@hybridlabor-api/aos 4.13.2 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.agents/AGENTS.md +8 -0
  2. package/.agents/nodes.json +5 -2
  3. package/.claude/hooks/conventional-commits.mjs +14 -15
  4. package/.claude/hooks/env-file-protection.mjs +14 -15
  5. package/.claude/hooks/go-gate.mjs +152 -10
  6. package/.claude/hooks/go-token.mjs +55 -0
  7. package/.claude/hooks/memb-inject.mjs +75 -62
  8. package/.claude/hooks/trail-autostart.mjs +27 -0
  9. package/.claude/settings.json +18 -0
  10. package/.claude/workflows/startcycle-dispatch.mjs +11 -4
  11. package/.opencode/plugins/bdb-aos.js +98 -121
  12. package/.opencode/plugins/lib/trail-autostart.js +38 -0
  13. package/CLAUDE.md +1 -1
  14. package/README.de.md +6 -6
  15. package/README.md +6 -6
  16. package/README.pt.md +6 -6
  17. package/THIRD_PARTY_NOTICES.md +19 -3
  18. package/assets/header-v5.png +0 -0
  19. package/bin/aos-acp.mjs +211 -0
  20. package/bin/aos-doctor.mjs +1 -1
  21. package/bin/aos-uninstall.mjs +2 -2
  22. package/docs/master-session-acp.md +51 -0
  23. package/installer.js +252 -35
  24. package/mcps/mcsc/packages/mcp/server.js +6 -7
  25. package/package.json +4 -3
  26. package/scripts/validate-skills.mjs +76 -0
  27. package/skills/basic/bdbmediastorm/SKILL.md +1 -1
  28. package/skills/basic/godmode-shipping/SKILL.md +3 -0
  29. package/skills/basic/master-session/SKILL.md +89 -0
  30. package/skills/basic/startcycle/SKILL.md +1 -1
  31. package/skills/basic/startcycle-graph/SKILL.md +2 -2
  32. package/skills/basic/startcycle-graph-user/SKILL.md +1 -1
  33. package/skills/basic/teamwork-preview/SKILL.md +1 -1
  34. package/skills/bdbrainstorm/SKILL.md +7 -1
  35. package/skills/global_config/agentic-harness-patterns/SKILL.md +257 -0
  36. package/skills/global_config/agentic-harness-patterns/metadata.json +10 -0
  37. package/skills/global_config/agentic-harness-patterns/references/agent-orchestration-pattern.md +97 -0
  38. package/skills/global_config/agentic-harness-patterns/references/bootstrap-sequence-pattern.md +106 -0
  39. package/skills/global_config/agentic-harness-patterns/references/context-engineering/compress-pattern.md +78 -0
  40. package/skills/global_config/agentic-harness-patterns/references/context-engineering/isolate-pattern.md +82 -0
  41. package/skills/global_config/agentic-harness-patterns/references/context-engineering/select-pattern.md +86 -0
  42. package/skills/global_config/agentic-harness-patterns/references/context-engineering-pattern.md +29 -0
  43. package/skills/global_config/agentic-harness-patterns/references/hook-lifecycle-pattern.md +111 -0
  44. package/skills/global_config/agentic-harness-patterns/references/memory-persistence-pattern.md +109 -0
  45. package/skills/global_config/agentic-harness-patterns/references/permission-gate-pattern.md +111 -0
  46. package/skills/global_config/agentic-harness-patterns/references/skill-runtime-pattern.md +104 -0
  47. package/skills/global_config/agentic-harness-patterns/references/task-decomposition-pattern.md +92 -0
  48. package/skills/global_config/agentic-harness-patterns/references/tool-registry-pattern.md +101 -0
  49. package/skills/global_config/agenttrail/SKILL.md +8 -0
  50. package/skills/global_config/agenttrail/bin/agenttrail.mjs +14 -0
  51. package/skills/global_config/agenttrail/bin/ensure.mjs +118 -0
  52. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
  53. package/skills/global_config/bdb-visual-edit/SKILL.md +51 -0
  54. package/skills/global_config/bdb-visual-edit/references/vite-react-source-attr.md +59 -0
  55. package/skills/global_config/bdb-visual-edit/scripts/pick-snippet.js +27 -0
  56. package/skills/global_config/bdb-visual-edit/scripts/sanitize-element.mjs +123 -0
  57. package/skills/global_config/factory-collect/SKILL.md +74 -0
  58. package/skills/global_config/factory-human-digest/SKILL.md +92 -0
  59. package/skills/global_config/factory-lookback/SKILL.md +95 -0
  60. package/skills/global_config/factory-review-prs/SKILL.md +63 -0
  61. package/skills/global_config/git-pr-review/SKILL.md +3 -0
  62. package/skills/global_config/grilling/SKILL.md +2 -0
  63. package/skills/global_config/mcsc/SKILL.md +1 -1
  64. package/skills/global_config/plan-arbiter/SKILL.md +125 -0
  65. package/skills/global_config/plan-canvas/SKILL.md +62 -5
  66. package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +19 -3
  67. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/README.md +285 -0
  68. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/agent-trail.js +129 -0
  69. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/board-client.js +124 -0
  70. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/canvas.mdx +19 -0
  71. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/plan.mdx +18 -0
  72. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/recap-demo/plan.mdx +72 -0
  73. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/README.md +29 -0
  74. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/architecture.json +30 -0
  75. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/00_architecture.html +14950 -0
  76. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/canvas.mdx +511 -0
  77. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/plan.mdx +208 -0
  78. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/recap/plan.mdx +102 -0
  79. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/standard/plan.md +136 -0
  80. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/canvas.mdx +124 -0
  81. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/plan.mdx +37 -0
  82. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/index.js +188 -0
  83. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/kit.js +123 -0
  84. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/mdx.js +411 -0
  85. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/render.js +1291 -0
  86. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/meta.json +1 -0
  87. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/plan.mdx +195 -0
  88. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/standard.md +95 -0
  89. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/meta.json +1 -0
  90. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/plan.mdx +105 -0
  91. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/standard.md +76 -0
  92. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/canvas.mdx +81 -0
  93. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/meta.json +1 -0
  94. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/plan.mdx +145 -0
  95. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/standard.md +76 -0
  96. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/meta.json +1 -0
  97. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/plan.mdx +172 -0
  98. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/standard.md +100 -0
  99. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/meta.json +1 -0
  100. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/plan.mdx +67 -0
  101. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/standard.md +49 -0
  102. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/canvas.mdx +63 -0
  103. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/meta.json +1 -0
  104. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/plan.mdx +49 -0
  105. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/standard.md +39 -0
  106. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/meta.json +1 -0
  107. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/plan.mdx +118 -0
  108. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/standard.md +57 -0
  109. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/meta.json +1 -0
  110. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/plan.mdx +173 -0
  111. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/standard.md +96 -0
  112. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/meta.json +1 -0
  113. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/plan.mdx +91 -0
  114. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/standard.md +54 -0
  115. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/canvas.mdx +53 -0
  116. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/meta.json +1 -0
  117. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/plan.mdx +225 -0
  118. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/standard.md +111 -0
  119. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/theme.css +472 -0
  120. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/trail.js +216 -0
  121. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +1 -1
  122. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +37 -4
  123. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +125 -29
  124. package/skills/global_config/plan-canvas/scripts/plan-canvas.js +196 -8
  125. package/skills/global_config/pr-recap/SKILL.md +47 -0
  126. package/skills/global_config/pr-recap/scripts/pr-recap.mjs +200 -0
  127. package/skills/global_config/quick-recap/SKILL.md +55 -0
  128. package/skills/global_config/stay-within-limits/SKILL.md +85 -0
  129. package/skills/global_config/triage/SKILL.md +3 -0
  130. package/skills/global_config/visual-edit/README.md +96 -0
  131. package/skills/global_config/visual-edit/SKILL.md +615 -0
  132. package/skills/global_config/visual-plan/README.md +93 -0
  133. package/skills/global_config/visual-plan/SKILL.md +544 -0
  134. package/skills/global_config/visual-plan/references/canvas.md +139 -0
  135. package/skills/global_config/visual-plan/references/connection.md +51 -0
  136. package/skills/global_config/visual-plan/references/document-quality.md +186 -0
  137. package/skills/global_config/visual-plan/references/exemplar.md +62 -0
  138. package/skills/global_config/visual-plan/references/local-files.md +99 -0
  139. package/skills/global_config/visual-plan/references/wireframe.md +319 -0
  140. package/skills/global_config/visual-recap/README.md +103 -0
  141. package/skills/global_config/visual-recap/SKILL.md +560 -0
  142. package/skills/global_config/visual-recap/references/connection.md +51 -0
  143. package/skills/global_config/visual-recap/references/local-files.md +99 -0
  144. package/skills/global_config/visual-recap/references/wireframe.md +319 -0
  145. package/skills/playbooks/pb-ci-fix/SKILL.md +49 -0
  146. package/skills/playbooks/pb-event-tracker/SKILL.md +45 -0
  147. package/skills/playbooks/pb-meeting-actions/SKILL.md +42 -0
  148. package/skills/playbooks/pb-project-new/SKILL.md +48 -0
  149. package/skills/playbooks/pb-week-plan/SKILL.md +45 -0
  150. package/assets/header-v4.jpg +0 -0
@@ -0,0 +1,208 @@
1
+ ---
2
+ title: Harbor Notes - Team Notes MVP
3
+ status: draft
4
+ needs-auth: foundations
5
+ needs-notes-api: foundations, auth
6
+ needs-editor: notes-api
7
+ needs-sharing: notes-api, auth
8
+ needs-settings: auth, notes-api
9
+ needs-export: notes-api, sharing
10
+ needs-launch: editor, sharing, settings, export
11
+ ---
12
+
13
+ # Harbor Notes: Team Notes MVP
14
+
15
+ ## Goal
16
+
17
+ Harbor Notes is a team notes app. A small team signs up, creates a workspace, writes notes together and shares a read-only link with someone outside the team. The first private beta ships in six weeks. All names and data in this plan are invented.
18
+
19
+ - A new user reaches a working workspace in under two minutes.
20
+ - Two teammates edit the same note without losing text.
21
+ - A shared link works without an account and can be revoked at any time.
22
+
23
+ ## Decision
24
+
25
+ <Decision title="How do users verify their email?" question="Which proof do we ask for after the signup form?" options={[
26
+ { id: "code", label: "Six digit code", detail: "Survives a device switch, which is the common failure for links.", recommended: true },
27
+ { id: "link", label: "Magic link", detail: "One tap, but breaks when the link opens in a different browser." },
28
+ { id: "none", label: "No verification in the beta", detail: "Fastest, but invites cannot be trusted and bounces go unnoticed." },
29
+ ]}>
30
+
31
+ A code works on the phone and the laptop alike, and costs one extra input box. We can add magic links later without changing the data model.
32
+
33
+ </Decision>
34
+
35
+ ## Architecture
36
+
37
+ <Archify src="00_architecture.html" label="Harbor Notes system" height={600} />
38
+
39
+ <Callout tone="note" title="Why a queue and a worker">
40
+
41
+ Exports and invitation emails can take seconds. Running them off the request path keeps the editor responsive and lets us retry a failed job without the user waiting.
42
+
43
+ </Callout>
44
+
45
+ ## Acceptance {#acceptance}
46
+
47
+ <Checklist title="Done when" items={[
48
+ { label: "Signup to an empty dashboard takes six screens or fewer", checked: true },
49
+ { label: "Back from any signup step keeps the typed values" },
50
+ { label: "Autosave survives a reload while typing" },
51
+ { label: "A revoked share link shows the Gone page within one minute" },
52
+ { label: "A viewer cannot edit, invite or delete" },
53
+ { label: "Notes list loads in under one second for 2,000 notes" },
54
+ ]} />
55
+
56
+ ## Build map
57
+
58
+ ### Foundations {#foundations}
59
+
60
+ Repository, CI, design tokens and the database schema.
61
+
62
+ <Checklist title="Foundations tasks" items={[
63
+ { label: "Repository, CI and deploy previews", checked: true },
64
+ { label: "Design tokens and base components", checked: true },
65
+ { label: "Schema for users, workspaces, notes and share links" },
66
+ ]} />
67
+
68
+ <ImplementationMap files={[
69
+ { path: "db/schema.sql", change: "added", note: "Users, workspaces, notes, members, share_links" },
70
+ { path: "ui/tokens.css", change: "added", note: "Colour, spacing and type tokens" },
71
+ { path: ".github/workflows/ci.yml", change: "added", note: "Lint, test, preview deploy" },
72
+ ]} />
73
+
74
+ ### Auth and invites {#auth}
75
+
76
+ Sessions, six digit codes and invite tokens.
77
+
78
+ <Checklist title="Auth tasks" items={[
79
+ { label: "Create account and send the code" },
80
+ { label: "Verify the code, expire after ten minutes" },
81
+ { label: "Session cookies with rotation" },
82
+ { label: "Invite tokens with a role" },
83
+ ]} />
84
+
85
+ <ImplementationMap files={[
86
+ { path: "api/auth/signup.ts", change: "added", note: "Create user and send code" },
87
+ { path: "api/auth/verify.ts", change: "added", note: "Check code, start session" },
88
+ { path: "api/auth/session.ts", change: "added", note: "Cookie rotation and logout" },
89
+ { path: "app/signup/verify.tsx", change: "added", note: "Six code boxes with paste handling" },
90
+ ]} />
91
+
92
+ ### Notes API {#notes-api}
93
+
94
+ Create, read, update, archive and search notes.
95
+
96
+ <Checklist title="Notes API tasks" items={[
97
+ { label: "CRUD endpoints with revision check" },
98
+ { label: "Search by title, body and tag" },
99
+ { label: "Attachment upload with a 10 MB limit" },
100
+ ]} />
101
+
102
+ <ImplementationMap files={[
103
+ { path: "api/notes/index.ts", change: "added", note: "List, create and search" },
104
+ { path: "api/notes/item.ts", change: "added", note: "Read, update, archive with revision check" },
105
+ { path: "api/files/upload.ts", change: "added", note: "Signed upload to object storage" },
106
+ ]} />
107
+
108
+ ### Editor and notes list {#editor}
109
+
110
+ The editor with autosave and the list with tag filter.
111
+
112
+ <Checklist title="Editor tasks" items={[
113
+ { label: "Markdown editor with toolbar" },
114
+ { label: "Autosave every two seconds" },
115
+ { label: "Title lock while someone edits" },
116
+ { label: "Notes list with tags and sort" },
117
+ ]} />
118
+
119
+ <ImplementationMap files={[
120
+ { path: "app/notes/list.tsx", change: "added", note: "List, filter and preview pane" },
121
+ { path: "app/notes/editor.tsx", change: "added", note: "Toolbar, autosave and presence" },
122
+ { path: "app/notes/use-autosave.ts", change: "added", note: "Debounced save with revision" },
123
+ ]} />
124
+
125
+ ### Sharing {#sharing}
126
+
127
+ Read-only links with an expiry date, and member roles.
128
+
129
+ <Checklist title="Sharing tasks" items={[
130
+ { label: "Create and revoke share links" },
131
+ { label: "Gone page for expired or revoked links" },
132
+ { label: "Roles: owner, editor, viewer" },
133
+ ]} />
134
+
135
+ <ImplementationMap files={[
136
+ { path: "api/share/index.ts", change: "added", note: "Create, list and revoke links" },
137
+ { path: "app/s/shared-note.tsx", change: "added", note: "Public read-only page" },
138
+ { path: "app/notes/share-dialog.tsx", change: "added", note: "Expiry options and people list" },
139
+ ]} />
140
+
141
+ ### Workspace settings {#settings}
142
+
143
+ General settings, members and the danger zone.
144
+
145
+ <Checklist title="Settings tasks" items={[
146
+ { label: "General tab with name and defaults" },
147
+ { label: "Members tab with invites" },
148
+ { label: "Danger zone with typed confirmation" },
149
+ ]} />
150
+
151
+ <ImplementationMap files={[
152
+ { path: "app/settings/index.tsx", change: "added", note: "Tabs and forms" },
153
+ { path: "app/settings/members.tsx", change: "added", note: "Member list and invite dialog" },
154
+ ]} />
155
+
156
+ ### Export {#export}
157
+
158
+ A workspace as a ZIP of Markdown files, built by the worker.
159
+
160
+ <Checklist title="Export tasks" items={[
161
+ { label: "Queue the export job" },
162
+ { label: "Worker writes the ZIP to storage" },
163
+ { label: "Email a download link that expires in a day" },
164
+ ]} />
165
+
166
+ <ImplementationMap files={[
167
+ { path: "worker/jobs/export.ts", change: "added", note: "Collect notes and write the ZIP" },
168
+ { path: "worker/jobs/email.ts", change: "added", note: "Send the download link" },
169
+ { path: "api/export.ts", change: "added", note: "Enqueue and report status" },
170
+ ]} />
171
+
172
+ ### Launch {#launch}
173
+
174
+ <Checklist title="Launch tasks" items={[
175
+ { label: "Load test with 2,000 notes and 20 editors" },
176
+ { label: "Accessibility pass: keyboard and contrast" },
177
+ { label: "Private beta with five invited teams" },
178
+ ]} />
179
+
180
+ <ImplementationMap files={[
181
+ { path: "tests/load/notes.k6.js", change: "added", note: "Load script for the notes list and saves" },
182
+ { path: "docs/beta-checklist.md", change: "added", note: "Go or no-go list" },
183
+ ]} />
184
+
185
+ ## Agent trail
186
+
187
+ <AgentTrail live="http://localhost:5331" />
188
+
189
+ ## Risks
190
+
191
+ <Table title="Risk register" columns={["Risk", "Likelihood", "Impact", "Mitigation"]} rows={[
192
+ ["Concurrent edits overwrite text", "Medium", "High", "Title lock, revision check, conflict banner"],
193
+ ["Share links leak in forwarded mail", "Medium", "Medium", "Expiry by default, one click revoke"],
194
+ ["Email deliverability is poor", "Medium", "High", "Dedicated sending domain, resend limit"],
195
+ ["Export jobs pile up", "Low", "Medium", "Queue depth alert, per workspace rate limit"],
196
+ ["Scope grows before the beta", "High", "Medium", "Freeze this list after week two"],
197
+ ]} />
198
+
199
+ ## Open questions
200
+
201
+ <QuestionForm title="Open Questions" questions={[
202
+ { title: "Can viewers download attachments from a shared note?", mode: "single", options: [
203
+ { label: "No, view only", recommended: true }, { label: "Yes, if the owner allows it" } ] },
204
+ { title: "Default expiry for share links?", mode: "single", options: [
205
+ { label: "7 days", recommended: true }, { label: "30 days" }, { label: "Never" } ] },
206
+ { title: "Which beta extras do we want?", mode: "multi", options: [
207
+ { label: "Audit log of link opens" }, { label: "Dark mode" }, { label: "Keyboard shortcuts sheet" } ] },
208
+ ]} />
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: Share links with expiry and revoke
3
+ subtitle: Notes can be shared through a read-only link that expires after seven days and can be revoked in one click. Invented example.
4
+ kind: recap
5
+ pr: "#318"
6
+ branch: feat/share-links
7
+ base: main
8
+ commit: 9b3e7d2
9
+ files: 8
10
+ additions: 642
11
+ deletions: 57
12
+ author: sample-author
13
+ date: 2026-02-03
14
+ ---
15
+
16
+ ## Summary
17
+
18
+ Until now a note could only be read by workspace members. This change adds read-only share links for people outside the team. A link carries a random token, expires after seven days unless the owner picks another period, and can be revoked at any time. Recipients see a clean read-only page; expired or revoked links show a Gone page instead of an error.
19
+
20
+ - Tokens are 128 bit random values stored hashed; the plain token only appears in the URL.
21
+ - The public page never loads the editor bundle, so it opens fast on slow connections.
22
+ - Owners see who opened a link and how often, without personal data.
23
+
24
+ ## Before and after
25
+
26
+ <Compare>
27
+ <Before>
28
+ <Screen surface="web" caption="Share dialog before: members only">
29
+ <FrameScreen>
30
+ <Row><Title text="Share note" /><Btn label="Close" /></Row>
31
+ <Chips items={[{ label: "People", active: true }]} />
32
+ <Row><IconSquare active /><Lines n={2} widths={[60, 36]} /></Row>
33
+ <Row><IconSquare /><Lines n={2} widths={[54, 30]} /></Row>
34
+ <Row><IconSquare /><Lines n={2} widths={[66, 34]} /></Row>
35
+ <Box dashed><Text value="Only workspace members can open this note." tone="muted" /></Box>
36
+ <Divider />
37
+ <Row><Btn label="Invite member" primary /></Row>
38
+ </FrameScreen>
39
+ </Screen>
40
+ </Before>
41
+ <After>
42
+ <Screen surface="web" caption="Share dialog after: link tab with expiry">
43
+ <FrameScreen>
44
+ <Row><Title text="Share note" /><Btn label="Close" /></Row>
45
+ <Chips items={[{ label: "Link", active: true }, { label: "People" }]} />
46
+ <Box><Text value="Anyone with the link can view" /><Lines n={1} widths={[72]} /></Box>
47
+ <SectionLabel label="Link expires" />
48
+ <TaskRow title="In 7 days" done note="default" />
49
+ <TaskRow title="In 30 days" />
50
+ <TaskRow title="Never" />
51
+ <Row><IconSquare active /><Lines n={2} widths={[60, 36]} /></Row>
52
+ <Divider />
53
+ <Row><Btn label="Revoke link" /><Btn label="Copy link" primary /></Row>
54
+ </FrameScreen>
55
+ </Screen>
56
+ </After>
57
+ </Compare>
58
+
59
+ ## Files
60
+
61
+ <ImplementationMap title="Changed files" files={[
62
+ { path: "db/migrations/0012_share_links.sql", change: "added", note: "share_links table with hashed token and expiry" },
63
+ { path: "api/share/index.ts", change: "added", note: "Create, list and revoke links" },
64
+ { path: "api/share/resolve.ts", change: "added", note: "Public lookup, returns note or Gone" },
65
+ { path: "app/s/shared-note.tsx", change: "added", note: "Read-only page without the editor bundle" },
66
+ { path: "app/notes/share-dialog.tsx", change: "modified", note: "Link tab, expiry options, revoke" },
67
+ { path: "api/notes/item.ts", change: "modified", note: "Expose share count on the note" },
68
+ { path: "app/notes/legacy-share-modal.tsx", change: "removed", note: "Replaced by the new dialog" },
69
+ { path: "tests/share-links.test.ts", change: "added", note: "Expiry, revoke and permission cases" },
70
+ ]} />
71
+
72
+ ## Behaviour
73
+
74
+ <Table title="Link states" columns={["State", "Recipient sees", "Owner sees", "Next step"]} rows={[
75
+ ["Active", "Read-only note", "Open count", "Revoke or wait for expiry"],
76
+ ["Expired", "Gone page", "Expired badge", "Create a new link"],
77
+ ["Revoked", "Gone page within one minute", "Revoked badge", "Create a new link"],
78
+ ["Note archived", "Gone page", "Link paused", "Restore the note to resume"],
79
+ ]} />
80
+
81
+ <CodeTabs tabs={[
82
+ { label: "share/index.ts", language: "ts", code: "export async function createLink(noteId: string, days = 7) {\n const token = randomToken(16);\n await db.insert('share_links', {\n note_id: noteId,\n token_hash: sha256(token),\n expires_at: addDays(now(), days),\n });\n return `${BASE_URL}/s/${token}`;\n}" },
83
+ { label: "share/resolve.ts", language: "ts", code: "export async function resolve(token: string) {\n const link = await db.findOne('share_links', { token_hash: sha256(token) });\n if (!link || link.revoked_at || link.expires_at < now()) return null;\n return db.get('notes', link.note_id);\n}" },
84
+ { label: "0012_share_links.sql", language: "sql", code: "CREATE TABLE share_links (\n id BIGSERIAL PRIMARY KEY,\n note_id BIGINT NOT NULL REFERENCES notes(id),\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n revoked_at TIMESTAMPTZ\n);" },
85
+ ]} />
86
+
87
+ ## Decision
88
+
89
+ <Decision title="Token storage" question="How do we store share tokens?" options={[
90
+ { id: "hash", label: "Store only a hash", detail: "A database leak does not expose working links.", recommended: true },
91
+ { id: "plain", label: "Store the token", detail: "Lets us show the link again, but a leak exposes every link." },
92
+ ]}>
93
+
94
+ The dialog shows the full link once. After that only the owner can revoke it and create a new one, which is an acceptable cost for the safer default.
95
+
96
+ </Decision>
97
+
98
+ <Callout tone="note" title="Review focus">
99
+
100
+ Check that revoke is visible to the public resolver within one minute, and that an archived note never leaks through an active link.
101
+
102
+ </Callout>
@@ -0,0 +1,136 @@
1
+ # Harbor Notes: Team Notes MVP
2
+
3
+ > Invented example project. Every name, number and date is made up.
4
+
5
+ **Status:** draft for review **Owner:** product team **Target:** first private beta in six weeks
6
+
7
+ ## 1. Goal
8
+
9
+ Harbor Notes is a team notes app. A small team signs up, creates a workspace, writes notes together and shares a read-only link with someone outside the team.
10
+
11
+ **Success looks like**
12
+
13
+ - A new user reaches a working workspace in under two minutes.
14
+ - Two teammates can edit the same note without losing text.
15
+ - A shared link works without an account and can be revoked at any time.
16
+ - Notes list loads in under one second for 2,000 notes.
17
+
18
+ **Out of scope for the beta:** comments, version history, native mobile apps, offline editing.
19
+
20
+ ## 2. Decisions
21
+
22
+ | # | Question | Options | Recommendation | Why |
23
+ |---|----------|---------|----------------|-----|
24
+ | D1 | How do users verify their email? | Six digit code / magic link | **Six digit code** | Survives a device switch, the common failure for links |
25
+ | D2 | How are notes stored? | Markdown text / block JSON | **Markdown text** | Simple export, easy diffs, no migration lock-in |
26
+ | D3 | How do edits merge? | Last write wins / CRDT | **Last write wins per note, field locks on title** | Cheapest option that avoids lost text for small teams |
27
+ | D4 | How are files stored? | Database blobs / object storage | **Object storage** | Keeps the database small and backups fast |
28
+ | D5 | How do jobs run? | In request / queue and worker | **Queue and worker** | Exports and emails must not block the editor |
29
+
30
+ ## 3. Scope and build order
31
+
32
+ ### 3.1 Foundations
33
+
34
+ - [x] Repository, CI and a deploy preview per branch
35
+ - [x] Design tokens and the base component set
36
+ - [ ] Database schema for users, workspaces, notes and share links
37
+ - [ ] Auth service with sessions and invite tokens
38
+
39
+ ### 3.2 Notes core
40
+
41
+ - [ ] Notes API: create, read, update, archive, search
42
+ - [ ] Editor with autosave every two seconds
43
+ - [ ] Notes list with tag filter and sort by last edit
44
+ - [ ] Attachment upload with a 10 MB limit
45
+
46
+ ### 3.3 Sharing and settings
47
+
48
+ - [ ] Read-only share links with an expiry date
49
+ - [ ] Member invites by email with roles: owner, editor, viewer
50
+ - [ ] Workspace settings: name, members, danger zone
51
+ - [ ] Export a workspace as a ZIP of Markdown files
52
+
53
+ ### 3.4 Launch
54
+
55
+ - [ ] Load test with 2,000 notes and 20 concurrent editors
56
+ - [ ] Accessibility pass: keyboard navigation and contrast
57
+ - [ ] Private beta with five invited teams
58
+
59
+ ## 4. Request flow
60
+
61
+ ```mermaid
62
+ flowchart LR
63
+ U[User] --> W[Web app]
64
+ W --> A[API]
65
+ A --> AU{Session valid?}
66
+ AU -- no --> L[Sign in screen]
67
+ AU -- yes --> DB[(Database)]
68
+ A --> Q[[Job queue]]
69
+ Q --> K[Worker]
70
+ K --> S[(File storage)]
71
+ K --> M[Email service]
72
+ DB --> A
73
+ A --> W
74
+ ```
75
+
76
+ ## 5. Sharing a note
77
+
78
+ ```mermaid
79
+ sequenceDiagram
80
+ participant O as Owner
81
+ participant W as Web app
82
+ participant A as API
83
+ participant D as Database
84
+ participant R as Recipient
85
+ O->>W: Click Share
86
+ W->>A: POST /notes/42/share (expires in 7 days)
87
+ A->>D: Insert share token
88
+ D-->>A: token abc123
89
+ A-->>W: share URL
90
+ W-->>O: Copy link
91
+ O->>R: Sends the link
92
+ R->>A: GET /s/abc123
93
+ A->>D: Look up token and expiry
94
+ alt token valid
95
+ A-->>R: Read-only note
96
+ else expired or revoked
97
+ A-->>R: 410 Gone page
98
+ end
99
+ ```
100
+
101
+ ## 6. Acceptance criteria
102
+
103
+ - [ ] Signup to empty dashboard takes six screens or fewer
104
+ - [ ] Back from any signup step keeps the typed values
105
+ - [ ] An expired code shows a resend action
106
+ - [ ] Autosave survives a reload during typing
107
+ - [ ] A revoked share link returns the Gone page within one minute
108
+ - [ ] A viewer cannot edit, invite or delete
109
+
110
+ ## 7. Risks
111
+
112
+ | Risk | Likelihood | Impact | Mitigation |
113
+ |------|------------|--------|------------|
114
+ | Concurrent edits overwrite text | Medium | High | Field lock on title, revision check on save, conflict banner |
115
+ | Share links leak in forwarded mail | Medium | Medium | Expiry by default, one click revoke, view counter |
116
+ | Email deliverability is poor | Medium | High | Dedicated sending domain, plain text fallback, resend limit |
117
+ | Export jobs pile up | Low | Medium | Queue depth alert, per workspace rate limit |
118
+ | Scope grows before beta | High | Medium | Freeze the list in section 3 after week two |
119
+
120
+ ## 8. Open questions
121
+
122
+ 1. Should viewers be able to download attachments from a shared note?
123
+ 2. Is a 7 day default expiry right, or should links never expire unless set?
124
+ 3. Do we need an audit log of share link opens for the beta?
125
+ 4. Which region hosts the first workspaces?
126
+
127
+ ## 9. Timeline
128
+
129
+ | Week | Milestone |
130
+ |------|-----------|
131
+ | 1 | Schema, auth, signup screens |
132
+ | 2 | Notes API and editor |
133
+ | 3 | Notes list, search, attachments |
134
+ | 4 | Sharing and settings |
135
+ | 5 | Export, load test, accessibility |
136
+ | 6 | Private beta |
@@ -0,0 +1,124 @@
1
+ <DesignBoard title="Lumen Notes - signup storyboard" version={1} transitions={[
2
+ { from: "welcome", to: "create", label: "tap Continue" },
3
+ { from: "create", to: "verify", label: "submit" },
4
+ { from: "verify", to: "workspace", label: "code accepted" },
5
+ { from: "workspace", to: "invite", label: "create workspace" },
6
+ { from: "invite", to: "dashboard", label: "send or skip" },
7
+ ]}>
8
+ <Section id="account" title="Create the account" subtitle="Three steps from first launch to a verified address. Every screen is a low-fidelity sketch, not final UI.">
9
+ <Artboard id="welcome" label="Welcome" surface="mobile" x={80} y={120} width={320} height={580} order={1}>
10
+ <Screen surface="mobile" caption="First launch, signed out.">
11
+ <FrameScreen>
12
+ <StatusBar />
13
+ <Col full>
14
+ <Box dashed>
15
+ <Row><IconSquare active /><Title text="Lumen Notes" /></Row>
16
+ <Lines n={2} widths={[70, 48]} />
17
+ </Box>
18
+ <Text value="Notes that stay in sync on every device." tone="muted" />
19
+ <Lines n={3} widths={[90, 76, 60]} />
20
+ <Btn label="Continue with email" primary />
21
+ <Text value="Already have an account? Sign in" tone="muted" />
22
+ </Col>
23
+ </FrameScreen>
24
+ </Screen>
25
+ </Artboard>
26
+ <Artboard id="create" label="Create account" surface="mobile" x={600} y={120} width={320} height={580} order={2}>
27
+ <Screen surface="mobile">
28
+ <FrameScreen>
29
+ <StatusBar />
30
+ <Col full>
31
+ <Title text="Create account" />
32
+ <Box>
33
+ <Text value="Email" tone="muted" />
34
+ <Lines n={1} widths={[58]} />
35
+ </Box>
36
+ <Box>
37
+ <Text value="Password" tone="muted" />
38
+ <Lines n={1} widths={[36]} />
39
+ </Box>
40
+ <Row><IconSquare active /><Text value="I agree to the terms" /></Row>
41
+ <Divider />
42
+ <Btn label="Create account" primary />
43
+ </Col>
44
+ </FrameScreen>
45
+ </Screen>
46
+ </Artboard>
47
+ <Artboard id="verify" label="Verify email" surface="mobile" x={1120} y={120} width={320} height={580} order={3}>
48
+ <Screen surface="mobile">
49
+ <FrameScreen>
50
+ <StatusBar />
51
+ <Col full>
52
+ <Title text="Check your inbox" />
53
+ <Text value="We sent a six digit code." tone="muted" />
54
+ <Row><IconSquare /><IconSquare /><IconSquare /><IconSquare /><IconSquare /><IconSquare /></Row>
55
+ <Lines n={2} widths={[84, 52]} />
56
+ <Btn label="Open mail app" primary />
57
+ <Text value="Resend code" tone="muted" />
58
+ </Col>
59
+ </FrameScreen>
60
+ </Screen>
61
+ </Artboard>
62
+ </Section>
63
+ <Section id="first-run" title="First run" subtitle="Workspace setup and the empty state a new user lands on.">
64
+ <Artboard id="workspace" label="Name your workspace" surface="mobile" x={1120} y={980} width={320} height={580} order={4}>
65
+ <Screen surface="mobile">
66
+ <FrameScreen>
67
+ <StatusBar />
68
+ <Col full>
69
+ <Title text="Name your workspace" />
70
+ <Box><Lines n={1} widths={[44]} /></Box>
71
+ <SectionLabel label="Use it for" />
72
+ <TaskRow title="Personal" done note="default" />
73
+ <TaskRow title="Team" />
74
+ <TaskRow title="School" />
75
+ <Btn label="Create workspace" primary />
76
+ </Col>
77
+ </FrameScreen>
78
+ </Screen>
79
+ </Artboard>
80
+ <Artboard id="invite" label="Invite teammates" surface="mobile" x={600} y={980} width={320} height={580} order={5}>
81
+ <Screen surface="mobile">
82
+ <FrameScreen>
83
+ <StatusBar />
84
+ <Col full>
85
+ <Title text="Invite teammates" />
86
+ <Row><IconSquare active /><Lines n={1} widths={[70]} /></Row>
87
+ <Row><IconSquare /><Lines n={1} widths={[56]} /></Row>
88
+ <Row><IconSquare /><Lines n={1} widths={[64]} /></Row>
89
+ <Divider />
90
+ <Btn label="Send invites" primary />
91
+ <Text value="Skip for now" tone="muted" />
92
+ </Col>
93
+ </FrameScreen>
94
+ </Screen>
95
+ </Artboard>
96
+ <Artboard id="dashboard" label="Empty dashboard" surface="mobile" x={80} y={980} width={320} height={580} order={6}>
97
+ <Screen surface="mobile" caption="Nothing is created for the user yet.">
98
+ <FrameScreen>
99
+ <StatusBar />
100
+ <Col full>
101
+ <Row><Title text="Today" /><IconSquare active /></Row>
102
+ <Box dashed>
103
+ <Skeleton lines={3} widths={[80, 64, 72]} />
104
+ </Box>
105
+ <Text value="No notes yet" tone="muted" />
106
+ <Btn label="New note" primary />
107
+ </Col>
108
+ </FrameScreen>
109
+ </Screen>
110
+ </Artboard>
111
+ </Section>
112
+
113
+ <Annotation id="note-password" title="Password rules" targetId="create" placement="bottom">
114
+
115
+ Show the rule list only after the first keystroke, so the form starts calm.
116
+
117
+ </Annotation>
118
+
119
+ <Annotation id="note-code" title="Code entry" targetId="verify" placement="right">
120
+
121
+ Paste fills all six boxes at once. The code expires after ten minutes.
122
+
123
+ </Annotation>
124
+ </DesignBoard>
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Lumen Notes - Signup Storyboard
3
+ status: draft
4
+ ---
5
+
6
+ # Signup flow
7
+
8
+ ## Goal
9
+
10
+ A new visitor reaches an empty, ready-to-use dashboard in six screens or fewer. All names and data in this example are invented.
11
+
12
+ ## Decision
13
+
14
+ <Decision title="Verification method" question="How do we verify the email address?" options={[
15
+ { id: "code", label: "Six digit code", detail: "Works when the mail app opens on another device.", recommended: true },
16
+ { id: "link", label: "Magic link", detail: "One tap, but breaks when the link opens in a different browser." },
17
+ ]}>
18
+
19
+ A code survives a device switch, which is the common failure for links.
20
+
21
+ </Decision>
22
+
23
+ ## Acceptance {#acceptance}
24
+
25
+ <Checklist title="Done when" items={[
26
+ { label: "Every screen fits one viewport without scrolling", checked: true },
27
+ { label: "Back from any step keeps the typed values" },
28
+ { label: "Expired codes show a resend action" },
29
+ ]} />
30
+
31
+ ## Build map {#build-map}
32
+
33
+ <ImplementationMap files={[
34
+ { path: "app/signup/welcome.tsx", change: "added", note: "Entry screen and sign-in link" },
35
+ { path: "app/signup/verify.tsx", change: "added", note: "Code boxes with paste handling" },
36
+ { path: "app/auth/session.ts", change: "modified", note: "Create the workspace after the first verified session" },
37
+ ]} />