@jimhoyd/urlcode 0.4.1 → 0.4.6

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 (212) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +60 -7
  2. package/.claude/skills/urlcode-operations/SKILL.md +4 -0
  3. package/README.md +19 -15
  4. package/SECURITY.md +5 -3
  5. package/dist/BUILD-MANIFEST.json +31 -28
  6. package/dist/agent-context.js +82 -0
  7. package/dist/agents-guide.js +42 -42
  8. package/dist/authoring.js +12 -2
  9. package/dist/body-schema.js +159 -0
  10. package/dist/build-cloudflare.js +2 -0
  11. package/dist/capabilities.js +1 -1
  12. package/dist/cli.js +29 -12
  13. package/dist/config.js +74 -6
  14. package/dist/context.js +4 -6
  15. package/dist/errors.js +3 -1
  16. package/dist/examples.js +1 -1
  17. package/dist/extensions.js +138 -3
  18. package/dist/http-policy.js +19 -4
  19. package/dist/http-response.js +2 -2
  20. package/dist/init-with.js +71 -9
  21. package/dist/mcp.js +15 -2
  22. package/dist/pattern-guard.js +32 -0
  23. package/dist/policies/security.js +0 -0
  24. package/dist/policy.js +16 -0
  25. package/dist/project-tests.js +35 -11
  26. package/dist/readiness.js +188 -32
  27. package/dist/recipes.js +1 -1
  28. package/dist/router.js +17 -0
  29. package/dist/runtime.js +26 -3
  30. package/dist/scaffold.js +0 -0
  31. package/dist/server.js +26 -3
  32. package/dist/site.js +0 -0
  33. package/dist/tooling.js +3 -1
  34. package/dist/types/agent-context.d.ts +44 -0
  35. package/dist/types/authoring.d.ts +3 -1
  36. package/dist/types/body-schema.d.ts +58 -0
  37. package/dist/types/config.d.ts +10 -2
  38. package/dist/types/context.d.ts +1 -1
  39. package/dist/types/errors.d.ts +9 -1
  40. package/dist/types/examples.d.ts +1 -1
  41. package/dist/types/extensions.d.ts +105 -2
  42. package/dist/types/http-policy.d.ts +3 -0
  43. package/dist/types/init-with.d.ts +10 -1
  44. package/dist/types/pattern-guard.d.ts +10 -0
  45. package/dist/types/project-tests.d.ts +9 -0
  46. package/dist/types/readiness.d.ts +71 -0
  47. package/dist/types/recipes.d.ts +1 -1
  48. package/dist/types/runtime.d.ts +4 -0
  49. package/dist/types/server.d.ts +9 -1
  50. package/dist/types/tooling.d.ts +2 -0
  51. package/dist/types/types.d.ts +13 -0
  52. package/dist/types.js +10 -2
  53. package/dist/typescript-authoring.js +5 -3
  54. package/dist/verify-deployment.js +16 -10
  55. package/examples/body-validation/README.md +16 -0
  56. package/examples/body-validation/example.yaml +17 -0
  57. package/examples/body-validation/tests/requests.json +15 -0
  58. package/examples/body-validation/urlcode.yaml +34 -0
  59. package/examples/coverage-waiver/README.md +8 -0
  60. package/examples/coverage-waiver/example.yaml +16 -0
  61. package/examples/coverage-waiver/functions/notes.mjs +2 -0
  62. package/examples/coverage-waiver/tests/requests.json +3 -0
  63. package/examples/coverage-waiver/urlcode.yaml +10 -0
  64. package/examples/data-dir/README.md +39 -0
  65. package/examples/data-dir/data/welcome.txt +1 -0
  66. package/examples/data-dir/example.yaml +22 -0
  67. package/examples/data-dir/functions/note.mjs +18 -0
  68. package/examples/data-dir/tests/requests.json +6 -0
  69. package/examples/data-dir/urlcode.yaml +6 -0
  70. package/examples/lifecycle/README.md +15 -0
  71. package/examples/lifecycle/example.yaml +19 -0
  72. package/examples/lifecycle/functions/notes.mjs +29 -0
  73. package/examples/lifecycle/tests/requests.json +12 -0
  74. package/examples/lifecycle/urlcode.yaml +29 -0
  75. package/examples/not-found/README.md +10 -0
  76. package/examples/not-found/example.yaml +17 -0
  77. package/examples/not-found/public/404.html +3 -0
  78. package/examples/not-found/public/index.html +3 -0
  79. package/examples/not-found/tests/requests.json +7 -0
  80. package/examples/not-found/urlcode.yaml +7 -0
  81. package/examples/shared-blocks/README.md +11 -0
  82. package/examples/shared-blocks/example.yaml +17 -0
  83. package/examples/shared-blocks/tests/requests.json +7 -0
  84. package/examples/shared-blocks/urlcode.yaml +37 -0
  85. package/llms-full.txt +436 -149
  86. package/llms.txt +44 -6
  87. package/package.json +15 -22
  88. package/recipes/static-page/README.md +9 -0
  89. package/recipes/static-page/public/index.html +11 -0
  90. package/recipes/static-page/recipe.yaml +21 -0
  91. package/recipes/static-page/tests/requests.json +22 -0
  92. package/recipes/static-page/urlcode.yaml +7 -0
  93. package/recipes/static-plus-api/README.md +6 -0
  94. package/recipes/static-plus-api/urlcode.yaml +4 -0
  95. package/recipes/store-crud/README.md +53 -0
  96. package/recipes/store-crud/recipe.yaml +31 -0
  97. package/recipes/store-crud/tests/requests.json +18 -0
  98. package/recipes/store-crud/urlcode.yaml +18 -0
  99. package/schemas/urlcode.schema.json +125 -60
  100. package/skills/urlcode/SKILL.md +53 -26
  101. package/starters/default/AGENTS.md +43 -43
  102. package/starters/page/README.md +14 -0
  103. package/starters/page/public/index.html +12 -0
  104. package/starters/page/tests/requests.json +17 -0
  105. package/starters/page/urlcode.yaml +6 -0
  106. package/.claude-plugin/marketplace.json +0 -18
  107. package/CONTRIBUTING.md +0 -112
  108. package/ROADMAP.md +0 -66
  109. package/docs/AI-AUTHORING.md +0 -338
  110. package/docs/ASSETS.md +0 -107
  111. package/docs/AUTH-BACKUP.md +0 -32
  112. package/docs/AWS.md +0 -86
  113. package/docs/BEST-PRACTICES.md +0 -276
  114. package/docs/BULK.md +0 -79
  115. package/docs/CAPABILITIES.md +0 -192
  116. package/docs/CAPACITY.md +0 -305
  117. package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
  118. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
  119. package/docs/CI.md +0 -147
  120. package/docs/CLOUDFLARE.md +0 -109
  121. package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
  122. package/docs/COMPLIANCE.md +0 -239
  123. package/docs/COMPOSING-A-SITE.md +0 -278
  124. package/docs/CONDITIONS.md +0 -74
  125. package/docs/DEPLOYMENT-CHECKS.md +0 -108
  126. package/docs/DEVELOPMENT-PIPELINE.md +0 -270
  127. package/docs/EGRESS.md +0 -125
  128. package/docs/EXTENSIONS.md +0 -438
  129. package/docs/FRAMEWORK.md +0 -217
  130. package/docs/FUNCTION-SECURITY.md +0 -254
  131. package/docs/HTTP.md +0 -129
  132. package/docs/INSTALL.md +0 -128
  133. package/docs/INTERCHANGE.md +0 -134
  134. package/docs/LOAD-TESTING.md +0 -91
  135. package/docs/LOCAL-DEVELOPMENT.md +0 -102
  136. package/docs/MIDDLEWARE-EXAMPLES.md +0 -75
  137. package/docs/MIDDLEWARE.md +0 -102
  138. package/docs/MONITORING.md +0 -115
  139. package/docs/OBSERVABILITY.md +0 -222
  140. package/docs/OPEN-DECISIONS.md +0 -224
  141. package/docs/OPERATIONAL-PROOF.md +0 -41
  142. package/docs/OPERATIONS.md +0 -201
  143. package/docs/ORGANIZATION.md +0 -135
  144. package/docs/PERFORMANCE.md +0 -72
  145. package/docs/PLUGINS.md +0 -271
  146. package/docs/POLICIES.md +0 -211
  147. package/docs/PRERENDER.md +0 -245
  148. package/docs/PROJECT-DIRECTION.md +0 -118
  149. package/docs/PROVIDER-VERIFICATION.md +0 -84
  150. package/docs/READINESS.md +0 -150
  151. package/docs/README.md +0 -87
  152. package/docs/RECIPES.md +0 -99
  153. package/docs/RELEASE-0.4.0-alpha.3.md +0 -50
  154. package/docs/RELEASE-0.4.1.md +0 -73
  155. package/docs/RELEASE-READINESS.md +0 -117
  156. package/docs/RELEASE-SECURITY.md +0 -96
  157. package/docs/RESILIENCE.md +0 -161
  158. package/docs/ROUTING.md +0 -92
  159. package/docs/SANDBOX-REVIEW.md +0 -72
  160. package/docs/SCAFFOLDING.md +0 -70
  161. package/docs/SECURITY-AUDIT.md +0 -164
  162. package/docs/SITE.md +0 -150
  163. package/docs/SPECIFICATION.md +0 -359
  164. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
  165. package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
  166. package/docs/SPIKE-CORE-LAYERING.md +0 -368
  167. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -211
  168. package/docs/STANDARDS.md +0 -311
  169. package/docs/STARTERS.md +0 -83
  170. package/docs/STATIC.md +0 -105
  171. package/docs/TOOLING.md +0 -298
  172. package/docs/TUNNELS.md +0 -72
  173. package/docs/TYPESCRIPT-AUTHORING.md +0 -87
  174. package/docs/TYPESCRIPT.md +0 -123
  175. package/docs/VERCEL.md +0 -114
  176. package/docs/VERSION-ALIGNMENT.md +0 -80
  177. package/docs/YAML-GUIDE.md +0 -57
  178. package/docs/YAML-REFERENCE.md +0 -449
  179. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
  180. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
  181. package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
  182. package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
  183. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
  184. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
  185. package/docs/archive/2026-09-19/ROADMAP.md +0 -387
  186. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
  187. package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
  188. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
  189. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
  190. package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
  191. package/docs/archive/README.md +0 -28
  192. package/docs/policies/agents.md +0 -182
  193. package/docs/policies/cache.md +0 -152
  194. package/docs/policies/compression.md +0 -169
  195. package/docs/policies/contract.md +0 -52
  196. package/docs/policies/hardened.md +0 -56
  197. package/docs/policies/interoperability.md +0 -169
  198. package/docs/policies/operations.md +0 -45
  199. package/docs/policies/security.md +0 -161
  200. package/docs/policies/throttle.md +0 -103
  201. package/docs/yaml/assets.md +0 -36
  202. package/docs/yaml/conditions.md +0 -20
  203. package/docs/yaml/functions.md +0 -168
  204. package/docs/yaml/middleware.md +0 -31
  205. package/docs/yaml/organization.md +0 -74
  206. package/docs/yaml/policies.md +0 -37
  207. package/docs/yaml/redirects.md +0 -64
  208. package/docs/yaml/responses.md +0 -57
  209. package/docs/yaml/site.md +0 -24
  210. package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
  211. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -120
  212. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
