docs(architecture): refresh explainers and spec to the shipped system
Some checks failed
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests + visual regression (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Coverage snapshot / snapshot (push) Has been cancelled
Release Please / release-please (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled
Mutation testing (nightly) / mutate (push) Has been cancelled
Library trace revalidation (weekly) / revalidate (push) Has been cancelled
Some checks failed
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests + visual regression (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Coverage snapshot / snapshot (push) Has been cancelled
Release Please / release-please (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled
Mutation testing (nightly) / mutate (push) Has been cancelled
Library trace revalidation (weekly) / revalidate (push) Has been cancelled
Bring docs/architecture/ in line with the current repo: - feature-conformance-explainer.html: drop the "proposed / not yet implemented" framing — the system is shipped. Four enforcement points become five (adds `pnpm fallow` as the whole-codebase audit). Manifest playground shows `coverage`, `analyticsEvents`, `rateLimit`, `requiresConsent`. Milestone / anchor / open-question sections kept but marked historical. - agent-first-workflow-and-conformance.md: four → five enforcement layers; layer table gains the Fallow row. - di-explainer.html: bind-production sample rewritten to show wireUseCase() + assertFeatureConformance() + the full wrapper stack (span → capture → audit? → analytics? → consent? → rateLimit?). - data-flow-explainer.html: same bind-production refresh for the data-flow narrative. - audit-and-compliance-explainer.html: AuditAction enum 6 → 10 values (CONSENT_GRANT / WITHDRAW / RESTRICT / UNRESTRICT); BindProductionContext example gains analytics, consentFactory, rateLimit. - vertical-feature-spec.md: §5 layout lists the 8 optional cores plus core-testing; §9.5 hedges the turbo.json snippet against the live file; §10.4 drops the dated "360 tests" metric for the ADR-020 coverage architecture; §11 gains a historical lead-in pointing at docs/decisions/ as the canonical 25-ADR set.
This commit is contained in:
@@ -1703,16 +1703,56 @@ footer .colophon {
|
||||
<h3>blog/di/<em>bind-production.ts</em></h3>
|
||||
<p>Called from each app's bootstrap (<code>apps/web-next/src/server/bind-production.ts</code>) with the <code>ctx</code> object built once by the aggregator. <code>BindProductionContext</code> is imported from <code>@repo/core-shared/di</code>.</p>
|
||||
<pre class="code" data-lang="typescript // packages/blog/src/di/bind-production.ts"><span class="k">export function</span> <span class="n">bindProductionBlog</span>(<span class="n">ctx</span>: <span class="t">BindProductionContext</span>): <span class="t">void</span> {
|
||||
<span class="c">// bus, realtime, realtimeRegistry, auditLog are optional — present only when the corresponding optional package is scaffolded</span>
|
||||
<span class="k">const</span> { <span class="n">config</span>, <span class="n">tracer</span>, <span class="n">logger</span>, <span class="n">bus</span>, <span class="n">queue</span>, <span class="n">realtime</span>, <span class="n">realtimeRegistry</span>, <span class="n">auditLog</span> } = <span class="n">ctx</span>;
|
||||
<span class="c">// bus, realtime, realtimeRegistry, auditLog are optional — present only when</span>
|
||||
<span class="c">// the corresponding optional package is scaffolded</span>
|
||||
<span class="k">const</span> { <span class="n">config</span>, <span class="n">tracer</span>, <span class="n">logger</span>, <span class="n">bus</span>, <span class="n">queue</span> } = <span class="n">ctx</span>;
|
||||
|
||||
<span class="c">// 1) Swap the mock repo for the real Payload-backed impl</span>
|
||||
<span class="k">if</span> (<span class="n">blogContainer</span>.<span class="n">isBound</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IArticlesRepository</span>)) {
|
||||
<span class="n">blogContainer</span>.<span class="n">unbind</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IArticlesRepository</span>);
|
||||
}
|
||||
<span class="n">blogContainer</span>
|
||||
.<span class="n">bind</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IArticlesRepository</span>)
|
||||
.<span class="n">toConstantValue</span>(<span class="k">new</span> <span class="t">ArticlesRepository</span>(<span class="n">config</span>));
|
||||
<span class="c">// Use cases + controllers stay untouched.</span>
|
||||
<span class="c">// They'll resolve through the new repo automatically.</span>
|
||||
<span class="k">const</span> <span class="n">repo</span> = <span class="k">new</span> <span class="t">ArticlesRepository</span>(<span class="n">config</span>, <span class="n">tracer</span>, <span class="n">logger</span>);
|
||||
<span class="n">blogContainer</span>.<span class="n">bind</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IArticlesRepository</span>).<span class="n">toConstantValue</span>(<span class="n">repo</span>);
|
||||
|
||||
<span class="c">// 2) Wire each use case via wireUseCase — composes</span>
|
||||
<span class="c">// withSpan → withCapture → withAudit → withAnalytics → withConsent → withRateLimit → factory(deps)</span>
|
||||
<span class="c">// and binds the brand-stacked closure to the symbol. One call per use case.</span>
|
||||
<span class="k">const</span> <span class="n">wrappedGetArticles</span> = <span class="n">wireUseCase</span>({
|
||||
<span class="n">container</span>: <span class="n">blogContainer</span>,
|
||||
<span class="n">symbol</span>: <span class="n">BLOG_SYMBOLS</span>.<span class="n">IGetArticlesUseCase</span>,
|
||||
<span class="n">factory</span>: <span class="n">getArticlesUseCase</span>,
|
||||
<span class="n">deps</span>: [<span class="n">repo</span>],
|
||||
<span class="n">feature</span>: <span class="s">"blog"</span>, <span class="n">layer</span>: <span class="s">"use-case"</span>, <span class="n">name</span>: <span class="s">"getArticles"</span>,
|
||||
<span class="n">tracer</span>, <span class="n">logger</span>,
|
||||
});
|
||||
<span class="c">// ... wireUseCase calls for the other use cases ...</span>
|
||||
|
||||
<span class="c">// 3) Wrap each controller — controllers still use withSpan + withCapture manually,</span>
|
||||
<span class="c">// because they take the already-wired use case as their dep.</span>
|
||||
<span class="k">if</span> (<span class="n">blogContainer</span>.<span class="n">isBound</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IGetArticlesController</span>)) {
|
||||
<span class="n">blogContainer</span>.<span class="n">unbind</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IGetArticlesController</span>);
|
||||
}
|
||||
<span class="n">blogContainer</span>.<span class="n">bind</span>(<span class="n">BLOG_SYMBOLS</span>.<span class="n">IGetArticlesController</span>).<span class="n">toConstantValue</span>(
|
||||
<span class="n">withSpan</span>(<span class="n">tracer</span>, { <span class="n">name</span>: <span class="s">"blog.getArticles"</span>, <span class="n">op</span>: <span class="s">"controller"</span> },
|
||||
<span class="n">withCapture</span>(<span class="n">logger</span>, { <span class="n">feature</span>: <span class="s">"blog"</span>, <span class="n">layer</span>: <span class="s">"controller"</span>, <span class="n">name</span>: <span class="s">"blog.getArticles"</span> },
|
||||
<span class="n">getArticlesController</span>(<span class="n">wrappedGetArticles</span>),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
<span class="c">// bus + queue are passed through; generated event/job handlers consume them at the anchors below.</span>
|
||||
<span class="k">void</span> <span class="n">bus</span>; <span class="k">void</span> <span class="n">queue</span>;
|
||||
<span class="c">// <gen:event-handlers></span>
|
||||
<span class="c">// <gen:jobs></span>
|
||||
|
||||
<span class="c">// 4) Self-asserting tail — refuses to boot if any use-case binding is missing a required brand</span>
|
||||
<span class="c">// (withSpan / withCapture / withAudit / withAnalytics / withConsent / withRateLimit) or drifts from the manifest.</span>
|
||||
<span class="n">assertFeatureConformance</span>(
|
||||
<span class="n">blogContainer</span>,
|
||||
<span class="n">blogManifest</span>,
|
||||
{ <span class="n">getArticles</span>: <span class="n">BLOG_SYMBOLS</span>.<span class="n">IGetArticlesUseCase</span>, <span class="c">/* … */</span> },
|
||||
<span class="n">ctx</span>,
|
||||
);
|
||||
}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user