aw-spec-cli 0.1.5 → 0.1.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 (205) hide show
  1. package/assets/.agents/agent.json +1 -1
  2. package/assets/.agents/skills/{aw-spec-orch → appweaver}/SKILL.md +10 -10
  3. package/assets/.agents/skills/{aw-spec-orch-demo → appweaver-demo}/SKILL.md +9 -9
  4. package/assets/.claude/agent.json +1 -1
  5. package/assets/.claude/skills/{aw-spec-orch → appweaver}/SKILL.md +10 -10
  6. package/assets/.claude/skills/{aw-spec-orch-demo → appweaver-demo}/SKILL.md +9 -9
  7. package/assets/.kilocode/agent.json +1 -1
  8. package/assets/.kilocode/workflows/{aw-spec-orch-demo.md → appweaver-demo.md} +9 -9
  9. package/assets/.kilocode/workflows/{aw-spec-orch.md → appweaver.md} +10 -10
  10. package/assets/docs/pharma-constitution.my-ref.md +86 -0
  11. package/dist/utils/paths.js +2 -2
  12. package/dist/utils/paths.js.map +1 -1
  13. package/package.json +1 -1
  14. package/assets/.aw-spec/DESIGN-FORMAT.md +0 -151
  15. package/assets/.aw-spec/ORCH-DIALECT.md +0 -156
  16. package/assets/.aw-spec/RULE-PARTITION.md +0 -126
  17. package/assets/.aw-spec/domain.json +0 -3
  18. package/assets/.aw-spec/extensions/.registry +0 -19
  19. package/assets/.aw-spec/extensions/agent-context/README.md +0 -57
  20. package/assets/.aw-spec/extensions/agent-context/agent-context-config.yml +0 -4
  21. package/assets/.aw-spec/extensions/agent-context/commands/aw-spec.agent-context.update.md +0 -26
  22. package/assets/.aw-spec/extensions/agent-context/extension.yml +0 -37
  23. package/assets/.aw-spec/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -201
  24. package/assets/.aw-spec/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -237
  25. package/assets/.aw-spec/extensions.yml +0 -16
  26. package/assets/.aw-spec/feature.json +0 -3
  27. package/assets/.aw-spec/init-options.json +0 -9
  28. package/assets/.aw-spec/integration.json +0 -15
  29. package/assets/.aw-spec/integrations/aw-spec.manifest.json +0 -9
  30. package/assets/.aw-spec/interpreter/run-skill.py +0 -1158
  31. package/assets/.aw-spec/memory/constitution.md +0 -50
  32. package/assets/.aw-spec/orchestrator/AGENT-PROFILE.md +0 -94
  33. package/assets/.aw-spec/orchestrator/README.md +0 -300
  34. package/assets/.aw-spec/orchestrator/adapters/claude_agent_sdk.py +0 -74
  35. package/assets/.aw-spec/orchestrator/adapters/google_antigravity.py +0 -74
  36. package/assets/.aw-spec/orchestrator/modules/delta-design.orch.yaml +0 -105
  37. package/assets/.aw-spec/orchestrator/modules/delta-spec.orch.yaml +0 -79
  38. package/assets/.aw-spec/orchestrator/modules/domain-select.orch.yaml +0 -81
  39. package/assets/.aw-spec/orchestrator/modules/tech-select.orch.yaml +0 -75
  40. package/assets/.aw-spec/orchestrator/orchestrator.py +0 -1721
  41. package/assets/.aw-spec/orchestrator/rev-templates/ai-rules.reference.md +0 -40
  42. package/assets/.aw-spec/orchestrator/rev-templates/comandrulemap.skeleton.md +0 -59
  43. package/assets/.aw-spec/orchestrator/rev-templates/commandtechrulemap.skeleton.md +0 -97
  44. package/assets/.aw-spec/orchestrator/rev-templates/domain-constitution.skeleton.md +0 -61
  45. package/assets/.aw-spec/orchestrator/rev-templates/domain-requirements.skeleton.md +0 -48
  46. package/assets/.aw-spec/orchestrator/rev-templates/domain-rule-file.skeleton.md +0 -39
  47. package/assets/.aw-spec/orchestrator/rev-templates/technical-constitution.skeleton.md +0 -106
  48. package/assets/.aw-spec/orchestrator/rev-templates/technical-rule-file.skeleton.md +0 -54
  49. package/assets/.aw-spec/orchestrator/workflows/_smoke.orch.yaml +0 -160
  50. package/assets/.aw-spec/orchestrator/workflows/aw-spec-add-component.orch.yaml +0 -244
  51. package/assets/.aw-spec/orchestrator/workflows/aw-spec-adopt.orch.yaml +0 -775
  52. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -248
  53. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -261
  54. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +0 -425
  55. package/assets/.aw-spec/orchestrator/workflows/aw-spec-build.orch.yaml +0 -188
  56. package/assets/.aw-spec/orchestrator/workflows/aw-spec-characterize.orch.yaml +0 -474
  57. package/assets/.aw-spec/orchestrator/workflows/aw-spec-close-delta.orch.yaml +0 -181
  58. package/assets/.aw-spec/orchestrator/workflows/aw-spec-constitution.orch.yaml +0 -284
  59. package/assets/.aw-spec/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -103
  60. package/assets/.aw-spec/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +0 -69
  61. package/assets/.aw-spec/orchestrator/workflows/aw-spec-deploy.orch.yaml +0 -85
  62. package/assets/.aw-spec/orchestrator/workflows/aw-spec-design.orch.yaml +0 -382
  63. package/assets/.aw-spec/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +0 -382
  64. package/assets/.aw-spec/orchestrator/workflows/aw-spec-foundation.orch.yaml +0 -246
  65. package/assets/.aw-spec/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -231
  66. package/assets/.aw-spec/orchestrator/workflows/aw-spec-implement.orch.yaml +0 -258
  67. package/assets/.aw-spec/orchestrator/workflows/aw-spec-inventory.orch.yaml +0 -236
  68. package/assets/.aw-spec/orchestrator/workflows/aw-spec-onboard.orch.yaml +0 -949
  69. package/assets/.aw-spec/orchestrator/workflows/aw-spec-parity.orch.yaml +0 -293
  70. package/assets/.aw-spec/orchestrator/workflows/aw-spec-run.orch.yaml +0 -177
  71. package/assets/.aw-spec/orchestrator/workflows/aw-spec-select-domain.orch.yaml +0 -79
  72. package/assets/.aw-spec/orchestrator/workflows/aw-spec-select-feature.orch.yaml +0 -128
  73. package/assets/.aw-spec/orchestrator/workflows/aw-spec-specify.orch.yaml +0 -412
  74. package/assets/.aw-spec/scripts/bash/aw-inventory.sh +0 -14
  75. package/assets/.aw-spec/scripts/bash/aw-parity.sh +0 -13
  76. package/assets/.aw-spec/scripts/bash/aw-rev-constitution.sh +0 -13
  77. package/assets/.aw-spec/scripts/bash/aw-spec-actions.sh +0 -1899
  78. package/assets/.aw-spec/scripts/bash/aw-xref.sh +0 -15
  79. package/assets/.aw-spec/scripts/bash/common.sh +0 -533
  80. package/assets/.aw-spec/scripts/powershell/aw-inventory.ps1 +0 -14
  81. package/assets/.aw-spec/scripts/powershell/aw-parity.ps1 +0 -13
  82. package/assets/.aw-spec/scripts/powershell/aw-rev-constitution.ps1 +0 -13
  83. package/assets/.aw-spec/scripts/powershell/aw-spec-actions.ps1 +0 -1563
  84. package/assets/.aw-spec/scripts/powershell/aw-xref.ps1 +0 -15
  85. package/assets/.aw-spec/scripts/python/aw-inventory.py +0 -683
  86. package/assets/.aw-spec/scripts/python/aw-parity.py +0 -380
  87. package/assets/.aw-spec/scripts/python/aw-rev-constitution.py +0 -312
  88. package/assets/.aw-spec/scripts/python/aw-xref.py +0 -1330
  89. package/assets/.aw-spec/scripts/python/validate_okf.py +0 -349
  90. package/assets/.aw-spec/templates/constitution-domain-template.md +0 -75
  91. package/assets/.aw-spec/templates/constitution-technical-template.md +0 -70
  92. package/assets/.aw-spec/templates/delta-design-template.md +0 -69
  93. package/assets/.aw-spec/templates/delta-spec-template.md +0 -60
  94. package/assets/.aw-spec/templates/design-template.md +0 -383
  95. package/assets/.aw-spec/templates/okf-concept-template.md +0 -103
  96. package/assets/.aw-spec/templates/parity-manifest-template.json +0 -49
  97. package/assets/.aw-spec/templates/source-map-template.md +0 -85
  98. package/assets/.aw-spec/templates/spec-template.md +0 -252
  99. package/assets/docs/ModularMonolith/ModularMonolith.Reference.pack.txt +0 -25248
  100. package/assets/docs/ModularMonolith/ModularMonolith.pack.txt +0 -5726
  101. package/assets/docs/ModularMonolith/pack-foundation.ps1 +0 -145
  102. package/assets/docs/ModularMonolith/pack-foundation.sh +0 -196
  103. package/assets/docs/ModularMonolith/pack-reference-foundation.ps1 +0 -157
  104. package/assets/docs/ModularMonolith/pack-reference-foundation.sh +0 -209
  105. package/assets/docs/ModularMonolith/unpack-foundation.ps1 +0 -126
  106. package/assets/docs/ModularMonolith/unpack-foundation.sh +0 -217
  107. package/assets/docs/ModularMonolith/unpack-reference-foundation.ps1 +0 -129
  108. package/assets/docs/ModularMonolith/unpack-reference-foundation.sh +0 -218
  109. package/assets/docs/README.md +0 -106
  110. package/assets/docs/VerticalSlice/PACKAGING.md +0 -185
  111. package/assets/docs/VerticalSlice/VerticalSlice.Reference.pack.txt +0 -19318
  112. package/assets/docs/VerticalSlice/VerticalSlice.pack.txt +0 -2833
  113. package/assets/docs/VerticalSlice/pack-foundation.ps1 +0 -145
  114. package/assets/docs/VerticalSlice/pack-foundation.sh +0 -196
  115. package/assets/docs/VerticalSlice/pack-reference-foundation.ps1 +0 -157
  116. package/assets/docs/VerticalSlice/pack-reference-foundation.sh +0 -209
  117. package/assets/docs/VerticalSlice/unpack-foundation.ps1 +0 -126
  118. package/assets/docs/VerticalSlice/unpack-foundation.sh +0 -217
  119. package/assets/docs/VerticalSlice/unpack-reference-foundation.ps1 +0 -129
  120. package/assets/docs/VerticalSlice/unpack-reference-foundation.sh +0 -218
  121. package/assets/docs/architecture/clean-architecture.md +0 -71
  122. package/assets/docs/architecture/cqrs.md +0 -141
  123. package/assets/docs/architecture/eventing.md +0 -83
  124. package/assets/docs/architecture/folder-structure.md +0 -61
  125. package/assets/docs/architecture/modular-monolith.md +0 -47
  126. package/assets/docs/architecture/persistence.md +0 -269
  127. package/assets/docs/architecture/testing.md +0 -55
  128. package/assets/docs/architecture/vertical-slices.md +0 -201
  129. package/assets/docs/components/Email/README.md +0 -119
  130. package/assets/docs/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +0 -84
  131. package/assets/docs/components/Email/integration.md +0 -300
  132. package/assets/docs/components/Jobs/README.md +0 -113
  133. package/assets/docs/components/Jobs/integration.md +0 -259
  134. package/assets/docs/components/QrGenerator/README.md +0 -85
  135. package/assets/docs/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +0 -57
  136. package/assets/docs/components/QrGenerator/integration.md +0 -230
  137. package/assets/docs/components/README.md +0 -74
  138. package/assets/docs/domain/domain-driven-design.md +0 -212
  139. package/assets/docs/domainspecs/healthcare/ai-rules.domain.md +0 -34
  140. package/assets/docs/domainspecs/healthcare/api-versioning.domain.md +0 -17
  141. package/assets/docs/domainspecs/healthcare/auditing.domain.md +0 -97
  142. package/assets/docs/domainspecs/healthcare/authorization.domain.md +0 -26
  143. package/assets/docs/domainspecs/healthcare/clinical-terms.md +0 -20
  144. package/assets/docs/domainspecs/healthcare/coding-standards.domain.md +0 -26
  145. package/assets/docs/domainspecs/healthcare/comandrulemap.md +0 -100
  146. package/assets/docs/domainspecs/healthcare/commandtechrulemap.md +0 -119
  147. package/assets/docs/domainspecs/healthcare/consent.md +0 -19
  148. package/assets/docs/domainspecs/healthcare/cqrs.domain.md +0 -12
  149. package/assets/docs/domainspecs/healthcare/data-classification.domain.md +0 -28
  150. package/assets/docs/domainspecs/healthcare/dependency-policy.domain.md +0 -11
  151. package/assets/docs/domainspecs/healthcare/dicom.md +0 -15
  152. package/assets/docs/domainspecs/healthcare/domain-driven-design.domain.md +0 -28
  153. package/assets/docs/domainspecs/healthcare/domain-requirements.md +0 -55
  154. package/assets/docs/domainspecs/healthcare/eventing.domain.md +0 -18
  155. package/assets/docs/domainspecs/healthcare/fhir.md +0 -36
  156. package/assets/docs/domainspecs/healthcare/folder-structure.domain.md +0 -23
  157. package/assets/docs/domainspecs/healthcare/hipaa.md +0 -34
  158. package/assets/docs/domainspecs/healthcare/hl7.md +0 -15
  159. package/assets/docs/domainspecs/healthcare/integration-terms.md +0 -21
  160. package/assets/docs/domainspecs/healthcare/persistence.domain.md +0 -20
  161. package/assets/docs/domainspecs/healthcare/terminology.md +0 -30
  162. package/assets/docs/domainspecs/healthcare/testing.domain.md +0 -15
  163. package/assets/docs/domainspecs/healthcare/vertical-slices.domain.md +0 -18
  164. package/assets/docs/domainspecs/healthcare/zero-trust.domain.md +0 -12
  165. package/assets/docs/domainspecs/pharma/ai-rules.domain.md +0 -32
  166. package/assets/docs/domainspecs/pharma/api-versioning.domain.md +0 -20
  167. package/assets/docs/domainspecs/pharma/atc.md +0 -22
  168. package/assets/docs/domainspecs/pharma/auditing.domain.md +0 -90
  169. package/assets/docs/domainspecs/pharma/authorization.domain.md +0 -25
  170. package/assets/docs/domainspecs/pharma/coding-standards.domain.md +0 -28
  171. package/assets/docs/domainspecs/pharma/comandrulemap.md +0 -108
  172. package/assets/docs/domainspecs/pharma/commandtechrulemap.md +0 -119
  173. package/assets/docs/domainspecs/pharma/cqrs.domain.md +0 -16
  174. package/assets/docs/domainspecs/pharma/data-classification.domain.md +0 -24
  175. package/assets/docs/domainspecs/pharma/data-provenance.md +0 -21
  176. package/assets/docs/domainspecs/pharma/dependency-policy.domain.md +0 -11
  177. package/assets/docs/domainspecs/pharma/domain-driven-design.domain.md +0 -36
  178. package/assets/docs/domainspecs/pharma/domain-requirements.md +0 -99
  179. package/assets/docs/domainspecs/pharma/eventing.domain.md +0 -18
  180. package/assets/docs/domainspecs/pharma/fhir.md +0 -31
  181. package/assets/docs/domainspecs/pharma/folder-structure.domain.md +0 -24
  182. package/assets/docs/domainspecs/pharma/hl7.md +0 -17
  183. package/assets/docs/domainspecs/pharma/idmp.md +0 -26
  184. package/assets/docs/domainspecs/pharma/integration-terms.md +0 -21
  185. package/assets/docs/domainspecs/pharma/ndc.md +0 -28
  186. package/assets/docs/domainspecs/pharma/persistence.domain.md +0 -23
  187. package/assets/docs/domainspecs/pharma/pharma-terms.md +0 -27
  188. package/assets/docs/domainspecs/pharma/product-lifecycle.domain.md +0 -30
  189. package/assets/docs/domainspecs/pharma/regulatory-compliance.md +0 -19
  190. package/assets/docs/domainspecs/pharma/terminology.md +0 -32
  191. package/assets/docs/domainspecs/pharma/testing.domain.md +0 -19
  192. package/assets/docs/domainspecs/pharma/vertical-slices.domain.md +0 -17
  193. package/assets/docs/domainspecs/pharma/zero-trust.domain.md +0 -12
  194. package/assets/docs/glossary/ai-rules.md +0 -59
  195. package/assets/docs/governance/api-versioning.md +0 -99
  196. package/assets/docs/governance/coding-standards.md +0 -87
  197. package/assets/docs/governance/dependency-policy.md +0 -40
  198. package/assets/docs/interop/ihe-conformance.md +0 -31
  199. package/assets/docs/requirement-spec.txt +0 -27
  200. package/assets/docs/security/auditing.md +0 -160
  201. package/assets/docs/security/authorization-matrix.md +0 -14
  202. package/assets/docs/security/authorization.md +0 -87
  203. package/assets/docs/security/data-classification.md +0 -38
  204. package/assets/docs/security/zero-trust.md +0 -76
  205. package/assets/docs/technology-constitution.md +0 -172