@@ -1,1029 +0,0 @@
1
- # URLCode business suite spike
2
-
3
- > Review update, 2026-09-19: Current status: an unapproved candidate list, gated on observed repetition
4
- > and benchmark evidence under PROJECT-DIRECTION.md. The short-link products
5
- > are retired; the seven-product recommendation below is historical, not agreed
6
- > current scope. No business-suite implementation is implied.
7
-
8
-
9
- Date: 2026-09-18. Status: proposal, not an implemented contract or production claim.
10
- Core inspected at `50790d3` (0.4.0-alpha.1), plus local auth, admin, UI and
11
- shortener source/status files. Competitor research below is a documentation
12
- review, not hands-on benchmarking. Features and commercial packaging can change.
13
-
14
- > **Update:** this proposal was written when `link`/`LinkStore` was still a
15
- > native core feature. Core no longer has that API — it was extracted to a
16
- > separate `urlcode-dynamic-link` package, which has since been retired,
17
- > unpublished and deleted (September 2026), along with the `urlcode-short`
18
- > shortener this document proposes. Those two products are no longer planned.
19
- > References below to core owning link storage (e.g. "Reuse core's LinkStore",
20
- > "Retain core link semantics", the `core LinkStore -> short` dependency line)
21
- > describe the pre-extraction state this spike was proposing against, and the
22
- > `urlcode-short` migration sections record an abandoned plan.
23
-
24
- ## Recommendation
25
-
26
- Build seven independently released Apache-2.0 applications on URLCode:
27
- `urlcode-cms`, `urlcode-blog`, `urlcode-short`, `urlcode-support`,
28
- `urlcode-forms`, `urlcode-billing` and `urlcode-legal`. Use
29
- `@jimhoyd/urlcode-<name>` packages.
30
- Rename the existing `urlcode-shortener` repository to **`urlcode-short`** and
31
- publish it as **`@jimhoyd/urlcode-short`**, with CLI `urlcode-short` and logical
32
- extension name `short`. This is the agreed naming/release direction; the remote
33
- rename and npm publication have not happened as part of this documentation spike.
34
- Each application has one domain service, an operator-installed runtime extension,
35
- a CLI/API for agents, and a standalone launcher composing the same components.
36
- Standalone means no separate URLCode installation/configuration exercise; it
37
- still uses URLCode internally. Auth and admin are optional integrations.
38
-
39
- CMS is the content foundation; blog is a CMS preset plus publishing features.
40
- Support reuses CMS for its optional knowledge base, not for ticket storage.
41
- Short reuses core's live-link engine. Forms owns submissions and lead intake;
42
- billing owns payment-provider synchronization and entitlements. Reliable
43
- notifications are a shared operator library/worker, initially developed with
44
- forms and consumed by billing and support; they are not another login or console.
45
- Legal is a shared versioned document/control library used by every application;
46
- it can publish through CMS or serve a standalone legal center.
47
- Core remains generic and never imports
48
- these applications. Shared presentation stays in urlcode-ui, using the existing
49
- Tailwind/shadcn style, themes, translations and safe templates.
50
-
51
- Start with a single business per deployment and a durable Node host. Do not
52
- promise hostile multi-tenant hosting, arbitrary edge deployment or enterprise
53
- feature parity. Ship useful small products with explicit expansion points.
54
-
55
- ## What to learn from existing products
56
-
57
- The selection covers publishing, structured/headless content, file-based content,
58
- and commercial editorial workflows. It is a fit assessment, not a universal
59
- ranking. Borrow product behavior; do not copy incompatible licensed code.
60
-
61
- | Reference | Relevant strengths | URLCode decision |
62
- |---|---|---|
63
- | [WordPress](https://wordpress.org/about/features/) — open-source CMS | Familiar publishing, media, roles, themes and extensibility | Pages, media, preview and revisions are baseline; avoid an unrestricted runtime theme/plugin marketplace |
64
- | [Ghost](https://ghost.org/help/manual/) — open-source publishing and managed hosting | Focused publication experience, newsletters and memberships | Blog should feel complete immediately; defer newsletter delivery and payment machinery to shared integrations |
65
- | [Payload](https://payloadcms.com/docs/versions/overview), [access control](https://payloadcms.com/docs/access-control/overview) — open-source developer CMS | Drafts, versions and operation-specific permissions | Typed collections, explicit draft/published versions and authorization in the domain service |
66
- | [Strapi](https://docs.strapi.io/) — open-source CMS with commercial offerings | Content types, APIs, localization and editor UI | Small schema vocabulary and API/UI parity; avoid a general backend generator in v1 |
67
- | [Directus](https://docs.directus.io/reference/system/versions) — self-hostable/commercial data platform | Independent unpublished versions promoted into main content | Explicit revision promotion; don't turn CMS into a UI for arbitrary databases. Verify current license terms separately before reuse |
68
- | [Decap](https://decapcms.org/docs/intro/) — open-source Git CMS | File ownership, Git workflow, editor preview and media | Keep Markdown portable and Git-friendly; production editors should not need Git credentials |
69
- | [Grav](https://getgrav.org/headless) — open-source flat-file CMS | File-based content and API delivery | Closest content-storage reference; plain files must remain a first-class path |
70
- | [Statamic](https://statamic.com/features) — commercial flat-file CMS offering | Editorial UI, flexible content modeling and file-oriented operation | A polished editor can coexist with file portability; avoid starting with a visual site builder |
71
- | [Sanity](https://www.sanity.io/docs/content-lake/presenting-and-previewing-content) — commercial content platform | Separate published/draft/release perspectives | Preview must select a revision explicitly and never contaminate public caches |
72
- | [Contentful](https://www.contentful.com/help/ai-automations/workflows/workflows-management/multiple-workflows-to-content-types/) — commercial content platform | Workflow specialization by content type/team | Begin with draft → review → publish; defer enterprise workflow builders |
73
-
74
- Recommended balance: Grav/Decap portability, Ghost's focused publishing UX,
75
- Payload's typed authorization, and a small portion of commercial revision and
76
- review workflows. The differentiator is a safe, inspectable agent workflow with
77
- an optional human console—not the longest checklist of CMS features.
78
-
79
- | Support/link reference | Lesson to adopt | Deliberately later |
80
- |---|---|---|
81
- | [Zendesk routing](https://support.zendesk.com/hc/en-us/articles/6712096584090-Understanding-how-omnichannel-routing-uses-queues-to-route-work-to-agents) — commercial | Queues, assignment, priority and response deadlines | Skills/capacity routing across voice and social channels |
82
- | [Zammad](https://zammad.com/en/product/features) — open-source help desk | Ticket lifecycle, team collaboration, knowledge base | Deep ITSM and highly configurable workflows |
83
- | [Chatwoot](https://www.chatwoot.com/features/shared-inbox) — open-source support platform with hosted offering | Shared inbox, internal context and handoffs | Every channel and a live-chat transport in the first release |
84
- | [Shlink](https://shlink.io/features/) — open-source shortener | API-centered link management, QR codes and visit reporting | Complex targeting before abuse controls are proven |
85
- | [Dub](https://dub.co/docs) — commercial link attribution platform with public source | Polished link operations, bulk creation and integrations | Affiliate payouts, revenue attribution and partner programs |
86
-
87
- ## One application, three supported compositions
88
-
89
- Installing an npm package alone must not activate privileged code. “Install and
90
- it works” means the initializer discovers compatible installed packages and
91
- writes explicit, reviewable host wiring. The operator activates it with a pinned
92
- revision. No ambient discovery from untrusted route YAML.
93
-
94
- | Installed integrations | Intended behavior |
95
- |---|---|
96
- | Neither auth nor admin | CMS/blog serve public content; short supports bounded anonymous creation; forms accepts public submissions; billing supports operator-managed customers and provider-hosted checkout; support exposes intake/public help. Operator CLI/API manages data. No public management console or unverified customer account access |
97
- | Auth only | Account identity, scoped app APIs, optional restricted content, customer tickets and billing portal access. Leads can be explicitly linked to verified accounts. CLI/API remain full management surfaces |
98
- | Admin only | Unsupported: admin requires auth. Initialization and activation reject this combination with an actionable error |
99
- | Auth and admin | Integrated, permission-filtered management screens and shared accounts; domain services enforce every operation regardless of UI visibility |
100
-
101
- **Confirmed product rule:** admin requires auth, matching its current required
102
- peer and privileged service. Keep that dependency. Removing auth while admin is
103
- configured must refuse activation. Protected content, private tickets and writes
104
- also fail closed; removing admin alone should only remove the console.
105
-
106
- For a complete standalone console, provide a recommended preset composing auth,
107
- admin and the application. Also retain a minimal preset with neither. Do not
108
- implement separate password/session systems for the applications.
109
-
110
- Proposed package surfaces: domain service, host extension factory, `scaffold`,
111
- CLI executable, optional admin module, schemas, fixtures and migration tools.
112
- Auth/admin adapters should use optional dependencies or separate exports so the
113
- minimal app does not import them. CMS is a real blog dependency; the public UI
114
- library is acceptable as a shared rendering dependency.
115
-
116
- ## Markdown content and publishing
117
-
118
- Pages, posts and knowledge-base articles use `.md` with validated frontmatter.
119
- Operational records do not. A proposed file (CMS-owned schema, not core YAML):
120
-
121
- ```markdown
122
- ---
123
- id: page_about
124
- kind: page
125
- slug: /about
126
- title: About us
127
- locale: en
128
- status: draft
129
- template: standard
130
- ---
131
- # About us
132
- A small business built on URLCode.
133
- ```
134
-
135
- Stable IDs survive renames. Schema definitions live in a versioned CMS content
136
- manifest; frontmatter cannot select modules, secrets, infrastructure or arbitrary
137
- executable templates. Start with text, Markdown, boolean, number, date, enum,
138
- media and reference fields. Validate references, unique slugs, locale variants,
139
- reserved paths and bounded document sizes. Rich editing must round-trip the
140
- supported Markdown subset without silently deleting unsupported syntax.
141
-
142
- Support two explicit operating modes, never two competing sources of truth:
143
-
144
- 1. **File mode:** project authors edit Markdown in Git. A deterministic compiler
145
- produces a public-only artifact and ordinary core page/static routes. Validate,
146
- review/re-pin where required, then redeploy. No database is needed to serve it.
147
- 2. **Managed mode:** immutable Markdown revision blobs and media live in private
148
- operator storage. SQLite owns revision pointers, workflow, audit, jobs and
149
- indexes. UI/API/CLI write through one service using expected revisions. Export
150
- yields ordinary Markdown and a manifest; import is previewed and conflict-aware.
151
- Direct disk edits are an explicit import, never a concurrent hidden writer.
152
-
153
- For managed publishing, commit a durable job referencing the approved revision;
154
- render a complete immutable public artifact; validate it; atomically switch the
155
- active artifact/release pointer through a trusted deployment adapter. A crash
156
- must leave the previous release serving. Domain publish state is not reported
157
- as live until activation is acknowledged. A lost acknowledgement is reconciled
158
- by release ID. Store the previous release for rollback; index/search/sitemap
159
- versions travel with it. Publishing groups can be added after single-release
160
- atomicity is proven.
161
-
162
- Core `serve` is a fixed snapshot. A file write alone is not a live publish.
163
- Initially use controlled restart/redeployment of the public artifact. A future
164
- generic activation API can improve this without allowing CMS to reapprove its
165
- own changed execution grants. Separate public serving from the private editor
166
- host when needed. Published pages are ordinary core assets, avoiding blanket
167
- extension-cache relaxation. Private/member content stays behind authorization
168
- and is never included in public exports, search indexes or static artifacts.
169
-
170
- Disable raw HTML and MDX execution by default; sanitize generated links/markup,
171
- escape frontmatter in templates and bound parser work. Rich components are a
172
- small validated allowlist. Auth/admin browsers must not execute content-author
173
- scripts on their origin. Use a separate preview origin/sandbox for potentially
174
- active material. Media uploads need private quarantine, type/size validation,
175
- image re-encoding where appropriate and explicit publication. Large media uses
176
- operator-bound object storage, not a larger unbounded extension response.
177
-
178
- ## Application release scope
179
-
180
- | Application | First production scope | Subsequent scope |
181
- |---|---|---|
182
- | CMS | Pages and small collections; Markdown editor/preview; media with alt text; navigation; drafts/review/publish; revision diff/restore; SEO metadata/canonicals; sitemap; slug redirects; bounded search; import/export; editor/publisher permissions; audit; static export | Scheduled release bundles, richer localization workflow, reusable structured blocks and provider media adapters |
183
- | Blog | CMS post type and templates; authors/tags; archive/pagination; RSS/Atom; reading pages; social metadata; draft preview; publish scheduling through durable jobs; import/export | Newsletter integration, memberships through auth plus billing, moderated comments; no separate CMS engine |
184
- | Short | Existing anonymous short-lived mode; authenticated ownership and CRUD; custom slug; expiration/disable; QR; tags; CSV import/export; bounded aggregate analytics; operator takedown and abuse reporting | Verified custom domains, campaigns, richer analytics; no affiliate product initially |
185
- | Support | Email and web intake; ticket thread/status/priority; assignee/team queues; public replies vs private notes; safe attachments; search; macros; customer-scoped portal with auth; audit; delivery retries; basic response/resolution timing; optional CMS help center | Business-hours SLA calendars/escalation, automation rules, CSAT, chat and additional channels |
186
- | Forms | Versioned forms; accessible hosted/embed views; server validation; spam/rate limits; durable submission receipt; minimal lead inbox; explicit consent evidence; export/deletion; notification outbox; signed webhook handoff | File uploads, branching/multi-step forms, richer routing and CRM connectors |
187
- | Billing | One provider adapter; hosted checkout/customer portal; fixed recurring plan; authenticated customer binding when auth is present; durable verified webhook inbox; subscription reconciliation; local entitlements; operator inspection and recovery | One-time purchases, additional providers, usage billing, seats, coupons and tax/accounting integrations |
188
- | Legal | Versioned operator-reviewed terms, privacy notice, cookie notice, acceptable-use policy, refund/subscription terms, accessibility statement, security page, subprocessor list and DPA materials; disclosure registry; acceptance evidence; standalone legal center and CMS publishing adapter | Jurisdiction-specific reviewed packs, change-notice workflows, additional contract schedules and externally validated compliance mappings |
189
-
190
- CMS localization-ready IDs/schema ship first; do not claim translated UI or
191
- content until catalogues and workflows are tested. Scheduling requires durable
192
- worker execution, restart catch-up and cancellation/version checks; it is not
193
- an in-process timer. CMS does not need to block its first release on scheduling,
194
- but the listed blog scope does.
195
-
196
- Short migration: the existing `urlcode-shortener` demo is private/unpublished and marked
197
- UNLICENSED, pins an old core archive, and has no auth/analytics. This proposal
198
- records the requested direction to Apache-2.0 and public packages, but the
199
- implementation PR must verify rights to existing assets/dependencies, add the
200
- license/notices, migrate the package/runtime pin and preserve existing links,
201
- expiry and QR behavior. Rename the existing repo without discarding its history. Reuse core's LinkStore and
202
- conditional updates; keep ownership and domain metadata in the app with a
203
- recoverable transaction/outbox strategy if stores are separate. Never let a
204
- metadata failure leave an unauthorized active link. Redirect availability must
205
- not depend on analytics delivery. Core link events are bounded observations,
206
- not a guaranteed billing ledger. No preview-fetching arbitrary destinations.
207
-
208
- Support tickets require transactional storage, not Markdown files. Separate
209
- requester identity, staff identity, message visibility and delivery status.
210
- Inbound adapters verify provider signatures; email From alone grants no portal
211
- access. Deduplicate provider/message IDs, bound MIME parsing and attachments,
212
- and prevent auto-reply loops. A transactional outbox sends only committed public
213
- replies, retries with idempotency keys and exposes failures. Private notes never
214
- enter mail, customer APIs, public search or AI prompts for customer replies.
215
- Without auth, intake confirmation does not grant ticket read access; use the
216
- operator CLI/API or explicitly configured scoped verification links. CMS absence
217
- must leave tickets usable and simply remove the help center.
218
-
219
- ## Naming and release migration: urlcode-short
220
-
221
- Treat the rename as a focused repository migration, followed by implementation
222
- and then a release. The approved name does not waive existing release gates.
223
-
224
- 1. Inventory repo settings, CI references, Pages/container names, docs links,
225
- local remotes, npm metadata, lockfiles and executable names. Check the target
226
- repository/package name and publisher access before changing remote state.
227
- 2. Rename the existing GitHub repository to `urlcode-short`; retain issues,
228
- history, protected-branch settings and security reporting. Verify redirects
229
- and update first-party references explicitly. Update local checkout/remotes
230
- without moving a directory underneath active work.
231
- 3. Change package/bin/repository metadata and release workflows together. Use
232
- the current reviewed scoped core dependency, Apache-2.0 and required notices.
233
- Publish only `@jimhoyd/urlcode-short`; do not publish an old-name placeholder.
234
- If an old package was published since this inventory, document its supported
235
- migration/deprecation rather than assuming there are no consumers.
236
- 4. Keep public short URLs, stored codes, expiration and existing data paths
237
- unchanged. The branding change must not change a redirect hostname or add
238
- `/short` to existing URLs. Provide explicit, reversible config/schema migration
239
- where extension names or imports change; never silently reset the store.
240
- 5. Verify clean tarball installation, CLI/bin resolution, all composition modes,
241
- existing-link fixtures, upgrade/restore and container startup. Tag/publish
242
- from reviewed CI, inspect registry provenance and install the actual published
243
- version in the dogfood deployment. Update framework/agent docs afterward.
244
-
245
- ## Forms and lead capture: urlcode-forms
246
-
247
- First dogfood use: contact, early-access and product-interest forms on our own
248
- site. A lead is a business contact/submission, not an auth account or a mailing
249
- list subscription. Start with a usable inbox rather than waiting for a full CRM.
250
-
251
- The domain owns `FormDefinition`, immutable `FormVersion`, `Submission`,
252
- `ConsentEvidence`, `Lead` and an outbox. Form definitions are versioned JSON/YAML
253
- validated by the app; core YAML only declares routes/extensions. Each submission
254
- records the exact form version and notice version shown. Allow text, email,
255
- textarea, enum, checkbox and bounded numbers first. Validate on the server,
256
- reject unknown fields, and avoid sensitive fields by default. No arbitrary JS,
257
- remote validation callbacks or user-supplied notification destinations.
258
-
259
- Public rendering and POST handling live under an exclusive `/forms/*` extension
260
- mount. CMS embeds a generated accessible form or links to a hosted form; API
261
- clients use a documented JSON endpoint with the same validation. An allowlisted
262
- origin policy controls browser embeds, but is not an abuse defense by itself.
263
- Use bounded body/field lengths, per-form admission limits, honeypots and optional
264
- operator-bound challenges. CSRF protection applies to authenticated management;
265
- public submissions need their own abuse controls. No uploads in the first slice.
266
-
267
- Acceptance means a submission and notification intent commit atomically before
268
- a receipt is returned. Submission retries with the same idempotency key and
269
- payload return the same receipt; changed payloads with that key conflict. Spam
270
- can be quarantined without emailing staff. The receipt reveals no inbox content
271
- or account existence. Email outage must not lose the lead or claim delivery.
272
-
273
- The inbox provides new/contacted/qualified/closed states, assignment, notes,
274
- filters and CSV/JSON export with spreadsheet-formula injection protection.
275
- Email matching may suggest a merge, but must not auto-link to an auth principal
276
- or merge unrelated contacts. Record consent purpose, notice version and time;
277
- marketing opt-in is separate and defaults off. Retention, export and deletion
278
- cover attachments when later enabled and downstream delivery metadata, with
279
- explicit backup retention limits. Metrics distinguish accepted, quarantined,
280
- notified and followed-up counts.
281
-
282
- Host-configured handoffs use a durable outbox: lead creation, support-ticket
283
- creation or CRM export. Consumers deduplicate by submission/event ID. Never make
284
- an arbitrary guest-supplied webhook URL a privileged network destination. Admin
285
- screens live at `/admin/forms`; without admin the CLI/API can do every operation.
286
- Definition edits and bulk export require separate permissions. Drafting a reply
287
- is distinct from authorizing it to be sent.
288
-
289
- ## Billing and entitlements: urlcode-billing
290
-
291
- First dogfood use: one paid recurring offering with a clear free baseline. Keep
292
- plan prices and the precise paid feature set outside this spike until the
293
- business chooses them. Prove purchase → access → cancellation → access change
294
- in provider test mode before accepting money.
295
-
296
- Choose Stripe as the first proposed adapter, behind a small provider interface;
297
- this is an implementation recommendation, not an account configuration decision.
298
- Use hosted checkout and the provider portal. Server-side operator configuration
299
- maps logical plans/features to allowed provider price IDs; a browser cannot set
300
- an amount, select an arbitrary price or assert that it paid. Credentials, API
301
- version and provider endpoints remain operator configuration. Cards and payment
302
- method data stay with the payment provider.
303
-
304
- Own `BillingCustomer`, stable business subject ID, provider mapping,
305
- `SubscriptionProjection`, `EntitlementGrant`, webhook inbox, reconciliation
306
- cursor and audit. An auth user can be a verified member/owner of a billing
307
- subject, but email equality never proves ownership. Start with one owner per
308
- customer; leave organization/seat management later. Without auth, operators
309
- manage stable external subjects through the CLI/API; public checkout does not
310
- automatically create an account or expose a customer portal. Portal sessions
311
- require a verified authenticated mapping or an explicit operator workflow.
312
-
313
- [Stripe webhook guidance](https://docs.stripe.com/webhooks) documents signature
314
- verification using the raw payload, duplicate events and unordered delivery.
315
- Our receiver validates the signature, account/environment and event size, then
316
- durably inserts an inbox record before acknowledging. Workers process retries;
317
- event IDs and domain transition keys prevent repeated effects. Test/live stores
318
- and keys are separate. Return URLs are allowlisted; checkout success redirects
319
- are never evidence for granting access.
320
-
321
- Reconciliation fetches authoritative current provider state, serializes updates
322
- per subscription and prevents stale workers from overwriting newer projections.
323
- A periodic full reconciliation recovers missed events; timestamps alone are not
324
- an ordering guarantee. Operator tooling reports mismatches and supports dry-run
325
- repair. Pin the provider API contract and test historical payload versions.
326
- [Stripe entitlements](https://docs.stripe.com/billing/entitlements) are one possible
327
- adapter input; the app-facing feature contract stays provider-neutral.
328
-
329
- Proposed default lifecycle, configurable only through reviewed operator policy:
330
-
331
- | Payment state | Access behavior |
332
- |---|---|
333
- | Checkout pending/incomplete | Free baseline; no paid access |
334
- | Active and payment requirements satisfied | Grant versioned features through their recorded validity |
335
- | Trial | Disabled initially; explicit finite trial policy if added |
336
- | Payment past due | Keep existing grants only within a configured finite grace period; do not grant new capacity |
337
- | Cancel at period end | Preserve already-paid access until the verified period end |
338
- | Subscription ended/unpaid after grace | Revoke paid features; retain login, data export, billing and support access |
339
- | Refund/dispute | Record and apply an explicit entitlement policy; no automatic content deletion |
340
- | Provider unavailable or projection stale | Never invent new grants; retain known grants only within recorded validity/staleness bounds, then restrict paid operations |
341
-
342
- Authorization is `principal permission AND entitlement`, enforced inside each
343
- protected domain action. Entitlements do not grant admin roles. Return structured
344
- feature decisions containing feature key, scope, limit, revision, expiry and
345
- reason. Resource quotas need atomic reserve/commit/release in the owning app;
346
- a cached boolean check cannot enforce a concurrent quota. Start with feature
347
- flags and simple resource limits, not metered charges. Cache invalidation and
348
- maximum staleness must be explicit and tested. Removing billing cannot silently
349
- turn paid features into public access; already-configured checks fail closed.
350
-
351
- The billing admin view covers customer/subscription state, event processing,
352
- entitlement diff, synchronization health and audited recovery. Initial refunds
353
- and complex adjustments use the provider console with reconciliation; do not
354
- build an incomplete accounting ledger. Billing notifications never block an
355
- access update. Suppress duplicate provider/application receipts by declaring
356
- which sender owns each message type. All spending/refund actions require
357
- separate agent capabilities and review according to operator policy.
358
-
359
- ## Reliable notifications and durable jobs
360
-
361
- Build a shared operator package, provisionally `@jimhoyd/urlcode-notifications`,
362
- with a library, worker CLI, adapter contract and optional admin delivery module.
363
- Its package/repository name is proposed; unlike `urlcode-short`, it is not yet a
364
- user-selected repository name. It works without auth/admin; admin integration
365
- still requires auth. Extract it from the first forms implementation once billing
366
- confirms the contract. Avoid a generic distributed workflow platform.
367
-
368
- Reliability has three separate states: persisted intent, provider acceptance and
369
- confirmed delivery (when reported). Provider acceptance is not inbox delivery or
370
- human reading. The transport is at-least-once; no blanket exactly-once promise.
371
-
372
- 1. **Commit:** the producing app stores its state change and outbox intent in the
373
- same database transaction. A helper must accept the existing transaction;
374
- sending to a separate queue after commit is not an atomic substitute.
375
- 2. **Relay:** a worker leases committed rows, sends them to the delivery service
376
- and marks them relayed only after durable acknowledgement. A unique source
377
- plus event/recipient/channel key deduplicates relay retries. Separate stores
378
- use this relay/inbox protocol, not cross-database transaction assumptions.
379
- 3. **Deliver:** fixed trusted handlers render a pinned template/version/locale,
380
- validate destinations and send through operator-configured adapters. Persist
381
- attempt IDs and provider IDs. Apply bounded exponential backoff with jitter,
382
- rate limits, timeouts, finite retry/expiry and per-source fairness.
383
- 4. **Recover:** expired leases can be reclaimed with fencing against stale workers.
384
- A timeout after provider acceptance is an ambiguous outcome. Reuse provider
385
- idempotency keys where supported; otherwise expose ambiguity and the chosen
386
- retry policy, which may duplicate mail. Do not mark it delivered or silently
387
- discard it. Poison jobs go to a visible dead-letter queue with reasoned replay.
388
- 5. **Observe:** process authenticated, deduplicated delivery/bounce/complaint
389
- callbacks. Show pending/retrying/accepted/delivered/failed/suppressed/unknown
390
- separately. [SES notifications](https://docs.aws.amazon.com/ses/latest/dg/monitor-sending-activity-using-notifications.html)
391
- can themselves be duplicated; event processing must tolerate this.
392
-
393
- First adapters: a deterministic local capture sender for tests and a production
394
- email adapter chosen from existing operator infrastructure; signed outbound
395
- webhooks are the second transport. Separate transactional from marketing
396
- preferences. Hard bounces/complaints trigger suppression with an audited policy;
397
- critical account workflows surface non-delivery rather than bypassing suppression.
398
- Pin webhook destination origins, bound response handling, block private-address
399
- SSRF and redirects, and rotate signing keys with overlap. No arbitrary shell,
400
- module import or destination from job payloads.
401
-
402
- Store minimal encrypted-at-rest payloads where they contain personal data or
403
- short-lived tokens, with strict access and retention. Do not log message bodies,
404
- password-reset tokens or verification codes. Expired tokens must not be resent;
405
- cancel superseded notices by domain revision. Auth integration must preserve
406
- its existing security semantics and needs dedicated regression review; forms
407
- and billing should not force an immediate auth sender migration.
408
-
409
- Expose queue age, retry/dead-letter counts, provider errors, bounce/complaint
410
- rates and worker heartbeat. Alert through an independent operator channel when
411
- the notification transport is down. Define retention and purge for payloads,
412
- metadata and backups. Recovery must not replay old external messages merely
413
- because a backup was restored: default to a paused dispatch state and reconcile
414
- provider IDs/outbox watermarks before an operator resumes it.
415
-
416
- Reuse leasing/retry primitives for scheduled publication, but keep publication
417
- and email as distinct job types and queues. Cancellation uses expected revisions;
418
- workers recheck permission/policy and current domain state before irreversible
419
- effects. For external sends already in flight, cancellation is best effort and
420
- must report the race. Email outage cannot starve entitlement reconciliation or
421
- site publication.
422
-
423
- ## Legal documents and compliance evidence: urlcode-legal
424
-
425
- `urlcode-legal` is an Apache-2.0 standard library and optional extension, not a
426
- law firm, certification product or substitute for advice from qualified counsel.
427
- It supplies a safe structure for operator-reviewed documents and evidence. The
428
- operator chooses applicable jurisdictions, completes the business facts, accepts
429
- the reviewed versions and owns the resulting promises. Packages must never label
430
- a deployment compliant merely because this library is installed.
431
-
432
- The library owns versioned document definitions, typed variables, clause IDs,
433
- effective/published/retired states, locale variants, changelogs and immutable
434
- rendered snapshots. It ships conservative starter documents and questionnaires,
435
- with source citations and a review-required marker. It rejects unresolved
436
- placeholders and conflicting facts before publication. Templates cannot execute
437
- code, name infrastructure, grant capabilities or import arbitrary clauses from
438
- the network. Project overrides are explicit, diffable and survive package
439
- upgrades; upstream template changes never silently alter accepted terms.
440
-
441
- The first document set is:
442
-
443
- - Terms of service, privacy notice, cookie/optional-storage notice and acceptable
444
- use policy, with operator identity, contacts, governing-law choices and dates.
445
- - Subscription, cancellation and refund terms consumed by billing; product and
446
- price promises remain operator-reviewed business configuration.
447
- - Accessibility statement, security/trust page and public subprocessor list,
448
- generated from evidence and operator declarations rather than unsupported
449
- claims. A data-processing addendum pack records controller/processor roles,
450
- subprocessors, transfer mechanism fields and security schedule for counsel.
451
- - Copyright/takedown and abuse-reporting materials used by CMS, short and support.
452
- Jurisdiction-specific statutory agent/registration steps remain operator work.
453
-
454
- CMS is the preferred publisher, but not a dependency: standalone legal serves
455
- immutable pages under `/legal/*`, a manifest and machine-readable current-version
456
- metadata. With CMS, legal documents are a protected content type whose approved
457
- snapshot is included in the public artifact; CMS editors cannot change a signed
458
- legal version without legal-publisher permission. Auth records acceptance of the
459
- exact terms/privacy version when acceptance is actually required. A privacy
460
- notice view is not stored as consent. Forms records the notice and consent-purpose
461
- versions shown; billing records checkout/subscription terms; support and short
462
- link to the current privacy/AUP/takedown versions. Notifications distinguish
463
- transactional messages from marketing preferences and apply the relevant footer.
464
-
465
- Acceptance records contain principal or stable subject, document/version digest,
466
- locale, presented-at/accepted-at time, purpose, product surface and evidence
467
- source. They never store raw passwords, payment data or a copy of every page.
468
- Anonymous acceptance uses a bounded receipt only when the workflow needs it;
469
- cookie banners must not manufacture consent for required storage. Withdrawal and
470
- supersession are explicit events. Material-change notices use the durable
471
- notification service but publication does not depend on delivery success.
472
-
473
- ### Compliance profiles and shared controls
474
-
475
- The suite maintains a versioned obligations matrix with jurisdiction, trigger,
476
- organizational role, data/process scope, responsible owner, required control,
477
- evidence and review date. A profile enables validations and evidence collection;
478
- it does not decide whether a law applies. Applicability and legal text require
479
- operator/counsel approval. Laws and assurance frameworks remain distinct:
480
-
481
- | Profile | Initial product posture and evidence |
482
- |---|---|
483
- | [GDPR](https://commission.europa.eu/law/law-topic/data-protection/information-business-and-organisations/principles-gdpr_en) and UK GDPR-ready privacy controls | Purpose/legal-basis inventory, minimization, retention, access/correction/export/deletion workflows, processor/subprocessor register, transfer fields, security and accountability evidence. Controller/processor roles are declared per deployment |
484
- | [CCPA/CPRA](https://www.oag.ca.gov/privacy/ccpa) | Notice-at-collection mapping, know/correct/delete requests, sale/share and sensitive-data declarations, non-discrimination evidence and Global Privacy Control handling when the operator's practices require it |
485
- | [COPPA](https://www.ftc.gov/business-guidance/resources/complying-coppa-frequently-asked-questions) | Default profile is not child-directed and does not knowingly collect personal information from children under 13. Known under-13 collection fails closed. Child-directed service, age screening and verifiable parental consent are unsupported until a separately reviewed profile, deletion/parent rights, data practices and live evidence exist |
486
- | [CAN-SPAM](https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business) | Classify transactional versus commercial mail, truthful sender/subject, postal-address field, working unsubscribe, durable suppression and timely opt-out processing. Other countries' marketing/consent rules need their own profiles |
487
- | [PCI DSS 4.0.1](https://www.pcisecuritystandards.org/document_library/) | Use provider-hosted checkout/portal and never store card data. Maintain data-flow and integration inventory, protect webhook/API credentials and determine the actual merchant validation scope with the acquirer/QSA; hosted payments reduce scope but do not prove compliance |
488
- | [WCAG 2.2 AA](https://www.w3.org/TR/wcag/) and applicable accessibility law | Shared UI conformance target, automated and manual keyboard/screen-reader/contrast checks, accessible legal/support paths and a public limitations/contact process. An accessibility statement is not conformance evidence |
489
- | [SOC 2](https://www.aicpa-cima.com/topic/audit-assurance/audit-and-assurance-greater-than-soc-2) readiness | Control owners/evidence for applicable Trust Services Criteria, change/access/incident/vendor/availability processes and evidence periods. Only an independent CPA examination produces a SOC 2 report |
490
- | [ISO/IEC 27001:2022](https://www.iso.org/standard/27001) readiness | ISMS scope, risk assessment/treatment, policies, control ownership, internal review and continual improvement. Only an accredited certification process justifies a certification claim |
491
- | HIPAA decision gate | Unsupported by default. HIPAA applies to covered entities and business associates in defined circumstances; supporting ePHI requires a separate architecture/threat model, contracts/BAAs, safeguards, breach process, vendor commitments and review before any claim. See [HHS applicability guidance](https://www.hhs.gov/hipaa/for-professionals/covered-entities/index.html) |
492
-
493
- Common controls live in narrow modules rather than one compliance database:
494
-
495
- - A data inventory contract makes each app declare data categories, purposes,
496
- subjects, stores, recipients/subprocessors, residency, retention and deletion.
497
- Legal composes the registry; it cannot read or mutate app tables directly.
498
- - A privacy-request orchestrator plans access, correction, export, deletion and
499
- restriction across registered adapters. Each app authorizes and executes its
500
- own operation with idempotency and audit. Dry-run reports exclusions and legal
501
- holds; partial completion remains visible and retryable.
502
- - A consent/preference ledger records purpose-specific decisions and provenance.
503
- It is separate from terms acceptance and from required transactional delivery.
504
- Apps query the smallest decision needed and fail safely when evidence is stale.
505
- - Retention policies are operator-approved and app-enforced, covering primary
506
- data, indexes, blobs, audit, delivery payloads and backup expiry. Deletion does
507
- not make unverifiable promises about already-expired or legally retained data.
508
- - The evidence exporter produces a signed manifest of versions, controls, tests,
509
- owners, exceptions and collection time. It excludes secrets and customer data
510
- by default. Evidence supports assessment; it is not a certification badge.
511
- - Incident and breach runbooks preserve facts, affected-data/app scope, decision
512
- ownership and notification timelines without hard-coding one jurisdiction's
513
- deadline into core. External notices require authorized human/legal review.
514
-
515
- The admin module provides document drafts/diffs/approvals, current-version and
516
- acceptance reports, data inventory, processors, request workflow, exceptions and
517
- evidence export. Legal publishing, compliance administration, privacy-request
518
- execution and viewing customer data are separate permissions. Without auth/admin,
519
- the same operations remain available through a local operator CLI/API. Agents can
520
- draft changes and assemble evidence; they cannot approve legal language, declare
521
- applicability, accept contracts, notify regulators or claim certification.
522
-
523
- Release acceptance includes counsel review of production legal text and product
524
- facts, but counsel review does not validate technical controls. Conversely,
525
- passing tests does not validate the promises in legal documents. Every release
526
- checks that product behavior, data inventory, subprocessors, retention and public
527
- documents agree; a mismatch blocks the suite release until resolved or explicitly
528
- documented as an approved exception.
529
-
530
- ## Agent-first contract
531
-
532
- Every meaningful UI operation uses the same domain service as the API and CLI.
533
- Publish machine-readable schemas, API descriptions, capability discovery,
534
- `llms.txt`, versioned examples and executable fixtures in each package.
535
-
536
- Proposed commands such as `urlcode-cms plan`, `apply`, `publish`, `export`,
537
- `doctor` and `urlcode-support tickets reply` are design targets, not working CLI
538
- commands today. Return structured JSON, stable IDs, error codes, pagination,
539
- revision conflicts and operation IDs. Mutations accept expected revisions and
540
- idempotency keys. Plans show diffs, affected URLs, visibility and outgoing
541
- communications. Applying a stale plan fails rather than overwriting another
542
- editor. Support replies, deletions and publishing require their own explicit
543
- capabilities; an operator may require review before external communication.
544
-
545
- Keep core MCP read-only. Each app can supply a separate opt-in write MCP adapter
546
- backed by scoped operator authority; it cannot self-grant from project files.
547
- Agents may draft, classify and suggest. Content/tickets are untrusted data, not
548
- instructions authorizing tool calls. Scope retrieval by the acting principal;
549
- record human/agent attribution and require policy checks again at commit time.
550
- AI providers are optional adapters with explicit data permissions and budgets.
551
- No AI account should be necessary to run or edit the suite.
552
-
553
- ## UI and admin composition
554
-
555
- Use urlcode-ui's tokens, template/view-model contracts, locale handling,
556
- light/dark themes, keyboard patterns, empty states and error conventions.
557
- Build shared table/filter, editor, revision-diff, media-picker and ticket-thread
558
- components there only when more than one application needs them. Tailwind
559
- styles ship compiled; no runtime CDN requirement or second theme system.
560
- Current UI docs distinguish compiled primitive CSS from handwritten kit CSS;
561
- consolidation should be a UI issue, not an assumed completed migration.
562
-
563
- Admin should accept explicit trusted module registrations containing stable IDs,
564
- labels, navigation, permissions, screens, actions and health observations.
565
- The application owns business operations; admin owns the console shell and
566
- routing. A proposed `/admin/cms` screen is dispatched within admin's one mount,
567
- not registered as a conflicting nested core extension. Reject module collisions
568
- and incompatible view-model versions. A hidden sidebar item is not authorization.
569
- A CMS-only operator does not acquire identity-admin rights; support staff cannot
570
- impersonate users merely because they can read tickets.
571
-
572
- ## Implementation backlog: owners, dependencies and acceptance
573
-
574
- These are proposed work items, not filed GitHub issues. Search the tracker for
575
- existing work before filing. IDs below are local planning IDs. Priorities refer
576
- to their dependent dogfood milestone, not a requirement to finish every shared
577
- abstraction before launching a public page. Each implementation belongs in its
578
- own repository/PR, with compatibility and executable acceptance evidence.
579
-
580
- ### SUITE-01 — composition contract and admin modules (P0; admin/auth/apps)
581
-
582
- Current admin exports offer no generic application-module registry. Add explicit
583
- operator-installed module descriptors for namespace, navigation, view-model
584
- version, screens, actions, permissions and health. Admin owns `/admin/*`; it
585
- internally dispatches `/admin/cms`, `/admin/forms`, `/admin/short`,
586
- `/admin/billing`, `/admin/support` and blog views. No nested competing core mounts.
587
- An application service exists once and is shared by its CLI/API/admin adapters.
588
- Keep the existing admin → auth dependency; no alternative identity system.
589
-
590
- Accept when two real modules coexist, registrations fail atomically on ID/path
591
- collision, direct requests enforce permission even without navigation, writes
592
- require CSRF/fresh auth as appropriate, revoked sessions stop working and shared
593
- services close exactly once. Repeat with all seven modules before suite release.
594
- Start with forms and short; richer editor components must not block this contract.
595
- Depends on existing core extensions; no product-specific core imports.
596
-
597
- ### SUITE-02 — shared scaffolding and machine-readable capability plan (P0 preset; P1 core enhancement)
598
-
599
- Core already merges scaffold fragments and refuses collisions. Extend only the
600
- missing pieces: typed dependency/contribution metadata, deterministic ordering,
601
- one owner per shared service, explicit project-content files and preflight
602
- compatibility checks. Scaffold files currently cannot be written inside the
603
- project. A package-specific initializer can create a complete reviewed layout
604
- until a generic contribution contract exists; keep it covered by tests.
605
-
606
- Accept with order-independent supported presets, safe normalized paths, no
607
- symlink escape, no partially written project after preflight failure and an
608
- inspectable plan containing mounts, packages, services, environment requirements
609
- and target limitations. Admin without auth fails before writing. Blog's CMS
610
- dependency is resolved once. Generic core machinery never downloads/activates
611
- packages named by untrusted YAML. Publish a tested peer/version matrix rather
612
- than relying on unconstrained latest versions. Depends on SUITE-01 descriptors.
613
-
614
- ### SUITE-03 — permissions, subjects and entitlement integration (P0 before paid access)
615
-
616
- Auth owns principals/sessions and permission checks; applications own resource
617
- ownership; billing owns commercial grants. Specify a narrow host-bound adapter
618
- carrying verified subject ID, permissions, authentication freshness, request ID
619
- and optional billing subject. Do not pass raw credentials into guests or infer
620
- identity from client headers. Standalone operator operations use explicit local
621
- operator authority, not a new browser login implementation.
622
-
623
- Accept when cross-account resource IDs fail, a paid member cannot administer
624
- other members, form emails do not auto-link accounts, cancellation is reflected
625
- within the documented entitlement staleness budget, and permission/entitlement
626
- checks apply to CLI/API/MCP/admin equally. Include revoked sessions, impersonation
627
- restrictions and concurrent quota reservations. Required for billing and support;
628
- public file-mode CMS does not wait for it.
629
-
630
- ### SUITE-04 — durable outbox, inbox and notification recovery (P0 before external notifications)
631
-
632
- Implement the notification design above first against forms, then billing and
633
- support. App writes and outbox insertion share one transaction. Provide event
634
- schemas, unique consumer keys, bounded leases, backoff/expiry, dead-letter tools,
635
- provider status and dispatch-paused restore. Separate reliability from rendering.
636
- Do not describe existing best-effort auth hooks or core signals as durable.
637
-
638
- Accept fault injection before/after commit, duplicate relay, restart while leased,
639
- provider timeout after acceptance, bounce replay, expired token and poisoned job.
640
- Every acknowledged source event must be either pending, completed or explicitly
641
- failed/suppressed; measure delivery ambiguity rather than hiding it. An email
642
- outage cannot erase a form or undo a billing entitlement. Depends on forms' first
643
- transactional slice; freeze shared API only after a second consumer validates it.
644
-
645
- ### SUITE-05 — publication artifacts and activation (P0 CMS adapter; P1 core API)
646
-
647
- Current `serve` snapshots assets; extension responses default to no-store. CMS
648
- must build only the approved public revision into a complete artifact, then use
649
- a trusted deployment adapter to validate/activate it. Store immutable manifest,
650
- content digest, deployment ID, state and previous release. Explicitly review any
651
- changed route/policy revision; a content job cannot renew its own authority.
652
- The first adapter may stage and restart a public server; do not wait for hot
653
- activation or weaken extension caching. Generic atomic activation/reporting is
654
- a separate core proposal after this adapter demonstrates the need.
655
-
656
- Accept a failed render/validation/start leaves the old site available; concurrent
657
- publishes serialize; lost acknowledgement reconciles by release ID; drafts never
658
- appear in public assets/search/feeds; rollback restores a coherent release.
659
- Separate static-public delivery from protected content. Test deep-link routes
660
- alongside extension mounts, excluding `/account`, `/admin`, `/forms`, billing and
661
- support namespaces. Depends on CMS compiler; managed/scheduled publishing also
662
- uses SUITE-04 job primitives.
663
-
664
- ### SUITE-06 — shared UI and bounded media (P0 app acceptance; incremental UI work)
665
-
666
- Add accessible tables/forms/statuses first, then the Markdown editor, media picker
667
- and revision diff, then ticket thread. Register view-model samples and catalogues;
668
- compile the shared kit stylesheet with the agreed Tailwind toolchain while
669
- preserving tokens/overrides. Keep vendor notices and review CSP-safe script use.
670
- Core's 1 MiB extension response bound stays; object-storage uploads are explicit
671
- operator adapters with quarantine, authorization, expiry and size limits.
672
-
673
- Accept real rendered screens plus keyboard, light/dark, narrow-screen and error
674
- states. Check labels/focus, escaping, stale form versions, localization fallback
675
- and direct unauthorized requests. Verify upload access before and after publish,
676
- unpublish and deletion; no private assets through public URLs. File-mode CMS and
677
- forms without attachments can ship before the media adapter.
678
-
679
- ### SUITE-07 — urlcode-short migration and abuse operations (P0 short release)
680
-
681
- Apply the agreed rename/release migration above. Replace the demo's bespoke HTTP
682
- wrapper with current extension composition where feasible. Retain core link
683
- semantics, expired/disabled behavior and optimistic writes; add an app-owned
684
- ownership model with recoverable metadata/link creation. Keep anonymous creation
685
- bounded and configurable. Anonymous abuse must not degrade existing redirects.
686
-
687
- Accept old-store upgrade, unchanged codes/URLs, expiry/takedown, backup restoration,
688
- account isolation, retry-safe creation and aggregate analytics drop behavior.
689
- Document destination rules, retention and takedown workflow. Analytics is never
690
- required for redirects or used as a billing ledger. Depends on SUITE-01 for the
691
- console; anonymous mode remains independently useful.
692
-
693
- ### SUITE-08 — release truth and executable composition matrix (P0 every release; core/apps)
694
-
695
- Reconcile stale FRAMEWORK.md claims about unpublished siblings and adapter
696
- support against actual released revisions. `src/capabilities.ts` admits generic
697
- extensions on Node/AWS/Vercel, but application storage compatibility is separate.
698
- Update llms resources with executable examples, current package names and explicit
699
- unsupported behavior; do not make this proposal look like shipped syntax.
700
-
701
- Run installed tarballs in standalone, auth-only and auth+admin modes, plus
702
- admin-only rejection, removing dependencies, stale pins, duplicate mounts,
703
- missing secrets/adapters, package version mismatch and extension order changes.
704
- Adding/removing billing must not bypass configured entitlements. Core remains
705
- free of app imports. Include one synthetic full journey fixture and regenerate
706
- reference/agent docs whenever implemented contracts change.
707
-
708
- ### SUITE-09 — billing provider reconciliation (P0 before charging; billing)
709
-
710
- Implement verified durable ingress, retry-safe checkout, per-subject serialized
711
- reconciliation, entitlement projection, inspection and dry-run repair. Bind
712
- provider account/environment/version explicitly. Keep local state recoverable
713
- from the provider and never interpret a redirect as proof of payment.
714
-
715
- Accept duplicate/out-of-order/missing events, payment failure, cancel-now versus
716
- period-end, refund/dispute policy, provider outage, concurrent quota writes and
717
- restore followed by reconciliation. Require test-mode end-to-end evidence before
718
- an explicitly authorized live-money smoke test. Depends on SUITE-03/04; public
719
- pricing pages can ship earlier without accepting payment.
720
-
721
- ### SUITE-10 — suite deployment, recovery and feedback (P0 dogfood promotion; apps/operations)
722
-
723
- Ship pinned standalone/suite manifests, private durable data directories,
724
- non-root containers, health/readiness, worker lifecycle and versioned migration
725
- plans. Each store has one migration owner; starting two processes cannot run
726
- conflicting migrations. Back up content, metadata, files, keys and the release
727
- manifest coherently. Restore into an isolated host with outbound dispatch paused;
728
- reconcile billing before enabling paid operations and review notifications before
729
- resuming them. A shared host is not permission to read another app's tables.
730
-
731
- Accept fresh install, upgrade from the preceding dogfood version, backup restore,
732
- disk-full, process kill, mail/provider outage and rollback according to schema
733
- compatibility. Record latency/error/queue-age baselines, recovery timings and
734
- unresolved defects. Each milestone ships an operator runbook, a rollback
735
- path and the required learning report defined below. Dogfood friction becomes a minimal reproducible upstream issue; retain
736
- business policy in the app rather than forking core.
737
-
738
- ### SUITE-11 — legal library and compliance evidence (P0 before collecting dogfood personal data)
739
-
740
- Create `urlcode-legal` with typed/versioned documents, immutable publication,
741
- operator questionnaires, acceptance/consent evidence and the data-inventory and
742
- privacy-request adapter contracts above. Seed only reviewed baseline templates;
743
- mark jurisdiction/applicability decisions unresolved until the operator accepts
744
- them. Integrate CMS, forms and auth first, then billing, notifications, short and
745
- support. Keep organizational controls and evidence honest: readiness mappings
746
- cannot emit certification badges or compliance claims.
747
-
748
- Accept a clean standalone legal-center install and CMS publication; unresolved
749
- variables block release; material versions and acceptance are reproducible after
750
- restore; a privacy request plans and executes across synthetic app adapters with
751
- partial failure/retry; withdrawal affects the right purpose without disabling
752
- required transactional messages; retention and backup limitations appear in the
753
- evidence report. Verify a changed subprocessor/data purpose causes an explicit
754
- document/inventory review. Run accessibility/manual checks on every public legal
755
- and request path. Require counsel sign-off for the dogfood documents and a named
756
- control owner/review date for every enabled compliance profile.
757
-
758
- The genuine core work is SUITE-02's generic contribution support, the optional
759
- SUITE-05 activation API, and SUITE-08 documentation/conformance. Admin modules,
760
- billing, legal/compliance content, notification durability, domain storage and
761
- shared UI belong to their respective repositories. Do not make core a CMS, queue
762
- server, legal rules engine or payment engine.
763
-
764
- ## Instant deployment and production acceptance
765
-
766
- “Instant deployable” means a reproducible preset, not a demo labeled production.
767
- Ship a standalone npm launcher, a verified container and a compose example for
768
- each app; also ship a suite preset sharing one explicit host and admin shell.
769
- Generate private operator configuration outside the route project, use durable
770
- volumes and refuse public staff mode without identity/secrets/origin setup.
771
- Health/readiness reports storage, migrations, queue backlog and required adapters.
772
- A minimal public CMS/blog export can deploy as static files; the operational suite
773
- initially targets Node plus patched SQLite and a durable volume. AWS/Vercel
774
- extension contracts alone do not make local SQLite apps serverless-ready.
775
-
776
- Before a production tag, require recorded evidence for:
777
-
778
- - Fresh tarball/container installation, all supported composition presets,
779
- non-root operation, bootstrap, HTTPS ingress, graceful shutdown and restart.
780
- - Schema migrations with preflight backup, interrupted migration recovery,
781
- concurrent-update conflicts, bounded jobs and idempotent replay.
782
- - Complete backup/restore of metadata, Markdown blobs, attachments and keys;
783
- restore drill on a fresh host with measured recovery time/data loss. A DB-only
784
- backup is insufficient. Rollback must account for schema compatibility.
785
- - Threat-model and security review of content rendering, previews, uploads,
786
- object authorization, CSRF, mail ingestion, SSRF and cross-app permissions.
787
- Automated tests do not substitute for independent review.
788
- - Accessibility/browser/mobile checks, load/soak results with published hardware,
789
- data sizes and latency/error budgets, disk-full and provider-outage exercises.
790
- - Retention/export/deletion controls, redacted logs and metrics, abuse/takedown
791
- procedures, staff audit and least-privilege deployment examples.
792
- - Versioned legal documents match observed product/data/subprocessor behavior;
793
- applicable privacy/marketing/children/payment/accessibility profiles have named
794
- owners, evidence and exceptions. Counsel reviews production-facing text and
795
- applicability; independent assessors own any SOC 2/ISO/PCI certification claim.
796
- - Apache-2.0 license/notices, contributor/security policy, protected main,
797
- reviewed PRs, dependency/SBOM checks, supported-version policy and tag-driven
798
- publishing with provenance. No dist committed and no new CLA/DCO.
799
-
800
- Run each repo's verification and package smoke tests, then suite integration CI.
801
- Use alpha releases until the deployment and recovery gates are demonstrated.
802
- No runtime implementation, deployment or production validation occurred in this
803
- spike; no such readiness is inferred from existing status files.
804
-
805
- ## Build order for impact: dogfood before breadth
806
-
807
- The first customer is our own business. Ship small complete journeys and operate
808
- them before expanding feature breadth. These are ordered delivery milestones,
809
- not calendar estimates; only measured implementation work should set dates.
810
- Public site delivery is the first useful outcome. Reliability work begins with
811
- its first real form, not after support and billing depend on email.
812
-
813
- | Order | Deliverable and dependencies | What we use ourselves | Evidence required to advance |
814
- |---|---|---|---|
815
- | 0 | Release baseline and naming: SUITE-08 inventory, `urlcode-short` rename plan/execution, SUITE-01 minimal descriptors, SUITE-10 deployment skeleton | Install an existing auth/admin app from pinned artifacts and inspect health | Package/repo identities verified; admin-only rejected; reproducible dev/staging bootstrap; current capability matrix |
816
- | 1 | CMS file-mode vertical slice; SUITE-05 restart/deploy adapter | Publish our home and product pages from Markdown | Agent plan/validate/publish; human preview; no draft leakage; failed deploy retains previous site; rollback demonstrated |
817
- | 2 | Legal baseline; SUITE-11 standalone/CMS publishing, data inventory and reviewed dogfood documents | Publish terms, privacy, accessibility, security, AUP and processor pages before accepting personal data | No unresolved variables; product/data/docs agree; counsel review recorded; public pages accessible; no certification claims |
818
- | 3 | Forms + first notification slice; SUITE-01 first module and SUITE-04 local/production sender adapter | Capture contact and early-access requests, triage them in admin, receive delivery status | Acknowledged submissions survive restart/email outage; duplicate POST produces one submission; notice/consent/export/delete work; notification failure is visible |
819
- | 4 | `urlcode-short` extension/standalone migration; SUITE-07 and second admin module | Use our own stable short links/QR codes in the site and launch communications | Existing links survive upgrade; ownership/takedown/AUP work; anonymous mode is bounded; clean published package installation; redirect availability survives analytics failure |
820
- | 5 | Billing test-mode vertical slice; SUITE-03/04/09 plus legal subscription/refund terms | Exercise one paid offering, self-service portal and entitlement enforcement in our own app | Verified payment grants access, cancellation revokes it per policy; terms version recorded; out-of-order/missed webhook repair; no role escalation; provider outage verified |
821
- | 6 | Support web+email inbox; reuse notification worker and auth/admin/legal modules | Handle our own inbound questions and test customer issues | Intake/threading/assignment; private notes stay private; reply retry/ambiguity visible; restore does not resend old replies; customer isolation and retention agree with notice |
822
- | 7 | Controlled paid dogfood promotion; SUITE-10 recovery/security/operations and compliance-profile gates | Operate the complete site → lead → account → checkout → entitled action → support journey | Authorized live-provider checks, privacy request, restore drill, least-privilege review and monitoring; no critical unresolved journey or legal/product mismatch; free path useful |
823
- | 8 | Managed CMS editing + blog on CMS + support knowledge base | Publish release notes and tutorials; edit pages in admin; link help articles in support | Concurrent edit conflicts; revision diff/review/restore; scheduling survives restart; RSS/sitemap/search/legal references agree on published revisions |
824
- | 9 | Production suite release and broader onboarding | A fresh operator installs an individual app or the full suite without our assistance | Whole-suite journey and failure matrix, composition/upgrade/package tests, learning reports, legal/control evidence, deployment/accessibility/security/recovery evidence and published compatibility policy |
825
-
826
- Why this sequence: CMS establishes the public surface; legal records the promises
827
- and data practices before forms captures demand;
828
- short reuses an existing implementation and proves a second independent admin
829
- module; billing tests the revenue path; support is ready before paid promotion.
830
- Managed editing/blog follow once acquisition and customer service work. Do not
831
- wait for a visual page builder, a CRM or every content workflow to dogfood.
832
- Phases 1–6 can be internal alphas; they are not declarations of production safety.
833
- If short migration expands substantially, preserve existing redirect service and
834
- move optional analytics after the first billing/support journey.
835
-
836
- A practical dependency map:
837
-
838
- ```text
839
- core + ui + auth -> admin -> app management modules
840
- core + ui -> cms file mode -> public site
841
- legal + app data-inventory adapters -> public documents / privacy operations
842
- forms -> durable outbox -> notifications -> billing notices / support replies
843
- core LinkStore -> short (auth/admin optional)
844
- auth subject adapter + billing reconciliation -> enforced paid features
845
- cms + durable publication jobs -> blog and optional support knowledge base
846
- all app artifacts + recovery evidence -> suite production release
847
- ```
848
-
849
- Notification delivery is not a prerequisite for entitlement decisions, redirect
850
- resolution or serving published pages. Public CMS/short/forms remain useful
851
- without auth/admin; private customer features never silently degrade to public.
852
- Blog requires CMS, support does not. Paid app access may require auth even though
853
- the standalone billing service can manage operator-bound customer subjects.
854
-
855
- ### Dogfood acceptance and feedback loop
856
-
857
- Keep synthetic fixtures in public repositories; production contacts, messages,
858
- receipts, keys and business-specific configuration stay in operator storage.
859
- Do not commit dogfood data to reproduce a defect. Record each milestone's exact
860
- package versions, app revision, image digest, deploy target and known limits.
861
-
862
- | Journey | Human and agent checks | Operational measure |
863
- |---|---|---|
864
- | Author → publish → rollback | UI/CLI report the same content revision; stale plans fail | Time to publish, failed activations, rollback time |
865
- | Legal review → publish → evidence | Agent draft and human approval remain distinct; product facts and public versions agree | Unresolved variables, stale documents, review age and approved exceptions |
866
- | Visitor → form → follow-up | Same receipt on retry; staff export/reply scopes enforced | Accepted submissions, oldest unprocessed lead, queue age, terminal delivery failures |
867
- | Short link → redirect → takedown | Anonymous/account paths obey limits; disabled link no longer resolves | Redirect latency/errors, blocked creation, takedown completion time |
868
- | Checkout → paid action → cancellation | No access from success URL alone; API/UI decisions agree | Webhook lag, reconciliation mismatches, time to grant/revoke |
869
- | Ticket → staff reply → customer response | Private notes never leave staff scope; duplicates don't create a second ticket | Oldest unanswered ticket, failed sends, response time |
870
- | Restart/restore → resume | Outbound dispatch paused, provider state reconciled, old content available | Measured restore time/data loss and replay/duplication incidents |
871
-
872
- Proposed initial internal targets, to measure and revise rather than advertise
873
- as an SLA: reconcile acknowledged billing events within 60 seconds under normal
874
- load; alert on notification queue age over five minutes; perform a fresh-host
875
- restore before every milestone that introduces a new persistent store. Validate
876
- bounds with the actual sender/provider and record exceptions. Zero tolerated
877
- acceptance failures for acknowledged-data loss, unauthorized access, draft/private
878
- note leakage, or double effects from locally duplicated requests/events. External
879
- provider send ambiguity is a separately measured limitation, not proof of
880
- exactly-once mail. Independent alerts must work when email is unavailable.
881
-
882
- At each milestone, record friction with steps, expected/actual behavior, scope,
883
- workaround and owner. Classify it as application UX, shared UI, admin composition,
884
- core contract, provider operation or documentation. Fix only the smallest shared
885
- contract needed by a real consumer; exercise it in a second consumer before
886
- calling it stable. Convert the reproducible records into linked implementation
887
- issues/PRs and close them only with evidence, not just documentation edits.
888
-
889
- ## Required learning and modular extraction at every milestone
890
-
891
- Dogfooding must improve the framework as well as the applications. Each milestone
892
- ships a short learning report alongside its acceptance evidence, even when the
893
- conclusion is that no core change is needed. Record:
894
-
895
- - The real human/agent task, package revisions and a synthetic reproduction.
896
- - What core and existing modules supplied, what the app had to duplicate, and
897
- where contracts or documentation caused friction.
898
- - Measured cost where available: setup steps, failed attempts, latency, recovery
899
- time or duplicated behavior. Do not invent productivity percentages.
900
- - Proposed owner: app, shared module, admin, UI, core, documentation or operations;
901
- alternatives considered and why the smallest proposed change belongs there.
902
- - A linked issue/PR, regression fixture, compatibility impact and outcome; retain
903
- unresolved findings with an owner and the next milestone that needs them.
904
-
905
- Public reports contain sanitized evidence only. Business-specific policy and
906
- customer data stay outside public repositories. Before the next milestone,
907
- review unresolved findings, implement blockers, and assign useful non-blocking
908
- improvements rather than letting them disappear into a retrospective.
909
-
910
- ### Principles remain acceptance constraints
911
-
912
- A core improvement must preserve declarative portable route behavior, external
913
- operator configuration, explicit capabilities and revision-pinned grants, WASM
914
- isolation for untrusted application code, strict validation and target refusal,
915
- and a useful free/self-hosted runtime. Core must not import suite applications,
916
- auto-load privileged project modules, execute guests in Node, move provider
917
- settings into route YAML, or weaken authorization/caching boundaries to make a
918
- particular app easier. Keep domain state and business workflows outside core.
919
-
920
- Every proposed core change includes a principles-impact note and executable
921
- conformance evidence, with a small non-suite consumer or fixture demonstrating
922
- that the contract is generic. If the problem is only app policy, fix the app.
923
- If a shared library solves it without a runtime change, prefer that boundary.
924
- Generic runtime improvements must land upstream through reviewed PRs; do not
925
- maintain a private behavior fork just to make the dogfood deployment work.
926
-
927
- ### Extract common behavior into modules, following urlcode-ui
928
-
929
- Treat urlcode-ui as the model: a focused, versioned package with a clear contract
930
- consumed by independent applications. Start with a concrete implementation,
931
- identify a second real consumer, compare their semantics, then extract the
932
- smallest shared behavior. Avoid both copy-and-paste implementations and a
933
- speculative all-purpose framework. Planned shared infrastructure may start with
934
- one consumer, but must prove a second before its public contract is stabilized.
935
-
936
- | Candidate | Evidence to seek | Intended boundary |
937
- |---|---|---|
938
- | Tables, forms, theme, locale, safe view rendering | Same interaction in two app screens | urlcode-ui; app-specific screens stay in their apps |
939
- | Admin registration/navigation | Two independent apps in the same console | urlcode-admin; domain mutations stay in app services |
940
- | Outbox, inbox, delivery, leasing | Forms plus billing/support need the same delivery guarantees | Shared operator package; no arbitrary guest job execution |
941
- | Media validation/storage | CMS and support need compatible upload/security behavior | Narrow storage/media adapter; public and private access rules remain explicit |
942
- | Publication and content revisions | CMS, blog and help articles share content semantics | CMS exports; blog/support consume rather than fork the engine |
943
- | Documents, inventories and privacy operations | Every data-handling app needs consistent disclosures and evidence contracts | urlcode-legal; each app retains its own data, authorization and retention execution |
944
- | Permission/entitlement decisions | Multiple services require the same verified decision shape | Auth/billing adapters; apps retain resource ownership and business policy |
945
- | Activation/scaffold primitives | Independent consumers hit the same runtime limitation | Generic core API only when the host/runtime must enforce it |
946
-
947
- Each extraction needs an owner, versioned public exports, narrow dependencies,
948
- contract tests, migration notes and clean tarball installation in both consumers.
949
- Move consumers onto the shared implementation and remove superseded copies;
950
- verify behavior before/after, including failures and authorization. Reject cyclic
951
- dependencies and a catch-all utilities package. Avoid a shared database schema
952
- that lets one module silently mutate another module's state. Keep apps usable
953
- standalone with explicit adapters and without requiring the whole suite.
954
-
955
- ## Whole-suite testing is a release gate
956
-
957
- Passing each repository's tests is necessary but insufficient. Build the suite
958
- harness incrementally from the first two integrated apps and run the complete
959
- suite before final release. The final gate covers core, UI, auth, admin, CMS,
960
- blog, short, forms, billing, legal and notification workers plus support in one
961
- pinned, production-shaped deployment. It must not rely on unpublished sibling
962
- source imports or developer symlinks to pass.
963
-
964
- Maintain a versioned integration harness and suite manifest under a named release
965
- owner. Its eventual repository location is a delivery choice, not a new core
966
- application dependency. Install candidate tarballs/container images into a clean
967
- environment; record exact digests, test results and supported combinations.
968
- Use deterministic fake providers for CI, then separate provider test-mode and
969
- explicitly authorized live deployment checks. Fakes are not delivery evidence.
970
-
971
- The required end-to-end journey is:
972
-
973
- 1. An agent drafts a page and post; an authorized publisher previews and publishes
974
- them. Drafts remain private; public pages, feed, sitemap and search agree.
975
- 2. An authorized legal publisher approves the documents and data inventory;
976
- public versions match form, account, billing and support behavior. An agent
977
- may prepare the diff but cannot approve it or claim certification.
978
- 3. A visitor follows a short link to the site and submits a form. The submission
979
- is durable, appears in admin, and produces a traceable notification intent.
980
- 4. A verified customer signs in, completes test checkout and gains only the paid
981
- feature entitlement. A second account cannot access their resources.
982
- 5. The customer opens a ticket; staff triages it, adds a private note and replies
983
- with a published knowledge-base link. Only the public reply reaches them.
984
- 6. The customer exercises an access/export request and changes a marketing
985
- preference; app adapters produce a coherent result while required transactional
986
- messages and approved retention exceptions remain explicit.
987
- 7. Cancellation or payment failure changes access according to policy while
988
- preserving account, support and export access. Session revocation takes effect.
989
- 8. Upgrade and restore the entire deployment, reconcile billing and resume workers
990
- deliberately. Published content and short URLs survive; private data stays
991
- private and acknowledged work is accounted for without blind resend.
992
-
993
- Run the following system-level matrices in addition to this happy path:
994
-
995
- | Area | Required evidence |
996
- |---|---|
997
- | Optional modules | Each app standalone, auth-only and auth+admin; admin-only rejection; blog without CMS rejection; legal standalone and with CMS; support without CMS; safe removal of optional modules |
998
- | Shared host | Mount/service collisions, dependency ordering, migration ownership, startup rollback, one-time close, shared UI/CSP/cookies and authorization isolation |
999
- | Cross-app writes | Duplicate requests/events, concurrent edits, stale revisions, permission revocation and quota races across CLI/API/MCP/UI |
1000
- | Partial failures | Restart during publish/send/webhook processing, disk-full, exhausted worker pools, provider outage, dead-letter replay and bounded backpressure |
1001
- | Isolation | A notification backlog cannot stop redirects/public pages; one app's failure cannot grant access or expose another app's data; resource limits hold under contention |
1002
- | Upgrades | Previous supported suite to candidate, permitted mixed versions, incompatible-version refusal, interrupted migrations and documented rollback limits |
1003
- | Recovery | Coherent backup of every store/blob/key/release; clean-host restore with dispatch paused; reconciliation and measured recovery time/data loss |
1004
- | Human experience | Navigation across all apps, shared theme/locale, responsive layouts, keyboard/accessibility checks and coherent error/recovery paths |
1005
- | Legal and compliance | Current documents/acceptance evidence, data/purpose/processor inventory, privacy-request partial failure, retention/backup behavior, child-directed-mode refusal, marketing suppression and claims/evidence consistency |
1006
-
1007
- Every shared-contract PR runs affected consumer integration tests before merge;
1008
- release candidates run the full matrix and soak/recovery exercises. The suite
1009
- manifest cannot promote incompatible artifacts merely because their independent
1010
- CI passed. Release evidence names what ran, what failed, what remains unverified
1011
- and the accountable owner. Critical security, data-loss or broken customer-journey
1012
- failures block promotion. CI success remains distinct from independent security
1013
- review and real-provider operational proof.
1014
-
1015
- ## Remaining expansion after the launch suite
1016
-
1017
- Forms, billing, legal and reliable notifications are now in the launch plan,
1018
- not optional future suggestions. The remaining candidates are:
1019
-
1020
- | Priority | Addition | Boundary |
1021
- |---|---|---|
1022
- | Later | `urlcode-crm` | Contacts, companies and a small pipeline; evolve forms' lead handoff without duplicating auth identities |
1023
- | Later | `urlcode-analytics` | Privacy-conscious aggregate site/product events; no payment ledger based on lossy telemetry |
1024
- | Later | `urlcode-status` | Service status and incidents; reuse publishing and notification channels |
1025
- | Segment-dependent | Commerce, booking, newsletter automation | Integrate established payment/calendar/email infrastructure after a specific customer need |
1026
-
1027
- A full enterprise ERP, accounting ledger, tax system, omnichannel contact center
1028
- or autonomous outbound sales agent is outside this launch scope. The first suite
1029
- must complete and operate the site → lead → customer → payment → support journey.