@rashidee/co2 1.2.5

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 (190) hide show
  1. package/dist/index.js +25449 -0
  2. package/drizzle/0000_remarkable_charles_xavier.sql +210 -0
  3. package/drizzle/0001_wise_wolf_cub.sql +13 -0
  4. package/drizzle/0002_secret_spyke.sql +16 -0
  5. package/drizzle/0003_workspace_config_singleton.sql +16 -0
  6. package/drizzle/0004_terminal_claim_v120.sql +11 -0
  7. package/drizzle/0005_brainstorm_v124.sql +10 -0
  8. package/drizzle/0006_project_v140.sql +6 -0
  9. package/drizzle/0007_prd_wizard_v124.sql +14 -0
  10. package/drizzle/0008_workflow_artifact_v126.sql +24 -0
  11. package/drizzle/0009_project_import_v150.sql +7 -0
  12. package/drizzle/0010_quality_v151.sql +3 -0
  13. package/drizzle/meta/0000_snapshot.json +1335 -0
  14. package/drizzle/meta/0001_snapshot.json +1416 -0
  15. package/drizzle/meta/0002_snapshot.json +1510 -0
  16. package/drizzle/meta/_journal.json +83 -0
  17. package/package.json +41 -0
  18. package/plugin/.claude-plugin/marketplace.json +36 -0
  19. package/plugin/.claude-plugin/plugin.json +22 -0
  20. package/plugin/README.md +625 -0
  21. package/plugin/SKILLS.md +350 -0
  22. package/plugin/co2.svg +5 -0
  23. package/plugin/commands/brainstorm-loop.md +129 -0
  24. package/plugin/skills/conductor-defect/SKILL.md +898 -0
  25. package/plugin/skills/conductor-feature-develop/SKILL.md +1383 -0
  26. package/plugin/skills/conductor-feature-develop/references/implementation-domain-template.md +131 -0
  27. package/plugin/skills/conductor-feature-develop/references/implementation-master-template.md +89 -0
  28. package/plugin/skills/conductor-feature-develop/references/playwright-setup.md +224 -0
  29. package/plugin/skills/conductor-feature-prepare/SKILL.md +604 -0
  30. package/plugin/skills/depgen-k8s/SKILL.md +468 -0
  31. package/plugin/skills/depgen-k8s/references/dockerfile-laravel.md +197 -0
  32. package/plugin/skills/depgen-k8s/references/dockerfile-nodejs.md +163 -0
  33. package/plugin/skills/depgen-k8s/references/dockerfile-spring-boot.md +174 -0
  34. package/plugin/skills/depgen-k8s/references/k8s-patterns.md +869 -0
  35. package/plugin/skills/mockgen-shadcn/SKILL.md +1067 -0
  36. package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +1467 -0
  37. package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +498 -0
  38. package/plugin/skills/mockgen-shadcn/references/mockup-index-template.md +216 -0
  39. package/plugin/skills/mockgen-tailwind/SKILL.md +904 -0
  40. package/plugin/skills/mockgen-tailwind/references/admin-layout-template.md +720 -0
  41. package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +498 -0
  42. package/plugin/skills/mockgen-tailwind/references/mockup-index-template.md +190 -0
  43. package/plugin/skills/modelgen-nosql/SKILL.md +617 -0
  44. package/plugin/skills/modelgen-nosql/references/model-extraction-methodology.md +497 -0
  45. package/plugin/skills/modelgen-nosql/references/nosql-design-guide.md +258 -0
  46. package/plugin/skills/modelgen-relational/SKILL.md +707 -0
  47. package/plugin/skills/modelgen-relational/references/model-extraction-methodology.md +499 -0
  48. package/plugin/skills/specgen-flutter-riverpod/SKILL.md +898 -0
  49. package/plugin/skills/specgen-flutter-riverpod/references/component-patterns.md +971 -0
  50. package/plugin/skills/specgen-flutter-riverpod/references/notification-patterns.md +457 -0
  51. package/plugin/skills/specgen-flutter-riverpod/references/routing-patterns.md +362 -0
  52. package/plugin/skills/specgen-flutter-riverpod/references/security-patterns.md +709 -0
  53. package/plugin/skills/specgen-flutter-riverpod/references/spec-template.md +1566 -0
  54. package/plugin/skills/specgen-flutter-riverpod/references/state-patterns.md +518 -0
  55. package/plugin/skills/specgen-flutter-riverpod/references/storage-patterns.md +370 -0
  56. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/SKILL.md +984 -0
  57. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/batch-patterns.md +359 -0
  58. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/messaging-patterns.md +468 -0
  59. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/modulith-patterns.md +461 -0
  60. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/reporting-patterns.md +803 -0
  61. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/security-patterns.md +501 -0
  62. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/spec-template.md +1268 -0
  63. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/web-patterns.md +301 -0
  64. package/plugin/skills/specgen-node-cli-web/SKILL.md +561 -0
  65. package/plugin/skills/specgen-node-cli-web/references/auth-patterns.md +293 -0
  66. package/plugin/skills/specgen-node-cli-web/references/cli-packaging-patterns.md +250 -0
  67. package/plugin/skills/specgen-node-cli-web/references/server-patterns.md +247 -0
  68. package/plugin/skills/specgen-node-cli-web/references/spec-template.md +401 -0
  69. package/plugin/skills/specgen-node-cli-web/references/testing-patterns.md +174 -0
  70. package/plugin/skills/specgen-react-mui/SKILL.md +789 -0
  71. package/plugin/skills/specgen-react-mui/references/component-patterns.md +1077 -0
  72. package/plugin/skills/specgen-react-mui/references/reporting-patterns.md +1998 -0
  73. package/plugin/skills/specgen-react-mui/references/routing-patterns.md +461 -0
  74. package/plugin/skills/specgen-react-mui/references/security-patterns.md +599 -0
  75. package/plugin/skills/specgen-react-mui/references/spec-template.md +1030 -0
  76. package/plugin/skills/specgen-react-mui/references/state-patterns.md +327 -0
  77. package/plugin/skills/specgen-react-tailwind/SKILL.md +859 -0
  78. package/plugin/skills/specgen-react-tailwind/references/component-patterns.md +1212 -0
  79. package/plugin/skills/specgen-react-tailwind/references/reporting-patterns.md +1529 -0
  80. package/plugin/skills/specgen-react-tailwind/references/routing-patterns.md +669 -0
  81. package/plugin/skills/specgen-react-tailwind/references/security-patterns.md +656 -0
  82. package/plugin/skills/specgen-react-tailwind/references/spec-template.md +1237 -0
  83. package/plugin/skills/specgen-react-tailwind/references/state-patterns.md +327 -0
  84. package/plugin/skills/specgen-sdk-java/SKILL.md +933 -0
  85. package/plugin/skills/specgen-sdk-java/references/api-extraction-patterns.md +247 -0
  86. package/plugin/skills/specgen-sdk-java/references/http-client-patterns.md +495 -0
  87. package/plugin/skills/specgen-sdk-java/references/packaging-patterns.md +366 -0
  88. package/plugin/skills/specgen-sdk-java/references/spec-template.md +956 -0
  89. package/plugin/skills/specgen-spring-jpa-jtehtmx/SKILL.md +1284 -0
  90. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/batch-patterns.md +1224 -0
  91. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/jasper-patterns.md +1638 -0
  92. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/messaging-patterns.md +512 -0
  93. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/modulith-patterns.md +354 -0
  94. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/security-patterns.md +551 -0
  95. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/spec-template.md +2502 -0
  96. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/web-patterns.md +503 -0
  97. package/plugin/skills/specgen-spring-jpa-restapi/SKILL.md +990 -0
  98. package/plugin/skills/specgen-spring-jpa-restapi/references/batch-patterns.md +1224 -0
  99. package/plugin/skills/specgen-spring-jpa-restapi/references/messaging-patterns.md +512 -0
  100. package/plugin/skills/specgen-spring-jpa-restapi/references/modulith-patterns.md +279 -0
  101. package/plugin/skills/specgen-spring-jpa-restapi/references/reporting-patterns.md +1536 -0
  102. package/plugin/skills/specgen-spring-jpa-restapi/references/restapi-patterns.md +722 -0
  103. package/plugin/skills/specgen-spring-jpa-restapi/references/security-patterns.md +351 -0
  104. package/plugin/skills/specgen-spring-jpa-restapi/references/spec-template.md +553 -0
  105. package/plugin/skills/specgen-ts-cli/SKILL.md +861 -0
  106. package/plugin/skills/specgen-ts-cli/references/async-patterns.md +1101 -0
  107. package/plugin/skills/specgen-ts-cli/references/command-patterns.md +383 -0
  108. package/plugin/skills/specgen-ts-cli/references/config-patterns.md +430 -0
  109. package/plugin/skills/specgen-ts-cli/references/database-patterns.md +750 -0
  110. package/plugin/skills/specgen-ts-cli/references/packaging-patterns.md +426 -0
  111. package/plugin/skills/specgen-ts-cli/references/spec-template.md +1391 -0
  112. package/plugin/skills/specgen-ts-cli/references/testing-patterns.md +909 -0
  113. package/plugin/skills/testgen-functional/SKILL.md +1381 -0
  114. package/plugin/skills/tracegen-matrix/SKILL.md +243 -0
  115. package/plugin/skills/util-preparek8senv/SKILL.md +422 -0
  116. package/plugin/skills/util-projectinit/SKILL.md +307 -0
  117. package/plugin/skills/util-projectinit/reference/brainstorm-loop.md +129 -0
  118. package/plugin/skills/util-projectinit/reference/brainstorm-protocol.md +144 -0
  119. package/plugin/skills/util-projectinit/reference/brainstorm-setup-guide.md +153 -0
  120. package/plugin/skills/util-projectinit/reference/brainstorm-template-appdev.md +87 -0
  121. package/plugin/skills/util-projectinit/reference/co2-context-generation-guide.md +761 -0
  122. package/plugin/skills/util-projectsync/SKILL.md +501 -0
  123. package/plugin/skills/util-updprd/SKILL.md +324 -0
  124. package/plugin/skills/util-usanalyzer/SKILL.md +307 -0
  125. package/plugin/skills/util-ustagger/SKILL.md +154 -0
  126. package/static/assets/abnfDiagram-VRR7QNED-DvPuwyCV.js +1 -0
  127. package/static/assets/arc-DRKw7sjs.js +1 -0
  128. package/static/assets/architectureDiagram-ZJ3FMSHR-CaNcxUbC.js +36 -0
  129. package/static/assets/blockDiagram-677ZJIJ3-Demd4AOK.js +132 -0
  130. package/static/assets/c4Diagram-LMCZKHZV-PVKUfc2x.js +10 -0
  131. package/static/assets/channel-C2nVbuwv.js +1 -0
  132. package/static/assets/chunk-2Q5K7J3B-CExf8ww_.js +1 -0
  133. package/static/assets/chunk-32BRIVSS-CFPaoONF.js +1 -0
  134. package/static/assets/chunk-5VM5RSS4-DE2esM67.js +15 -0
  135. package/static/assets/chunk-EX3LRPZG-SON_YdDG.js +231 -0
  136. package/static/assets/chunk-JWPE2WC7-Qxah8LNr.js +1 -0
  137. package/static/assets/chunk-MOJQB5TN-BcWGQV3j.js +88 -0
  138. package/static/assets/chunk-RYQCIY6F-DkDj-OR5.js +1 -0
  139. package/static/assets/chunk-V7JOEXUC-BlI1Mrah.js +206 -0
  140. package/static/assets/chunk-VR4S4FIN-Agf__duj.js +1 -0
  141. package/static/assets/chunk-XXDRQBXY-B5CfAh85.js +1 -0
  142. package/static/assets/classDiagram-OUVF2IWQ-DXJIljsR.js +1 -0
  143. package/static/assets/classDiagram-v2-EOCWNBFH-DXJIljsR.js +1 -0
  144. package/static/assets/cose-bilkent-JH36ORCC-DO0cQkcy.js +1 -0
  145. package/static/assets/cynefin-VYW2F7L2-CfOnsnXc.js +178 -0
  146. package/static/assets/cynefinDiagram-TSTJHNR4-BJ8tULAv.js +62 -0
  147. package/static/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  148. package/static/assets/dagre-VKFMJZFB-DfjwzHqP.js +4 -0
  149. package/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  150. package/static/assets/diagram-FQU43EPY-CndSOIIM.js +3 -0
  151. package/static/assets/diagram-G47NLZAW-Czf5hN0Z.js +24 -0
  152. package/static/assets/diagram-NH7WQ7WH-COAyojGh.js +24 -0
  153. package/static/assets/diagram-OA4YK3LP-H8PoiN2m.js +30 -0
  154. package/static/assets/diagram-WEI45ONY-DzcaVzjp.js +41 -0
  155. package/static/assets/ebnfDiagram-CCIWWBDH-DPazGYLJ.js +1 -0
  156. package/static/assets/erDiagram-Q63AITRT-Bo-fubgF.js +85 -0
  157. package/static/assets/flowDiagram-23GEKE2U-CSvxUDwh.js +156 -0
  158. package/static/assets/ganttDiagram-NO4QXBWP-DnBveWX6.js +292 -0
  159. package/static/assets/gitGraphDiagram-IHSO6WYX-B3rVL8c-.js +106 -0
  160. package/static/assets/graph-C9eacEi8.js +1 -0
  161. package/static/assets/index-LZSQkLE2.css +41 -0
  162. package/static/assets/index-y7XDSgMG.js +495 -0
  163. package/static/assets/infoDiagram-FWYZ7A6U-CvWV9yy2.js +2 -0
  164. package/static/assets/init-Gi6I4Gst.js +1 -0
  165. package/static/assets/ishikawaDiagram-FXEZZL3T-DF28a1N6.js +70 -0
  166. package/static/assets/journeyDiagram-5HDEW3XC-CB6CugYk.js +139 -0
  167. package/static/assets/kanban-definition-HUTT4EX6-ResSLF6d.js +89 -0
  168. package/static/assets/katex-C5jXJg4s.js +257 -0
  169. package/static/assets/layout-DEXfKzaS.js +1 -0
  170. package/static/assets/linear-CLO--ryk.js +1 -0
  171. package/static/assets/map-Czzmt4hB.js +1 -0
  172. package/static/assets/mindmap-definition-LN4V7U3C-BvW3EbxX.js +96 -0
  173. package/static/assets/ordinal-Cboi1Yqb.js +1 -0
  174. package/static/assets/pegDiagram-2B236MQR-BHCgqrrM.js +1 -0
  175. package/static/assets/pieDiagram-ENE6RG2P-DVmCQ5FA.js +39 -0
  176. package/static/assets/quadrantDiagram-ABIIQ3AL-B3e5KR52.js +7 -0
  177. package/static/assets/railroadDiagram-RFXS5EU6-Csv5ysLc.js +1 -0
  178. package/static/assets/requirementDiagram-TGXJPOKE-DOMVzvnB.js +84 -0
  179. package/static/assets/sankeyDiagram-HTMAVEWB-B1dcTOvy.js +40 -0
  180. package/static/assets/sequenceDiagram-DBY2YBRQ-BY414yeO.js +162 -0
  181. package/static/assets/sizeCapture-X5ZJPWSS-CuJfrfBN.js +1 -0
  182. package/static/assets/stateDiagram-2N3HPSRC-FX4rJkzV.js +1 -0
  183. package/static/assets/stateDiagram-v2-6OUMAXLB-BVufbO_H.js +1 -0
  184. package/static/assets/swimlanes-5IMT3BWC-Sfy58mmv.js +2 -0
  185. package/static/assets/swimlanesDiagram-G3AALYLV-wDCDw08H.js +8 -0
  186. package/static/assets/timeline-definition-FHXFAJF6-CmV7by8p.js +120 -0
  187. package/static/assets/vennDiagram-L72KCM5P-FqIyFZFt.js +34 -0
  188. package/static/assets/wardleyDiagram-EHGQE667-BZ06O45i.js +78 -0
  189. package/static/assets/xychartDiagram-FW5EYKEG-BOkffR06.js +7 -0
  190. package/static/index.html +24 -0