@@ -1,84 +0,0 @@
1
- using FastEndpoints;
2
- using Microsoft.Extensions.Configuration;
3
- using AppWeaver.Messaging.Email;
4
-
5
- // NOTE: This is a bundled SAMPLE endpoint for the AppWeaver Email component.
6
- // It lives under docs/ and is NOT compiled here. /aw-spec-addcomponent copies it into the
7
- // host project's ReferenceEndpoints/ folder and replaces the __HOSTPROJECT__ namespace token
8
- // with the host project's root namespace (e.g. AppWeaver.Health.Service).
9
- namespace __HOSTPROJECT__.ReferenceEndpoints;
10
-
11
- /// <summary>
12
- /// Sample reference endpoint for the AppWeaver Email component.
13
- ///
14
- /// Demonstrates the full send sequence inline — it injects the <see cref="IEmailService"/>
15
- /// abstraction directly and calls <c>SendAsync</c> with the provider wired during DI
16
- /// registration (see the component's integration runbook). There is intentionally no
17
- /// command / command-handler / mediator: this is a copy-paste sample only.
18
- ///
19
- /// The active transport is whatever <c>options.Provider</c> was set to when
20
- /// <c>AddEmailMessaging(...)</c> was registered. With the <c>File</c> provider the message is
21
- /// written to <c>Emails_&lt;yyyy-MM-dd&gt;.txt</c> in the application base directory.
22
- /// </summary>
23
- public class SendEmailEndpoint(IEmailService _email, IConfiguration _config)
24
- : Endpoint<SendEmailRequest>
25
- {
26
- public override void Configure()
27
- {
28
- Post("/reference/email/send");
29
- AllowAnonymous();
30
- Summary(s =>
31
- {
32
- s.Summary = "Send a sample email via the configured Email provider";
33
- s.Description = "Reference endpoint for the AppWeaver Email component. Injects "
34
- + "IEmailService directly (no command/handler). 'from' falls back to "
35
- + "Messaging:Email:DefaultFrom when omitted.";
36
- });
37
- Options(o => o.WithTags("Reference - Email"));
38
- }
39
-
40
- public override async Task HandleAsync(SendEmailRequest req, CancellationToken ct)
41
- {
42
- if (string.IsNullOrWhiteSpace(req.To) || string.IsNullOrWhiteSpace(req.Subject))
43
- {
44
- HttpContext.Response.StatusCode = 400;
45
- await HttpContext.Response.WriteAsJsonAsync(
46
- new { error = "'to' and 'subject' are required." }, ct);
47
- return;
48
- }
49
-
50
- // 'from' is optional in the request — fall back to the configured DefaultFrom.
51
- var from = string.IsNullOrWhiteSpace(req.From)
52
- ? _config["Messaging:Email:DefaultFrom"] ?? "no-reply@your-domain.com"
53
- : req.From;
54
-
55
- await _email.SendAsync(from, req.To, req.Subject, req.Body ?? string.Empty, req.IsHtml, ct);
56
-
57
- await HttpContext.Response.WriteAsJsonAsync(new
58
- {
59
- status = "sent",
60
- from,
61
- to = req.To,
62
- note = "With the File provider, output is written to Emails_<yyyy-MM-dd>.txt "
63
- + "in the app base directory."
64
- }, ct);
65
- }
66
- }
67
-
68
- public class SendEmailRequest
69
- {
70
- /// <summary>Recipient address (required).</summary>
71
- public string To { get; set; } = string.Empty;
72
-
73
- /// <summary>Subject line (required).</summary>
74
- public string Subject { get; set; } = string.Empty;
75
-
76
- /// <summary>HTML or plain-text body.</summary>
77
- public string Body { get; set; } = string.Empty;
78
-
79
- /// <summary>Treat <see cref="Body"/> as HTML. Defaults to true.</summary>
80
- public bool IsHtml { get; set; } = true;
81
-
82
- /// <summary>Optional sender; falls back to Messaging:Email:DefaultFrom when omitted.</summary>
83
- public string? From { get; set; }
84
- }
@@ -1,300 +0,0 @@
1
- # Email Component — Integration Workflow (agent playbook)
2
-
3
- > Pure technology (domain-agnostic). This file is an **agent runbook**: read it top-to-bottom and
4
- > execute the workflow in order. It drives an interactive integration of `IEmailService` into a
5
- > project, asking the user which transport implementation(s) to wire. Read [README.md](./README.md)
6
- > first for the contract. Replace `<SampleProjectName>` with the project name.
7
- > Commands: `/aw-spec-implement`.
8
-
9
- ---
10
-
11
- ## Agent workflow — execute in order
12
-
13
- 1. **Load context.** Read [README.md](./README.md) (contract + provider matrix) and this file.
14
- 2. **Resolve the host project** `<HostProject>` (see [[folder-structure]], [[components-readme]] R0.2):
15
- the single startup project that owns **`Program.cs`** + the ASP.NET Core web SDK —
16
- `<SampleProjectName>.Service` (Vertical Slice foundation), `<SampleProjectName>.API` (Modular
17
- Monolith foundation), or another name in a future template. **Find it by locating `Program.cs`, not
18
- by assuming the name.** In these foundations application/domain/infrastructure code all live in this
19
- one project (modules are folders); there is **no** separate `…Application` / `…Infrastructure`
20
- project. `<HostProject>` is the target for C2–C4 below.
21
- 3. **Present the implementation catalog (below) as a selection list and ASK the user which
22
- implementation(s) to integrate.** Use an interactive multi-select prompt (`AskUserQuestion`,
23
- `multiSelect: true`). The list options are the rows of the *Implementation catalog*.
24
- - The user MAY select **more than one** (e.g., `MsGraph` for production + `File` for local dev).
25
- - If more than one is selected, **ask a follow-up single-select**: *which one is the default
26
- (active) provider?* — this becomes `options.Provider`.
27
- - If the user selects exactly one, that one is the default.
28
- 4. **Apply “Common steps” once** (§Common steps) — abstraction package + registration scaffold.
29
- 5. **For each selected implementation, apply its block** under §Implementation blocks — add its
30
- package, its `Use…` call inside the `AddEmailMessaging` builder, and its config section.
31
- 6. **Set the default provider:** `configureOptions: options => options.Provider = "<default key>"`.
32
- All selected implementations stay registered; the active one is switchable later via config.
33
- 7. **(Optional) Wire a usage example** in the relevant feature handler (§Usage).
34
- 8. **Offer the bundled sample endpoint (ASK).** After the wiring above, ask the user (single-select
35
- yes/no via `AskUserQuestion`) whether to add the ready-made sample endpoint. If **yes**, copy it
36
- into the host project — see §Sample reference endpoint. If **no**, skip silently.
37
- 9. **Verify** (§Verification) and report what was added.
38
-
39
- > **Guardrail — always set `options.Provider`.** When `Provider` is null the facade falls back to a
40
- > **hardcoded `"SendGrid"`** key; if SendGrid is not registered, resolution throws at runtime. Never
41
- > rely on the implicit fallback.
42
-
43
- ---
44
-
45
- ## Implementation catalog (selection list)
46
-
47
- Present these as the multi-select options. `Key` is the provider key and the `Use…` method suffix.
48
-
49
- | Key | Implementation | Best for | Package (v) | Required settings |
50
- |---|---|---|---|---|
51
- | `MsGraph` | Microsoft 365 / Graph API | Production on an O365 tenant | `AppWeaver.Messaging.Email.MsGraph` (0.1.2) | `TenantId`, `ClientId`, `ClientSecret`, `DefaultFrom` |
52
- | `Smtp` | Classic SMTP | Any SMTP server | `AppWeaver.Messaging.Email.Smtp` (0.1.3) | `Host`, `Port`, `Username`, `Password`, `EnableSsl` |
53
- | `SendGrid` | SendGrid API | SendGrid accounts | `AppWeaver.Messaging.Email.SendGrid` (0.1.2) | `ApiKey` *(required)*, `DefaultFrom` |
54
- | `OAuth2` | OAuth2-authenticated SMTP | O365 SMTP with OAuth2 | `AppWeaver.Messaging.Email.OAuth2` (0.1.3) | `TenantId`, `ClientId`, `ClientSecret`, `Host`, `Port` |
55
- | `File` | Writes email to a local `.txt` | Local dev / tests (no real send) | `AppWeaver.Messaging.Email.File` (0.1.2) | `DefaultFrom` |
56
-
57
- > Recommended pairing: **`MsGraph` (default) + `File`** so developers can run locally without
58
- > sending real mail, while production uses Graph.
59
-
60
- ---
61
-
62
- ## Common steps (apply once, regardless of selection)
63
-
64
- ### C1 — Abstraction package version
65
-
66
- **File:** `Directory.Packages.props` (versions live here only — see [[dependency-policy]])
67
-
68
- ```xml
69
- <ItemGroup>
70
- <!-- AppWeaver — Email (abstraction) -->
71
- <PackageVersion Include="AppWeaver.Messaging.Email" Version="0.1.3" />
72
- <!-- + one <PackageVersion> per selected implementation — see each block below -->
73
- </ItemGroup>
74
- ```
75
-
76
- ### C2 — Project references
77
-
78
- **File:** `src/<HostProject>/<HostProject>.csproj` (the host project resolved in step 2 — single
79
- project, no separate Application/Infrastructure). Add the abstraction **and** every selected
80
- implementation's package here (no `Version=` — versions live in `Directory.Packages.props`, C1).
81
-
82
- ```xml
83
- <ItemGroup>
84
- <PackageReference Include="AppWeaver.Messaging.Email" /> <!-- no Version= -->
85
- <!-- + each selected implementation’s package — see its block below -->
86
- </ItemGroup>
87
- ```
88
-
89
- ### C3 — Registration scaffold
90
-
91
- **File:** the host project `<HostProject>` (step 2) — add the registration in its
92
- `Extensions/InfrastructureServiceRegistration.cs` (`AddInfrastructure`) when that file exists (it does
93
- in the Vertical Slice / Modular Monolith foundations), otherwise directly in `Program.cs` **before**
94
- `builder.Build()`. (`configuration` below = the `IConfiguration` in scope: `config` inside
95
- `AddInfrastructure`, `builder.Configuration` in `Program.cs`.)
96
-
97
- Add the base call; each selected implementation contributes one `builder.Use…(…)` line (C4).
98
-
99
- ```csharp
100
- using AppWeaver.Messaging.Email.Extensions;
101
- // + one using per selected implementation (see its block)
102
-
103
- services.AddEmailMessaging(
104
- configureBuilder: builder =>
105
- {
106
- // ⬇ one Use…() call per selected implementation is inserted here
107
- },
108
- configureOptions: options => options.Provider = "<default key>"); // step 6
109
- ```
110
-
111
- > **Dual local/Aspire startup ([[components-readme]] R0.2a).** If the host project also has an
112
- > `AddAspireInfrastructure` method (`Extensions/AspireInfrastructureExtensions.cs`) selected by
113
- > `if (isAspire) … else …` in `Program.cs`, add this **same** `AddEmailMessaging(...)` block to
114
- > **both** `AddInfrastructure` and `AddAspireInfrastructure`. The Email registration is DB-agnostic, so
115
- > it is identical in both methods — copy it verbatim. Registering in only one leaves `IEmailService`
116
- > unresolvable (throws at runtime) in the other run mode.
117
-
118
- ### C4 — Base appsettings block
119
-
120
- **File:** `src/<HostProject>/appsettings.json` (the host project resolved in step 2)
121
-
122
- ```jsonc
123
- {
124
- "Messaging": {
125
- "Email": {
126
- "DefaultFrom": "no-reply@your-domain.com",
127
- "AdminEmail": "admin@your-domain.com"
128
- }
129
- }
130
- }
131
- ```
132
-
133
- ---
134
-
135
- ## Implementation blocks
136
-
137
- For each implementation the user selected, do all three sub-steps: **package**, **registration
138
- line**, **config**. Secrets MUST be supplied via user-secrets / env / key vault — never committed.
139
-
140
- ### MsGraph
141
- ```xml
142
- <!-- Directory.Packages.props --> <PackageVersion Include="AppWeaver.Messaging.Email.MsGraph" Version="0.1.2" />
143
- <!-- host .csproj --> <PackageReference Include="AppWeaver.Messaging.Email.MsGraph" />
144
- ```
145
- ```csharp
146
- using AppWeaver.Messaging.Email.MsGraph.Extensions;
147
- // inside AddEmailMessaging builder:
148
- builder.UseMsGraph(o =>
149
- {
150
- o.TenantId = configuration["Messaging.Email.MsGraph:TenantId"];
151
- o.ClientId = configuration["Messaging.Email.MsGraph:ClientId"];
152
- o.ClientSecret = configuration["Messaging.Email.MsGraph:ClientSecret"]; // user-secrets
153
- o.DefaultFrom = configuration["Messaging:Email:DefaultFrom"];
154
- });
155
- ```
156
- ```jsonc
157
- // appsettings.json — secret set out-of-band:
158
- // dotnet user-secrets set "Messaging.Email.MsGraph:ClientSecret" "<secret>"
159
- "Messaging.Email.MsGraph": { "TenantId": "<guid>", "ClientId": "<guid>", "DefaultFrom": "no-reply@your-domain.com" }
160
- ```
161
-
162
- ### Smtp
163
- ```xml
164
- <PackageVersion Include="AppWeaver.Messaging.Email.Smtp" Version="0.1.3" />
165
- <PackageReference Include="AppWeaver.Messaging.Email.Smtp" />
166
- ```
167
- ```csharp
168
- using AppWeaver.Messaging.Email.Smtp.Extensions;
169
- builder.UseSmtp(o =>
170
- {
171
- o.Host = configuration["Messaging.Email.Smtp:Host"]!;
172
- o.Port = int.Parse(configuration["Messaging.Email.Smtp:Port"] ?? "587");
173
- o.Username = configuration["Messaging.Email.Smtp:Username"]!;
174
- o.Password = configuration["Messaging.Email.Smtp:Password"]!; // user-secrets
175
- o.EnableSsl = true;
176
- o.DefaultFrom = configuration["Messaging:Email:DefaultFrom"];
177
- });
178
- ```
179
- ```jsonc
180
- "Messaging.Email.Smtp": { "Host": "smtp.example.com", "Port": 587, "Username": "<user>", "EnableSsl": true }
181
- ```
182
- > Note: the `SendAsync(from,to,…)` convenience overload of the SMTP service writes to a file; the
183
- > `EmailMessage` overload performs the real SMTP send. Use `SendAsync(EmailMessage, ct)` for delivery.
184
-
185
- ### SendGrid
186
- ```xml
187
- <PackageVersion Include="AppWeaver.Messaging.Email.SendGrid" Version="0.1.2" />
188
- <PackageReference Include="AppWeaver.Messaging.Email.SendGrid" />
189
- ```
190
- ```csharp
191
- using AppWeaver.Messaging.Email.SendGrid.Extensions;
192
- builder.UseSendGrid(o =>
193
- {
194
- o.ApiKey = configuration["Messaging.Email.SendGrid:ApiKey"]!; // [Required] — user-secrets
195
- o.DefaultFrom = configuration["Messaging:Email:DefaultFrom"];
196
- });
197
- ```
198
- > `ApiKey` is `[Required]` and validates on startup — a missing key fails app boot, not the first send.
199
-
200
- ### OAuth2
201
- ```xml
202
- <PackageVersion Include="AppWeaver.Messaging.Email.OAuth2" Version="0.1.3" />
203
- <PackageReference Include="AppWeaver.Messaging.Email.OAuth2" />
204
- ```
205
- ```csharp
206
- using AppWeaver.Messaging.Email.OAuth2.Extensions;
207
- builder.UseOAuth2(o =>
208
- {
209
- o.TenantId = configuration["Messaging.Email.OAuth2:TenantId"];
210
- o.ClientId = configuration["Messaging.Email.OAuth2:ClientId"];
211
- o.ClientSecret = configuration["Messaging.Email.OAuth2:ClientSecret"]; // user-secrets
212
- o.Host = "smtp.office365.com"; o.Port = 587;
213
- o.DefaultFrom = configuration["Messaging:Email:DefaultFrom"];
214
- });
215
- ```
216
-
217
- ### File
218
- ```xml
219
- <PackageVersion Include="AppWeaver.Messaging.Email.File" Version="0.1.2" />
220
- <PackageReference Include="AppWeaver.Messaging.Email.File" />
221
- ```
222
- ```csharp
223
- using AppWeaver.Messaging.Email.File.Extensions;
224
- builder.UseFile(o => o.DefaultFrom = configuration["Messaging:Email:DefaultFrom"]);
225
- ```
226
- > Pass `DefaultFrom` **inline** as shown. The File provider’s config binder reads the
227
- > `Messaging.Email.Smtp` section (a known quirk), so do not rely on a `Messaging.Email.File` config
228
- > section. Output is written to `Emails_<yyyy-MM-dd>.txt` in `AppContext.BaseDirectory`.
229
-
230
- ---
231
-
232
- ## Usage (inject the abstraction in a feature handler)
233
-
234
- Email is a side effect of a business operation — call it from the Application command handler that
235
- owns the operation (see [[cqrs]], [[vertical-slices]]). Inject **`IEmailService`**, never a provider.
236
-
237
- ```csharp
238
- using AppWeaver.Messaging.Email;
239
-
240
- public class CreateUserCommandHandler(IEmailService _email, IConfiguration _config /* … */)
241
- : ICommandHandler<CreateUserCommand, Result<UserDto>>
242
- {
243
- public async ValueTask<Result<UserDto>> Handle(CreateUserCommand req, CancellationToken ct)
244
- {
245
- // … persist aggregate …
246
- var from = _config["Messaging:Email:DefaultFrom"]!;
247
- var to = _config["Messaging:Email:AdminEmail"]!;
248
- await _email.SendAsync(from, to, $"New user: {req.Name}", "<p>Created.</p>", ct: ct);
249
- return Result<UserDto>.Ok(/* dto */);
250
- }
251
- }
252
- ```
253
-
254
- Multi-recipient / attachments — use the `EmailMessage` overload (To/Cc/Bcc + `EmailAttachment`,
255
- see [README.md](./README.md)).
256
-
257
- ---
258
-
259
- ## Sample reference endpoint
260
-
261
- A ready-to-run FastEndpoint is bundled in this component folder at
262
- [`ReferenceEndpoints/SendEmailEndpoint.cs`](./ReferenceEndpoints/SendEmailEndpoint.cs). It injects
263
- `IEmailService` directly and performs the **full send inline** — no command/handler/mediator — purely
264
- as a copy-paste sample. It is **not** wired automatically; it is offered in workflow step 8.
265
-
266
- **When the user opts in (step 8) — copy procedure:**
267
-
268
- 1. Confirm `docs/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs` exists. If it is missing,
269
- tell the user and skip (do not hand-write a replacement).
270
- 2. Create `src/<HostProject>/ReferenceEndpoints/` if it does not exist (`<HostProject>` = the project
271
- resolved in step 2).
272
- 3. Copy the file to `src/<HostProject>/ReferenceEndpoints/SendEmailEndpoint.cs`, replacing the
273
- namespace token `__HOSTPROJECT__` with `<HostProject>`'s root namespace (e.g.
274
- `AppWeaver.Health.Service`). Change nothing else.
275
- 4. Do **not** touch the C1–C4 wiring. FastEndpoints auto-discovers the endpoint by assembly scan, so
276
- no extra registration is required.
277
-
278
- **Endpoint:** `POST /reference/email/send` — body `{ "to", "subject", "body", "isHtml"?, "from"? }`.
279
- `from` falls back to `Messaging:Email:DefaultFrom`. With the `File` provider the message is written
280
- to `Emails_<yyyy-MM-dd>.txt` in the app base directory (no real mail is sent).
281
-
282
- ---
283
-
284
- ## Verification
285
-
286
- 1. **Builds** — `dotnet build` succeeds; no `Version=` on package references.
287
- 2. **Startup validates** — app boots; options `ValidateOnStart()` passes; `options.Provider` equals
288
- one of the selected keys.
289
- 3. **Resolves** — `IEmailService` resolves from DI.
290
- 4. **Sends** — a send succeeds; for `File`, confirm `Emails_<yyyy-MM-dd>.txt` appears in the app
291
- base directory.
292
- 5. **No secrets in diff** — `git diff` shows no secret / API key / password literals.
293
- 6. **Sample endpoint (only if copied in step 8)** — the build still succeeds with
294
- `ReferenceEndpoints/SendEmailEndpoint.cs` added, the `__HOSTPROJECT__` token was replaced, and
295
- `POST /reference/email/send` is discoverable.
296
-
297
- ## Related
298
-
299
- - [README.md](./README.md) · [[components-readme]] · [[cqrs]] · [[clean-architecture]] ·
300
- [[vertical-slices]] · [[dependency-policy]] · [[ai-rules]]
@@ -1,113 +0,0 @@
1
- # Jobs Component (`AppWeaver.Jobs`)
2
-
3
- > Pure technology (domain-agnostic). Reference sheet for the background-job component.
4
- > To wire it into a project, follow the agent runbook in [integration.md](./integration.md).
5
- > Commands: `/aw-spec-add-component`.
6
-
7
- ## What it is
8
-
9
- A plug-and-play background-job framework. Application code depends only on the `IJobScheduler`
10
- and `IJobProgress` abstractions; the engine (Quartz.NET, optionally with EF Core status
11
- persistence) is a single registration decision. Supports **fire-and-forget**, **delayed**, and
12
- **recurring (CRON)** jobs with progress tracking, status polling, and cooperative cancellation.
13
-
14
- **Use when:** work must run outside the request thread — exports, batch processing, archival,
15
- report generation, scheduled maintenance, sending bulk notifications.
16
-
17
- ## Public contract (`AppWeaver.Jobs.Abstractions`)
18
-
19
- ```csharp
20
- public interface IJob { } // marker — implement on every job class
21
-
22
- public interface IJobScheduler
23
- {
24
- Task<string> EnqueueAsync<TJob>(Expression<Func<TJob, Task>> jobMethod,
25
- string? description = null, string? userId = null) where TJob : class, IJob;
26
-
27
- Task<string> ScheduleAsync<TJob>(Expression<Func<TJob, Task>> jobMethod, TimeSpan delay,
28
- string? description = null, string? userId = null) where TJob : class, IJob;
29
-
30
- Task AddOrUpdateRecurringAsync<TJob>(string jobId,
31
- Expression<Func<TJob, Task>> jobMethod, string cronExpression) where TJob : class, IJob;
32
-
33
- Task RemoveRecurringAsync(string jobId);
34
- Task<JobStatus?> GetStatusAsync(string jobId);
35
- Task<IEnumerable<JobStatus>> GetStatusesAsync(string userId, DateTime? from = null, DateTime? to = null);
36
- Task CancelAsync(string jobId);
37
- }
38
-
39
- public interface IJobProgress
40
- {
41
- Task ReportProgressAsync(int percent, string? message = null, object? progressDetails = null);
42
- Task ReportResultUrlAsync(string url);
43
- CancellationToken CancellationToken { get; } // check inside loops for cooperative cancel
44
- }
45
- ```
46
-
47
- `JobStatus` carries: `JobId`, `State`, `CreatedAt`, `StartedAt`, `CompletedAt`, `ProgressPercent`,
48
- `ProgressMessage`, `ResultUrl`, `ErrorMessage`, `Description`, `UserId`, `ProgressDetails`.
49
- `JobState` = `Pending → Running → Completed | Failed | Cancelled`.
50
-
51
- ## Packages
52
-
53
- | Package | Version | Role | Builder method |
54
- |---|---|---|---|
55
- | `AppWeaver.Jobs` | `0.1.1` | **Required.** Abstractions + `AddAppWeaverJobs` + facade. | — |
56
- | `AppWeaver.Jobs.Quartz` | `0.1.0` | **Recommended engine.** Quartz.NET scheduler; in-memory or persistent store. | `UseQuartzJobScheduler` |
57
- | `AppWeaver.Jobs.Persistence.EfCore` | `0.1.0` | EF Core persistence of `JobStatus`. | `UseEfCoreJobs` + `UseJobDatabase` / `UseAppWeaverDataStore` |
58
- | `AppWeaver.Jobs.InMemory` | `0.1.0` | ⚠️ **Work in progress — not functional. Do not use.** | — |
59
-
60
- **Recommended stack:** `AppWeaver.Jobs` + `AppWeaver.Jobs.Quartz` + `AppWeaver.Jobs.Persistence.EfCore`.
61
-
62
- ## Registration shapes
63
-
64
- ```csharp
65
- // In AppWeaver.Jobs.Extensions
66
- IComponentBuilder<IJobScheduler> AddAppWeaverJobs(
67
- this IServiceCollection services,
68
- Action<IComponentBuilder<IJobScheduler>> configureBuilder, // required
69
- Action<JobsConfiguration>? configureOptions = null, // set Provider = "Quartz"
70
- IConfiguration? configuration = null); // OR bind "AppWeaver:Jobs"
71
-
72
- // In AppWeaver.Jobs.Quartz.Extensions
73
- builder.UseQuartzJobScheduler(opts => { opts.MaxConcurrency = 10; opts.ConfigureQuartz = q => { … }; });
74
-
75
- // In AppWeaver.Jobs.Persistence.EfCore.Extensions (choose ONE store wiring)
76
- builder.UseEfCoreJobs().UseJobDatabase(opts => opts.UseSqlite("Data Source=jobs.db")); // standalone
77
- builder.UseEfCoreJobs().UseAppWeaverDataStore(); // shared DataStore
78
- ```
79
-
80
- `JobsConfiguration.Provider` (config section `AppWeaver:Jobs`) selects the engine key; for Quartz
81
- it is `"Quartz"`. `UseQuartzJobScheduler` registers `IJobProgress` (`QuartzJobProgress`) and a
82
- Quartz hosted service automatically.
83
-
84
- ## Persistence modes (EF Core)
85
-
86
- | Mode | Wiring | DbContext | Migration |
87
- |---|---|---|---|
88
- | **Standalone** | `.UseJobDatabase(opts => opts.UseXxx(conn))` | dedicated `JobStatusDbContext` | own migration / `EnsureCreated` |
89
- | **Shared DataStore** | `.UseAppWeaverDataStore()` (after `AddDataStore().UseEfCoreDataStore()`) | shares DataStore connection | Shared: in `SharedComponentDbContext` migration; Isolated: own migration |
90
-
91
- The Quartz **persistent store** (for distributed/durable scheduling) is configured separately via
92
- `opts.ConfigureQuartz = q => q.UsePersistentStore(...)` and needs the Quartz DDL applied to the DB.
93
- With no `ConfigureQuartz`, Quartz uses an in-memory store (single instance, lost on restart).
94
-
95
- ## Source map (framework)
96
-
97
- ```
98
- framework/Jobs/
99
- README.md ← full component manual (authoritative deep-dive)
100
- src/
101
- AppWeaver.Jobs/ ← IJob, IJobScheduler, IJobProgress, JobStatus, AddAppWeaverJobs
102
- AppWeaver.Jobs.Quartz/ ← UseQuartzJobScheduler + QuartzJobScheduler/Wrapper/Progress
103
- AppWeaver.Jobs.Persistence.EfCore/ ← UseEfCoreJobs/UseJobDatabase/UseAppWeaverDataStore
104
- AppWeaver.Jobs.InMemory/ ← ⚠️ WIP, not functional
105
- tests/
106
- AppWeaver.Jobs.Tests/ ← DefaultJobSchedulerTests
107
- TestApp/ ← Quartz + EF Core end-to-end scenarios (A–O)
108
- ```
109
-
110
- ## Related
111
-
112
- - [integration.md](./integration.md) · [[components-readme]] · [[cqrs]] ·
113
- [[persistence]] · [[clean-architecture]] · [[dependency-policy]]