@@ -0,0 +1,956 @@
1
+ # Specification Template — Java SDK (Multi-Release Fat JAR)
2
+
3
+ This is the authoritative template for the generated specification. The specification is
4
+ split into **two types of files**:
5
+
6
+ 1. **`SPECIFICATION.md`** (root) — Table of Contents, shared infrastructure, and all
7
+ library-level sections. Generated once per SDK.
8
+ 2. **`<module>/SPEC.md`** (per-module) — Self-contained module blueprint. Generated
9
+ once per module from PRD.md.
10
+
11
+ ```
12
+ specification/
13
+ ├── SPECIFICATION.md
14
+ ├── auth/
15
+ │ └── SPEC.md
16
+ ├── orders/
17
+ │ └── SPEC.md
18
+ └── ...
19
+ ```
20
+
21
+ Placeholders use `{{VARIABLE}}` syntax and must be replaced with values gathered from
22
+ context files.
23
+
24
+ Sections marked **[CONDITIONAL]** must only be included when the corresponding option
25
+ is selected.
26
+
27
+ **CRITICAL: Sample code requirement.** Every component in the spec MUST include a
28
+ complete, continuous code sample in a fenced code block (Java, XML, or JSON as
29
+ appropriate). The code must be self-explanatory and directly usable as a reference for
30
+ a coding agent. Do not describe components with bullet points alone — always accompany
31
+ descriptions with full code.
32
+
33
+ ---
34
+
35
+ # Part A: Root SPECIFICATION.md
36
+
37
+ Everything from this point until "Part B" goes into the root `SPECIFICATION.md` file.
38
+ A coding agent implements these shared sections **first**, before any module work.
39
+
40
+ ---
41
+
42
+ ## Table of Contents
43
+
44
+ ```markdown
45
+ ## Table of Contents
46
+
47
+ ### Shared Infrastructure
48
+ - [1. Project Overview](#1-project-overview)
49
+ - [2. Maven Configuration](#2-maven-configuration)
50
+ - [3. Source Layout](#3-source-layout)
51
+ - [4. OkHttpClient Setup](#4-okhttpclient-setup)
52
+ - [5. JSON Support](#5-json-support)
53
+ - [6. Error Model](#6-error-model)
54
+ - [7. Retry Strategy](#7-retry-strategy)
55
+ - [8. Authentication](#8-authentication)
56
+ - [9. Top-Level Client Facade](#9-top-level-client-facade)
57
+ - [10. Diagnostic Main](#10-diagnostic-main)
58
+ - [11. Logging Strategy](#11-logging-strategy)
59
+ - [12. Testing Strategy](#12-testing-strategy)
60
+ - [13. Packaging & Distribution](#13-packaging-distribution)
61
+ - [14. Public API Surface & Compatibility](#14-public-api-surface)
62
+ - [15. Fat JAR Verification](#15-fat-jar-verification)
63
+ - [16. Architecture Patterns](#16-architecture-patterns)
64
+
65
+ ### Modules
66
+ - [Auth](auth/SPEC.md)
67
+ - [Orders](orders/SPEC.md)
68
+ - ...(one link per module)...
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Section 1: Project Overview
74
+
75
+ ```markdown
76
+ # {{APPLICATION_NAME}} — SDK Technical Specification
77
+
78
+ **Application Name**: {{APPLICATION_NAME}}
79
+ **Artifact ID**: {{ARTIFACT_ID}}
80
+ **Group ID**: com.bestinet.urp
81
+ **Base Package**: {{BASE_PACKAGE}}
82
+ **JDK Baseline**: 8
83
+ **JDK Overlay**: 11 (via Multi-Release JAR)
84
+ **Build Tool**: Maven 3.9.x
85
+ **Description**: {{APP_DESCRIPTION}}
86
+ **Versions Covered**: v1.0.0 — v{{LATEST_VERSION}}
87
+
88
+ ### API Surface Source
89
+
90
+ **Source**: {{Swagger UI URL | OpenAPI Spec URL | OpenAPI Spec Path | "Inferred from user stories — no OpenAPI spec available"}}
91
+ **URL/Path**: {{actual url or path or "n/a"}}
92
+ **Number of operations**: {{count from spec or "unknown"}}
93
+
94
+ ### Optional Components (Auto-Determined)
95
+
96
+ **Protocols**: REST{{ + WebSocket | + SSE | + AMQP | + MQTT}}
97
+ **Authentication**: {{Bearer | API Key | mTLS | Basic | None}}
98
+ **Async API**: {{yes (all) | yes (long ops) | no}}
99
+ **Logging**: {{SLF4J facade | JUL}}
100
+
101
+ ### Technology Stack
102
+
103
+ | Component | Version |
104
+ |--------------------------|---------------|
105
+ | Java baseline (`release`)| 8 |
106
+ | Java overlay (`release`) | 11 |
107
+ | Maven | 3.9.x |
108
+ | OkHttp | 4.12.0 |
109
+
110
+ (Test-only and optional protocol dependencies omitted.)
111
+
112
+ ### Target Consumers
113
+
114
+ (List each consumer of the SDK, with a one-line description.)
115
+
116
+ | Consumer Application | Use Case |
117
+ |----------------------|----------|
118
+ | ... | ... |
119
+
120
+ ### Modules
121
+
122
+ | Module | Stories | Versions | Spec |
123
+ |--------|---------|----------|------|
124
+ | Auth | 4 | 1.0.0 | [SPEC](auth/SPEC.md) |
125
+ | Orders | 8 | 1.0.0 | [SPEC](orders/SPEC.md) |
126
+ | ... | ... | ... | ... |
127
+
128
+ ### Default Base URL
129
+
130
+ `{{DEFAULT_BASE_URL}}` (override at runtime via `Client.Builder#baseUrl`)
131
+
132
+ ### Input Sources
133
+
134
+ - CLAUDE.md: {{path}}
135
+ - PRD.md: {{path}}
136
+ - Module Model: {{path to MODEL.md or "n/a"}}
137
+ - OpenAPI: {{url or path or "n/a"}}
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Section 2: Maven Configuration
143
+
144
+ Generate a complete `pom.xml` inside a code block. Key requirements:
145
+
146
+ - `<packaging>jar</packaging>`
147
+ - `<properties>` with `maven.compiler.release=8` baseline
148
+ - One runtime dependency: `com.squareup.okhttp3:okhttp:4.12.0`
149
+ - Test-scoped: JUnit 5, AssertJ, OkHttp MockWebServer
150
+ - `<scope>provided</scope>` for `org.slf4j:slf4j-api` (only if Logging = SLF4J facade)
151
+ - `maven-compiler-plugin` with two executions:
152
+ - Default: compiles `src/main/java` to `target/classes` with `<release>8</release>`
153
+ - `compile-java11`: compiles `src/main/java11` to `target/classes-java11` with
154
+ `<release>11</release>`
155
+ - `maven-jar-plugin`: adds the JDK 11 overlay into `META-INF/versions/11/` and writes
156
+ `Multi-Release: true` in the manifest
157
+ - `maven-shade-plugin`:
158
+ - `<phase>package</phase>` execution
159
+ - Relocates `okhttp3` → `{{BASE_PACKAGE}}.shaded.okhttp3`
160
+ - Relocates `okio` → `{{BASE_PACKAGE}}.shaded.okio`
161
+ - Relocates `kotlin` → `{{BASE_PACKAGE}}.shaded.kotlin`
162
+ - `<ManifestResourceTransformer>` preserving `Multi-Release: true`
163
+ - `<filters>` excluding `META-INF/*.SF`, `*.DSA`, `*.RSA`
164
+ - `maven-source-plugin`, `maven-javadoc-plugin`, `maven-surefire-plugin`
165
+
166
+ The complete `pom.xml` MUST be written out in this section. See
167
+ `references/packaging-patterns.md` for the canonical configuration to copy in.
168
+
169
+ ---
170
+
171
+ ## Section 3: Source Layout
172
+
173
+ Render the full directory tree (see SKILL.md "Source Layout"). Annotate each directory
174
+ with one line explaining its purpose. Highlight that:
175
+
176
+ - `src/main/java/` is the JDK 8 baseline that supplies the COMPLETE public API
177
+ - `src/main/java11/` contains overlay implementations only — every overlay class MUST
178
+ also exist in `src/main/java/` with an identical signature
179
+ - `src/test/java/` contains MockWebServer-driven tests
180
+
181
+ ---
182
+
183
+ ## Section 4: OkHttpClient Setup
184
+
185
+ ### `http/HttpClientFactory.java`
186
+
187
+ Sample code (mandatory):
188
+
189
+ ```java
190
+ package {{BASE_PACKAGE}}.http;
191
+
192
+ import okhttp3.ConnectionPool;
193
+ import okhttp3.OkHttpClient;
194
+
195
+ import java.time.Duration;
196
+ import java.util.concurrent.TimeUnit;
197
+
198
+ final class HttpClientFactory {
199
+
200
+ private HttpClientFactory() {}
201
+
202
+ static OkHttpClient build({{ClientName}}Config config) {
203
+ OkHttpClient.Builder builder = new OkHttpClient.Builder()
204
+ .connectTimeout(config.connectTimeout().toMillis(), TimeUnit.MILLISECONDS)
205
+ .readTimeout(config.readTimeout().toMillis(), TimeUnit.MILLISECONDS)
206
+ .writeTimeout(config.writeTimeout().toMillis(), TimeUnit.MILLISECONDS)
207
+ .connectionPool(new ConnectionPool(
208
+ config.maxIdleConnections(),
209
+ config.keepAliveDuration().toMillis(),
210
+ TimeUnit.MILLISECONDS));
211
+
212
+ if (config.credentialProvider() != null) {
213
+ builder.addInterceptor(new AuthInterceptor(config.credentialProvider()));
214
+ }
215
+ builder.addInterceptor(new CorrelationIdInterceptor());
216
+ builder.addInterceptor(new RetryInterceptor(config.retryStrategy()));
217
+ if (Slf4jPresence.AVAILABLE) {
218
+ builder.addInterceptor(new LoggingInterceptor());
219
+ }
220
+ return builder.build();
221
+ }
222
+ }
223
+ ```
224
+
225
+ Document thread-safety rules:
226
+
227
+ - The returned `OkHttpClient` is built ONCE per `{{ClientName}}` instance.
228
+ - Consumers MUST reuse a single `{{ClientName}}` across the application lifetime.
229
+ - Closing: call `client.close()` on application shutdown to release the connection pool.
230
+
231
+ ---
232
+
233
+ ## Section 5: JSON Support
234
+
235
+ ### `json/Json.java`
236
+
237
+ A minimal hand-written JSON read/write utility. Key requirements:
238
+
239
+ - No reflection
240
+ - Operates on `Object` for read (`Map<String, Object>`, `List<Object>`, `String`,
241
+ `Number`, `Boolean`, `null`) and `JsonWriter`/`JsonReader` token streams for write.
242
+ - Supports the surface area the SDK actually needs — no full JSON Pointer, no
243
+ schema validation, no streaming for arbitrary trees.
244
+
245
+ Sample skeleton:
246
+
247
+ ```java
248
+ package {{BASE_PACKAGE}}.json;
249
+
250
+ import java.io.IOException;
251
+ import java.io.Reader;
252
+ import java.io.StringReader;
253
+ import java.io.Writer;
254
+
255
+ public final class Json {
256
+
257
+ private Json() {}
258
+
259
+ public static Object parse(String text) {
260
+ return new JsonReader(new StringReader(text)).readValue();
261
+ }
262
+
263
+ public static String stringify(Object value) {
264
+ StringBuilder sb = new StringBuilder();
265
+ new JsonWriter(sb).writeValue(value);
266
+ return sb.toString();
267
+ }
268
+
269
+ // JsonReader and JsonWriter implementations follow.
270
+ // Each model class provides its own:
271
+ // public void toJson(JsonWriter w) { ... }
272
+ // public static Foo fromJson(JsonReader r) { ... }
273
+ }
274
+ ```
275
+
276
+ Per-model serializer pattern (every request/response DTO follows this):
277
+
278
+ ```java
279
+ public Map<String, Object> toJsonMap() {
280
+ Map<String, Object> m = new LinkedHashMap<>();
281
+ if (id != null) m.put("id", id);
282
+ if (name != null) m.put("name", name);
283
+ if (status != null) m.put("status", status.wireValue());
284
+ return m;
285
+ }
286
+
287
+ public static OrderDto fromJsonMap(Map<String, Object> m) {
288
+ return OrderDto.builder()
289
+ .id((String) m.get("id"))
290
+ .name((String) m.get("name"))
291
+ .status(OrderStatus.fromWireValue((String) m.get("status")))
292
+ .build();
293
+ }
294
+ ```
295
+
296
+ The full `JsonReader`/`JsonWriter` implementations are non-trivial — generate them in
297
+ this section, fully expanded, even if the spec is otherwise terse.
298
+
299
+ ---
300
+
301
+ ## Section 6: Error Model
302
+
303
+ ```java
304
+ package {{BASE_PACKAGE}}.error;
305
+
306
+ public class SdkException extends RuntimeException {
307
+ public SdkException(String message) { super(message); }
308
+ public SdkException(String message, Throwable cause) { super(message, cause); }
309
+ }
310
+
311
+ public class SdkApiException extends SdkException {
312
+ private final int statusCode;
313
+ private final String body;
314
+ private final String method;
315
+ private final String url;
316
+
317
+ public SdkApiException(int statusCode, String body, String method, String url) {
318
+ super("HTTP " + statusCode + " " + method + " " + url);
319
+ this.statusCode = statusCode;
320
+ this.body = body;
321
+ this.method = method;
322
+ this.url = url;
323
+ }
324
+ public int statusCode() { return statusCode; }
325
+ public String body() { return body; }
326
+ public String method() { return method; }
327
+ public String url() { return url; }
328
+ }
329
+
330
+ public class SdkAuthException extends SdkApiException { /* 401 / 403 */ }
331
+ public class SdkClientException extends SdkException { /* local I/O */ }
332
+ public class SdkTimeoutException extends SdkClientException { /* socket timeout */ }
333
+ public class SdkRetryExhaustedException extends SdkClientException { /* retry budget */ }
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Section 7: Retry Strategy
339
+
340
+ ```java
341
+ public interface RetryStrategy {
342
+ Decision evaluate(int attempt, Response response, IOException error);
343
+
344
+ final class Decision {
345
+ public final boolean retry;
346
+ public final long delayMillis;
347
+ Decision(boolean retry, long delayMillis) {
348
+ this.retry = retry; this.delayMillis = delayMillis;
349
+ }
350
+ public static Decision stop() { return new Decision(false, 0L); }
351
+ public static Decision retryIn(long delayMs) { return new Decision(true, delayMs); }
352
+ }
353
+ }
354
+ ```
355
+
356
+ Default implementation `ExponentialBackoffRetryStrategy` retries on:
357
+
358
+ - `IOException` with cause `ConnectException` / `SocketTimeoutException`
359
+ - HTTP 502, 503, 504
360
+
361
+ Backoff: `min(maxBackoff, base * 2^attempt + jitter)`. Default base = 200ms,
362
+ maxBackoff = 5s, max attempts = 3.
363
+
364
+ Provide the full implementation in this section.
365
+
366
+ ---
367
+
368
+ ## Section 8: Authentication [CONDITIONAL]
369
+
370
+ Refer to the SKILL.md "Authentication" section. Generate the relevant code:
371
+
372
+ - `BearerCredentialProvider` interface + `StaticBearerCredentialProvider`
373
+ - `AuthInterceptor` that reads from the provider, sets `Authorization` header, and on 401
374
+ invokes `provider.refresh()` and replays the request once.
375
+ - Redact the `Authorization` header in `LoggingInterceptor`.
376
+
377
+ For API key, mTLS, or Basic, follow the patterns documented in
378
+ `references/http-client-patterns.md`.
379
+
380
+ ---
381
+
382
+ ## Section 9: Top-Level Client Facade
383
+
384
+ ```java
385
+ package {{BASE_PACKAGE}};
386
+
387
+ import okhttp3.OkHttpClient;
388
+ import {{BASE_PACKAGE}}.http.HttpClientFactory;
389
+ import {{BASE_PACKAGE}}.auth.AuthService;
390
+ import {{BASE_PACKAGE}}.orders.OrdersService;
391
+
392
+ import java.time.Duration;
393
+ import java.util.Objects;
394
+
395
+ public final class {{ClientName}} implements AutoCloseable {
396
+
397
+ private final {{ClientName}}Config config;
398
+ private final OkHttpClient http;
399
+ private final AuthService authService;
400
+ private final OrdersService ordersService;
401
+
402
+ private {{ClientName}}({{ClientName}}Config config, OkHttpClient http) {
403
+ this.config = config;
404
+ this.http = http;
405
+ this.authService = new {{BASE_PACKAGE}}.auth.internal.AuthServiceImpl(http, config);
406
+ this.ordersService = new {{BASE_PACKAGE}}.orders.internal.OrdersServiceImpl(http, config);
407
+ }
408
+
409
+ public static Builder builder() { return new Builder(); }
410
+
411
+ public AuthService auth() { return authService; }
412
+ public OrdersService orders() { return ordersService; }
413
+
414
+ @Override
415
+ public void close() {
416
+ http.dispatcher().executorService().shutdown();
417
+ http.connectionPool().evictAll();
418
+ }
419
+
420
+ public static final class Builder {
421
+ private String baseUrl;
422
+ private Duration connectTimeout = Duration.ofSeconds(30);
423
+ private Duration readTimeout = Duration.ofSeconds(30);
424
+ private Duration writeTimeout = Duration.ofSeconds(30);
425
+ private RetryStrategy retryStrategy = RetryStrategy.defaultStrategy();
426
+ private CredentialProvider credentialProvider;
427
+ // ...one setter per Config field...
428
+
429
+ public Builder baseUrl(String baseUrl) { this.baseUrl = baseUrl; return this; }
430
+ public Builder connectTimeout(Duration d) { this.connectTimeout = d; return this; }
431
+ // ...etc...
432
+
433
+ public {{ClientName}} build() {
434
+ Objects.requireNonNull(baseUrl, "baseUrl is required");
435
+ {{ClientName}}Config cfg = new {{ClientName}}Config(
436
+ baseUrl, connectTimeout, readTimeout, writeTimeout,
437
+ retryStrategy, credentialProvider /* , ... */);
438
+ return new {{ClientName}}(cfg, HttpClientFactory.build(cfg));
439
+ }
440
+ }
441
+ }
442
+ ```
443
+
444
+ Generate `{{ClientName}}Config` as a final class with `private final` fields, all
445
+ accessors named without `get` prefix (e.g., `baseUrl()`), and a package-private
446
+ constructor. No setters.
447
+
448
+ ---
449
+
450
+ ## Section 10: Diagnostic Main [CONDITIONAL]
451
+
452
+ If included:
453
+
454
+ ```java
455
+ package {{BASE_PACKAGE}}.cli;
456
+
457
+ import {{BASE_PACKAGE}}.{{ClientName}};
458
+
459
+ public final class Diagnose {
460
+ public static void main(String[] args) throws Exception {
461
+ String baseUrl = System.getenv("BASE_URL");
462
+ String token = System.getenv("API_TOKEN");
463
+ if (baseUrl == null) {
464
+ System.err.println("BASE_URL env var is required");
465
+ System.exit(2);
466
+ }
467
+ try ({{ClientName}} client = {{ClientName}}.builder()
468
+ .baseUrl(baseUrl)
469
+ /* .credentials(BearerCredentialProvider.of(token)) */
470
+ .build()) {
471
+ System.out.println("SDK initialised against " + baseUrl);
472
+ // Make a single smoke-test call here.
473
+ }
474
+ }
475
+ }
476
+ ```
477
+
478
+ The fat-JAR manifest's `Main-Class` points to this class only if Diagnose is included.
479
+
480
+ ---
481
+
482
+ ## Section 11: Logging Strategy
483
+
484
+ If Logging = SLF4J facade:
485
+
486
+ - `org.slf4j:slf4j-api` is `<scope>provided</scope>` — NOT bundled.
487
+ - The SDK uses `LoggerFactory.getLogger(...)`. If the consumer has no SLF4J binding,
488
+ no-op output is the standard SLF4J behaviour.
489
+ - The `LoggingInterceptor` is registered ONLY if `org.slf4j.Logger` is on the classpath
490
+ (use a class-presence check):
491
+
492
+ ```java
493
+ final class Slf4jPresence {
494
+ static final boolean AVAILABLE = isAvailable();
495
+
496
+ private static boolean isAvailable() {
497
+ try {
498
+ Class.forName("org.slf4j.Logger");
499
+ return true;
500
+ } catch (ClassNotFoundException e) {
501
+ return false;
502
+ }
503
+ }
504
+ }
505
+ ```
506
+
507
+ If Logging = JUL: every component uses `java.util.logging.Logger.getLogger(...)`.
508
+ No external dependency. No facade.
509
+
510
+ ---
511
+
512
+ ## Section 12: Testing Strategy
513
+
514
+ ```java
515
+ package {{BASE_PACKAGE}}.orders;
516
+
517
+ import okhttp3.mockwebserver.MockResponse;
518
+ import okhttp3.mockwebserver.MockWebServer;
519
+ import {{BASE_PACKAGE}}.{{ClientName}};
520
+ import {{BASE_PACKAGE}}.orders.model.OrderDto;
521
+ import org.junit.jupiter.api.AfterEach;
522
+ import org.junit.jupiter.api.BeforeEach;
523
+ import org.junit.jupiter.api.Test;
524
+
525
+ import static org.assertj.core.api.Assertions.assertThat;
526
+
527
+ class OrdersServiceTest {
528
+
529
+ private MockWebServer server;
530
+ private {{ClientName}} client;
531
+
532
+ @BeforeEach
533
+ void setUp() throws Exception {
534
+ server = new MockWebServer();
535
+ server.start();
536
+ client = {{ClientName}}.builder()
537
+ .baseUrl(server.url("/").toString())
538
+ .build();
539
+ }
540
+
541
+ @AfterEach
542
+ void tearDown() throws Exception {
543
+ client.close();
544
+ server.shutdown();
545
+ }
546
+
547
+ @Test
548
+ void getById_returnsOrder() {
549
+ server.enqueue(new MockResponse()
550
+ .setResponseCode(200)
551
+ .setHeader("Content-Type", "application/json")
552
+ .setBody("{\"id\":\"ORD-123\",\"status\":\"NEW\"}"));
553
+
554
+ OrderDto order = client.orders().getById("ORD-123");
555
+
556
+ assertThat(order.id()).isEqualTo("ORD-123");
557
+ assertThat(order.status()).isEqualTo(OrderStatus.NEW);
558
+ }
559
+ }
560
+ ```
561
+
562
+ Every module's `*ServiceTest` follows this pattern. Document one full class here; per-
563
+ module SPEC.md only lists the test scenarios.
564
+
565
+ ---
566
+
567
+ ## Section 13: Packaging & Distribution
568
+
569
+ Refer to `references/packaging-patterns.md`. Render the full `maven-shade-plugin` and
570
+ `maven-jar-plugin` configurations and the `mvn package` / `mvn deploy` invocations.
571
+
572
+ ---
573
+
574
+ ## Section 14: Public API Surface & Compatibility
575
+
576
+ - Every public type and method is javadoc'd.
577
+ - Every introduction is annotated with `@since` matching the introducing version.
578
+ - Removed APIs are `@Deprecated(forRemoval = true, since = "x.y.z")` for at least one
579
+ minor version before removal.
580
+ - Optional: `revapi-maven-plugin` configured in the build to fail the build on
581
+ binary-incompatible changes.
582
+
583
+ ---
584
+
585
+ ## Section 15: Fat JAR Verification
586
+
587
+ Manual verification commands:
588
+
589
+ ```
590
+ mvn clean package
591
+ jar tf target/{{ARTIFACT_ID}}-{{VERSION}}.jar | head -50
592
+ unzip -p target/{{ARTIFACT_ID}}-{{VERSION}}.jar META-INF/MANIFEST.MF
593
+ jar tf target/{{ARTIFACT_ID}}-{{VERSION}}.jar | grep "META-INF/versions/11/"
594
+ jar tf target/{{ARTIFACT_ID}}-{{VERSION}}.jar | grep -E "^okhttp3/|^okio/|^kotlin/" || echo "ok: no unrelocated transitives"
595
+ ```
596
+
597
+ Expected:
598
+
599
+ - `META-INF/MANIFEST.MF` contains `Multi-Release: true`
600
+ - `META-INF/versions/11/` is non-empty
601
+ - No `okhttp3/`, `okio/`, or `kotlin/` packages at root (they live under
602
+ `{{BASE_PACKAGE}}/shaded/...`)
603
+
604
+ Functional verification:
605
+
606
+ ```
607
+ JAVA_HOME=/path/to/jdk-8 java -jar target/{{ARTIFACT_ID}}-{{VERSION}}.jar
608
+ JAVA_HOME=/path/to/jdk-11 java -jar target/{{ARTIFACT_ID}}-{{VERSION}}.jar
609
+ JAVA_HOME=/path/to/jdk-17 java -jar target/{{ARTIFACT_ID}}-{{VERSION}}.jar
610
+ JAVA_HOME=/path/to/jdk-21 java -jar target/{{ARTIFACT_ID}}-{{VERSION}}.jar
611
+ ```
612
+
613
+ (Only if Diagnose main is included.)
614
+
615
+ ---
616
+
617
+ ## Section 16: Architecture Patterns
618
+
619
+ Render the table extracted in the SKILL.md "Architecture Principle Extraction" step,
620
+ with one row per pattern and a one-paragraph explanation of where it appears in the
621
+ codebase. Include only patterns that the PRD's Architecture Principle section actually
622
+ mentions, plus the always-on defaults (Adapter, Builder, Strategy).
623
+
624
+ ---
625
+
626
+ # Part B: Module SPEC.md Template
627
+
628
+ Everything below is the template for each `<module>/SPEC.md` file. Generate one file
629
+ per module from PRD.md.
630
+
631
+ Each module SPEC.md is **self-contained** — a coding agent picks it up and implements
632
+ the entire module independently (after the shared infrastructure from
633
+ `SPECIFICATION.md` is in place).
634
+
635
+ ---
636
+
637
+ ## Module SPEC.md Structure
638
+
639
+ ```markdown
640
+ # {{ModuleName}} Module — SDK Specification
641
+
642
+ > Part of [{{APPLICATION_NAME}} SDK Technical Specification](../SPECIFICATION.md)
643
+
644
+ ## Overview
645
+
646
+ **Module:** {{ModuleName}}
647
+ **Package:** {{BASE_PACKAGE}}.{{modulename}}
648
+ **Public Service:** {{Module}}Service
649
+ **Internal Implementation:** {{BASE_PACKAGE}}.{{modulename}}.internal.{{Module}}ServiceImpl
650
+ ```
651
+
652
+ ### Traceability
653
+
654
+ ```markdown
655
+ ## Traceability
656
+
657
+ ### User Stories
658
+ | ID | Version | Description |
659
+ |---|---|---|
660
+ | USSDK00012 | v1.0.0 | List orders by status |
661
+
662
+ ### Non-Functional Requirements
663
+ | ID | Version | Description |
664
+ |---|---|---|
665
+ | NFRSDK0006 | v1.0.0 | Default per-call timeout 30s |
666
+
667
+ ### Constraints
668
+ | ID | Version | Description |
669
+ |---|---|---|
670
+ | CONSSDK003 | v1.0.0 | Backwards-compatible within major version |
671
+
672
+ ### Tests
673
+ | ID | Version | Description |
674
+ |---|---|---|
675
+ | TSDK00009 | v1.0.0 | MockWebServer 200/empty array → empty list |
676
+
677
+ ### References
678
+ | ID | Version | Description |
679
+ |---|---|---|
680
+ | REFSDK001 | v1.0.0 | Upstream API docs at https://api.example.com/docs |
681
+
682
+ ### Removed / Replaced
683
+ | ID | Type | Removed In | Replaced By | Reason |
684
+ |---|---|---|---|---|
685
+ | _None._ | | | | |
686
+ ```
687
+
688
+ ### OpenAPI Operation Mapping
689
+
690
+ ```markdown
691
+ ## OpenAPI Operation Mapping
692
+
693
+ | User Story | Operation ID | Method | Path | Request Schema | Response Schema |
694
+ |---|---|---|---|---|---|
695
+ | USSDK00012 | listOrders | GET | /orders | (query) | OrdersPage |
696
+ | USSDK00013 | getOrderById | GET | /orders/{id} | — | Order |
697
+ | USSDK00014 | createOrder | POST | /orders | OrderCreateRequest | Order |
698
+ ```
699
+
700
+ If no OpenAPI spec was available, replace the table with one derived from user stories
701
+ alone and add `[TODO]` notes where the upstream operation ID is unknown.
702
+
703
+ ### Public API
704
+
705
+ For each component, render a complete code sample.
706
+
707
+ #### Service Interface
708
+
709
+ ```java
710
+ package {{BASE_PACKAGE}}.{{modulename}};
711
+
712
+ import {{BASE_PACKAGE}}.{{modulename}}.model.OrderDto;
713
+ import {{BASE_PACKAGE}}.common.Page;
714
+
715
+ import java.util.concurrent.CompletableFuture;
716
+
717
+ public interface {{Module}}Service {
718
+
719
+ /** USSDK00012 — list orders, paginated. @since 1.0.0 */
720
+ Page<OrderDto> list(OrderListQuery query);
721
+
722
+ /** USSDK00013 — get order by id. @since 1.0.0 */
723
+ OrderDto getById(String id);
724
+
725
+ /** USSDK00014 — create order. @since 1.0.0 */
726
+ OrderDto create(OrderCreateRequest request);
727
+
728
+ // Async overloads if Async API = yes
729
+ // CompletableFuture<Page<OrderDto>> listAsync(OrderListQuery query);
730
+ }
731
+ ```
732
+
733
+ #### Request DTOs
734
+
735
+ ```java
736
+ package {{BASE_PACKAGE}}.{{modulename}}.model;
737
+
738
+ import java.util.Objects;
739
+
740
+ public final class OrderCreateRequest {
741
+
742
+ private final String customerId;
743
+ private final String currency;
744
+ private final long amountCents;
745
+
746
+ private OrderCreateRequest(Builder b) {
747
+ this.customerId = Objects.requireNonNull(b.customerId, "customerId");
748
+ this.currency = Objects.requireNonNull(b.currency, "currency");
749
+ this.amountCents = b.amountCents;
750
+ }
751
+
752
+ public String customerId() { return customerId; }
753
+ public String currency() { return currency; }
754
+ public long amountCents() { return amountCents; }
755
+
756
+ public static Builder builder() { return new Builder(); }
757
+
758
+ public static final class Builder {
759
+ private String customerId;
760
+ private String currency;
761
+ private long amountCents;
762
+ public Builder customerId(String s) { this.customerId = s; return this; }
763
+ public Builder currency(String s) { this.currency = s; return this; }
764
+ public Builder amountCents(long n) { this.amountCents = n; return this; }
765
+ public OrderCreateRequest build() { return new OrderCreateRequest(this); }
766
+ }
767
+ }
768
+ ```
769
+
770
+ #### Response DTOs
771
+
772
+ ```java
773
+ package {{BASE_PACKAGE}}.{{modulename}}.model;
774
+
775
+ public final class OrderDto {
776
+
777
+ private final String id;
778
+ private final String customerId;
779
+ private final OrderStatus status;
780
+ private final long amountCents;
781
+
782
+ private OrderDto(Builder b) { /* ... */ }
783
+
784
+ public String id() { return id; }
785
+ public String customerId() { return customerId; }
786
+ public OrderStatus status() { return status; }
787
+ public long amountCents() { return amountCents; }
788
+
789
+ public static Builder builder() { return new Builder(); }
790
+
791
+ public static OrderDto fromJsonMap(java.util.Map<String, Object> m) { /* ... */ }
792
+ public java.util.Map<String, Object> toJsonMap() { /* ... */ }
793
+
794
+ public static final class Builder { /* same shape as above */ }
795
+ }
796
+ ```
797
+
798
+ #### Module Exception
799
+
800
+ ```java
801
+ package {{BASE_PACKAGE}}.{{modulename}};
802
+
803
+ import {{BASE_PACKAGE}}.error.SdkApiException;
804
+
805
+ public class {{Module}}Exception extends SdkApiException {
806
+ public {{Module}}Exception(int statusCode, String body, String method, String url) {
807
+ super(statusCode, body, method, url);
808
+ }
809
+
810
+ public static class NotFound extends {{Module}}Exception { /* 404 */ }
811
+ public static class Conflict extends {{Module}}Exception { /* 409 */ }
812
+ }
813
+ ```
814
+
815
+ ### Internal Implementation
816
+
817
+ #### URL Constants
818
+
819
+ ```java
820
+ package {{BASE_PACKAGE}}.{{modulename}}.internal;
821
+
822
+ final class OrderPaths {
823
+ private OrderPaths() {}
824
+
825
+ static final String LIST = "/orders";
826
+ static final String BY_ID = "/orders/%s";
827
+
828
+ static String byId(String id) { return String.format(BY_ID, id); }
829
+ }
830
+ ```
831
+
832
+ #### Service Implementation
833
+
834
+ ```java
835
+ package {{BASE_PACKAGE}}.{{modulename}}.internal;
836
+
837
+ import okhttp3.HttpUrl;
838
+ import okhttp3.MediaType;
839
+ import okhttp3.OkHttpClient;
840
+ import okhttp3.Request;
841
+ import okhttp3.RequestBody;
842
+ import okhttp3.Response;
843
+
844
+ import {{BASE_PACKAGE}}.{{ClientName}}Config;
845
+ import {{BASE_PACKAGE}}.error.SdkClientException;
846
+ import {{BASE_PACKAGE}}.json.Json;
847
+ import {{BASE_PACKAGE}}.{{modulename}}.{{Module}}Service;
848
+ import {{BASE_PACKAGE}}.{{modulename}}.{{Module}}Exception;
849
+ import {{BASE_PACKAGE}}.{{modulename}}.model.OrderDto;
850
+
851
+ import java.io.IOException;
852
+ import java.util.Map;
853
+
854
+ public final class {{Module}}ServiceImpl implements {{Module}}Service {
855
+
856
+ private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
857
+
858
+ private final OkHttpClient http;
859
+ private final {{ClientName}}Config config;
860
+
861
+ public {{Module}}ServiceImpl(OkHttpClient http, {{ClientName}}Config config) {
862
+ this.http = http;
863
+ this.config = config;
864
+ }
865
+
866
+ @Override
867
+ public OrderDto getById(String id) {
868
+ HttpUrl url = HttpUrl.parse(config.baseUrl())
869
+ .newBuilder()
870
+ .addPathSegments("orders/" + id)
871
+ .build();
872
+
873
+ Request req = new Request.Builder()
874
+ .url(url)
875
+ .header("Accept", "application/json")
876
+ .get()
877
+ .build();
878
+
879
+ try (Response resp = http.newCall(req).execute()) {
880
+ if (resp.code() == 404) {
881
+ throw new {{Module}}Exception.NotFound(404, body(resp), "GET", url.toString());
882
+ }
883
+ if (!resp.isSuccessful()) {
884
+ throw new {{Module}}Exception(resp.code(), body(resp), "GET", url.toString());
885
+ }
886
+ @SuppressWarnings("unchecked")
887
+ Map<String, Object> map = (Map<String, Object>) Json.parse(body(resp));
888
+ return OrderDto.fromJsonMap(map);
889
+ } catch (IOException e) {
890
+ throw new SdkClientException("GET " + url + " failed", e);
891
+ }
892
+ }
893
+
894
+ private static String body(Response resp) throws IOException {
895
+ return resp.body() != null ? resp.body().string() : "";
896
+ }
897
+
898
+ // Implementations for list(...) and create(...) follow the same pattern.
899
+ }
900
+ ```
901
+
902
+ ### Error Mapping
903
+
904
+ ```markdown
905
+ ## Error Mapping
906
+
907
+ | HTTP Status | Exception | Notes |
908
+ |-------------|------------------------------------|--------------------------------------|
909
+ | 400 | {{Module}}Exception (root) | Validation error from server |
910
+ | 401 | SdkAuthException | Triggers 1× refresh-and-retry |
911
+ | 403 | SdkAuthException | Surfaced to caller |
912
+ | 404 | {{Module}}Exception.NotFound | |
913
+ | 409 | {{Module}}Exception.Conflict | |
914
+ | 429 | retried by RetryInterceptor | Exhaustion → SdkRetryExhaustedException |
915
+ | 5xx | retried by RetryInterceptor | Exhaustion → {{Module}}Exception |
916
+ ```
917
+
918
+ ### Test Plan
919
+
920
+ Derive scenarios from the PRD `### Test` items for this module. Each row maps to one
921
+ JUnit `@Test`.
922
+
923
+ ```markdown
924
+ ## Test Plan
925
+
926
+ | Test ID | Scenario | Mock Response |
927
+ |------------|-------------------------------------------------|----------------------------------------|
928
+ | TSDK00009 | getById on existing order | 200 + `{"id":"ORD-1","status":"NEW"}` |
929
+ | TSDK00010 | getById on missing order | 404 |
930
+ | TSDK00011 | list with status filter | 200 + array of 3 items |
931
+ | TSDK00012 | create with invalid amount | 400 + error body |
932
+ | TSDK00013 | retry on 503 | 503, 503, 200 |
933
+ ```
934
+
935
+ ### External References
936
+
937
+ ```markdown
938
+ ## External References
939
+
940
+ | Ref ID | Version | Title | URL |
941
+ |-----------|---------|----------------------------------|----------------------------------|
942
+ | REFSDK001 | v1.0.0 | Upstream Orders API docs | https://api.example.com/orders |
943
+ ```
944
+
945
+ ### Critical Rules for Module SPEC.md
946
+
947
+ 1. Use actual field names from MODEL.md / OpenAPI schemas.
948
+ 2. Use actual operation IDs and paths from the OpenAPI spec when available.
949
+ 3. Define service methods mapping to actual user stories (by tag ID).
950
+ 4. Map HTTP status codes to specific exception subclasses.
951
+ 5. List user story IDs, NFR IDs, constraint IDs, test IDs, reference IDs with versions.
952
+ 6. Include complete, continuous code samples — no `// ...` gaps.
953
+ 7. Follow all SDK constraints (constructor injection, immutable models, no Lombok, no
954
+ reflection-based JSON).
955
+ 8. Include "Removed / Replaced" subsection.
956
+ 9. Test plan rows MUST trace back to PRD `### Test` items where possible.