@pukujan/create-modular-monolith 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +91 -22
  2. package/index.js +47 -0
  3. package/package.json +16 -19
  4. package/template/.cursor/commands/planning-study-log.md +25 -0
  5. package/template/.cursor/commands/pre-push-dev-log.md +52 -0
  6. package/template/.cursor/rules/api-documentation.mdc +21 -0
  7. package/template/.cursor/rules/file-exchange-inbox.mdc +29 -0
  8. package/template/AGENTS.md +41 -0
  9. package/template/README.md +18 -57
  10. package/template/backend/.env.example +38 -0
  11. package/template/backend/package.json +14 -4
  12. package/template/backend/src/modules/model-condenser/README.md +7 -0
  13. package/template/backend/src/modules/model-condenser/config/index.js +20 -0
  14. package/template/backend/src/modules/model-condenser/events/index.js +1 -0
  15. package/template/backend/src/modules/model-condenser/index.js +12 -0
  16. package/template/backend/src/modules/model-condenser/routes/health.routes.js +10 -0
  17. package/template/backend/src/modules/model-condenser/routes/index.js +10 -0
  18. package/template/backend/src/modules/model-condenser/routes/modelCondenser.routes.js +44 -0
  19. package/template/backend/src/modules/model-condenser/services/health.service.js +8 -0
  20. package/template/backend/src/modules/model-condenser/services/modelCondenser.facade.js +58 -0
  21. package/template/backend/src/modules/model-condenser/services/modelCondenser.service.js +513 -0
  22. package/template/backend/src/modules/model-condenser/tests/integration/modelCondenser.routes.test.js +40 -0
  23. package/template/backend/src/modules/model-condenser/tests/unit/modelCondenser.service.test.js +31 -0
  24. package/template/backend/src/modules/model-condenser/utils/index.js +1 -0
  25. package/template/backend/src/shared/contracts/consolidatedExports.contract.js +19 -0
  26. package/template/backend/src/shared/contracts/prePushDevLog.contract.js +28 -0
  27. package/template/backend/src/shared/domain/case-filing/core-models.js +117 -0
  28. package/template/backend/src/shared/http/errors.js +8 -0
  29. package/template/backend/src/shared/utils/consolidatedExport.js +30 -0
  30. package/template/backend/src/shared/utils/formatExchangeTimestamp.js +47 -0
  31. package/template/backend/src/shared/utils/formatExchangeTimestamp.test.js +30 -0
  32. package/template/docs/API.md +42 -0
  33. package/template/docs/PUBLISHING.md +13 -1
  34. package/template/docs/README.md +4 -0
  35. package/template/docs/STARTER_PACK.md +4 -0
  36. package/template/docs/architecture/API_DOCUMENTATION_CONTRACT.md +112 -0
  37. package/template/docs/architecture/CONTRACTS_OVERVIEW.md +168 -0
  38. package/template/docs/architecture/MODULE_INTERNAL_CONTRACT.md +2 -0
  39. package/template/docs/architecture/PLATFORM_ARCHITECTURE.md +221 -0
  40. package/template/docs/architecture/REPO_ARTIFACT_LAYOUT.md +76 -0
  41. package/template/docs/architecture/contracts/apiDocumentationRegistry.contract.md +40 -0
  42. package/template/docs/architecture/contracts/changelog.jsonl +12 -0
  43. package/template/docs/architecture/contracts/consolidatedExports.contract.md +58 -0
  44. package/template/docs/architecture/contracts/fileExchange.contract.md +47 -0
  45. package/template/docs/architecture/contracts/manifest.json +56 -0
  46. package/template/docs/architecture/contracts/prePushDevLog.contract.md +69 -0
  47. package/template/docs/model-condenser/API.md +102 -0
  48. package/template/file-exchange/README.md +41 -0
  49. package/template/file-exchange/exports/.gitkeep +0 -0
  50. package/template/file-exchange/imports/.gitkeep +0 -0
  51. package/template/frontend/.env.example +2 -0
  52. package/template/frontend/package.json +1 -1
  53. package/template/frontend/src/index.css +311 -0
  54. package/template/frontend/src/modules/_reference/services/health-api.js +1 -1
  55. package/template/frontend/src/shared/api/client.js +67 -5
  56. package/template/models/.gitkeep +0 -0
  57. package/template/package.json +11 -4
  58. package/template/scripts/check-api-docs.mjs +183 -0
  59. package/template/scripts/condense-file-structure.mjs +44 -0
  60. package/template/scripts/condense-models.mjs +70 -0
  61. package/template/scripts/condense-prompts.mjs +161 -0
  62. package/template/scripts/consolidated-output.mjs +49 -0
  63. package/template/scripts/export-consolidated-models.mjs +11 -0
  64. package/template/scripts/git-hooks/pre-push.sample +15 -0
  65. package/template/scripts/import-to-file-exchange.mjs +43 -0
  66. package/template/scripts/lib/api-inventory.mjs +189 -0
  67. package/template/scripts/lib/dev-log-human-format.mjs +360 -0
  68. package/template/scripts/lib/git-snapshot.mjs +46 -0
  69. package/template/scripts/lib/module-scaffold.mjs +37 -1
  70. package/template/scripts/lib/repo-tree.mjs +127 -0
  71. package/template/scripts/lib/run-tests.mjs +60 -0
  72. package/template/scripts/lint-contracts.mjs +57 -0
  73. package/template/scripts/lint-repo-artifacts.mjs +37 -0
  74. package/template/scripts/new-module.mjs +7 -0
  75. package/template/scripts/resolve-import-stamp.mjs +50 -0
  76. package/template/scripts/verify-dev-log.mjs +50 -0
  77. package/template/scripts/write-pre-push-dev-log.mjs +220 -0
  78. package/template/work-log/INDEX.md +3 -0
  79. package/template/work-log/README.md +40 -0
  80. package/template/work-log/dev-logs/README.md +97 -0
  81. package/template/work-log/dev-logs/schemas/dev-log-agent.v1.schema.json +119 -0
  82. package/template/work-log/dev-logs/templates/dev-log-human.template.md +10 -0
  83. package/template/work-log/handoffs/README.md +36 -0
  84. package/template/work-log/study-docs/README.md +13 -0
  85. package/bin/create-modular-monolith.js +0 -132
  86. package/template/backend/package-lock.json +0 -882
  87. package/template/backend/src/modules/_reference/evals/README.md +0 -6
  88. package/template/backend/src/modules/_reference/evals/datasets/example.cases.json +0 -12
  89. package/template/backend/src/modules/_reference/evals/runners/example.eval.mjs +0 -25
  90. package/template/frontend/package-lock.json +0 -1724
  91. package/template/scripts/run-module-evals.mjs +0 -43
  92. package/template/scripts/sync-cli-template.mjs +0 -44
  93. /package/template/{frontend/src/modules → backend/db/migrations}/.gitkeep +0 -0
@@ -0,0 +1,19 @@
1
+ /** @readonly Consolidated repo snapshot exports contract. */
2
+
3
+ export {
4
+ CONSOLIDATED_EXPORT_DIR,
5
+ CONSOLIDATED_FILENAMES,
6
+ writeConsolidatedExport
7
+ } from "../utils/consolidatedExport.js";
8
+
9
+ export const CONSOLIDATED_EXPORTS_VERSION = "v001";
10
+
11
+ /** API / model-condenser mirror path. */
12
+ export const CONSOLIDATED_MODELS_MIRROR_DIR = "models";
13
+
14
+ export const CONSOLIDATED_NPM_SCRIPTS = {
15
+ models: "condense-models",
16
+ prompts: "condense-prompts",
17
+ fileStructure: "condense-file-structure",
18
+ all: "condense:all"
19
+ };
@@ -0,0 +1,28 @@
1
+ /** @readonly Pre-push dev log contract (human MD + agent JSON). */
2
+
3
+ export const PRE_PUSH_DEV_LOG_VERSION = "v001";
4
+ export const DEV_LOG_AGENT_SCHEMA_VERSION = "1.0.0";
5
+
6
+ export const DEV_LOG_HUMAN_DIR = "work-log/dev-logs/human";
7
+ export const DEV_LOG_AGENT_DIR = "work-log/dev-logs/agent";
8
+ export const DEV_LOG_AGENT_SCHEMA = "work-log/dev-logs/schemas/dev-log-agent.v1.schema.json";
9
+ export const DEV_LOG_HUMAN_FORMAT = "scripts/lib/dev-log-human-format.mjs";
10
+
11
+ export const DEV_LOG_GENERATOR_SCRIPT = "scripts/write-pre-push-dev-log.mjs";
12
+ export const DEV_LOG_VERIFY_SCRIPT = "scripts/verify-dev-log.mjs";
13
+ export const DEV_LOG_API_INVENTORY_SCRIPT = "scripts/lib/api-inventory.mjs";
14
+ export const DEV_LOG_REPO_TREE_SCRIPT = "scripts/lib/repo-tree.mjs";
15
+
16
+ /** Same as `tree -I "node_modules|.git|dist|build"`. */
17
+ export const DEV_LOG_TREE_IGNORE_DIRS = ["node_modules", ".git", "dist", "build", ".DS_Store"];
18
+
19
+ /** Filename patterns (paired by `{NNN}_{date}_{time}` prefix). */
20
+ export const DEV_LOG_HUMAN_FILENAME_PATTERN =
21
+ "{NNN}_{YYYY-MM-DD}_{HH-MM}_dev-log_{slug}.md";
22
+ export const DEV_LOG_AGENT_FILENAME_PATTERN =
23
+ "{NNN}_{YYYY-MM-DD}_{HH-MM}_dev-log-agent_{slug}.json";
24
+
25
+ export const DEV_LOG_NPM_SCRIPTS = {
26
+ prePush: "dev-log:pre-push",
27
+ verify: "dev-log:verify"
28
+ };
@@ -0,0 +1,117 @@
1
+ /** @typedef {"unreviewed" | "partially_reviewed" | "reviewed" | "rejected"} ReviewStatus */
2
+
3
+ /** @typedef {"ai_extracted_unreviewed" | "source_supported_auto_saved" | "conditional" | "needs_ocr_review" | "corrected_later" | "superseded" | "human_verified"} WorkflowStatus */
4
+
5
+ /**
6
+ * @typedef {Object} CaseModel
7
+ * @property {string} caseId
8
+ * @property {string | null} county
9
+ * @property {string | null} court
10
+ * @property {string | null} indexNumber
11
+ * @property {string | null} caseName
12
+ * @property {string | null} caseType
13
+ * @property {string | null} judgeName
14
+ * @property {string | null} partName
15
+ * @property {string | null} currentPhase
16
+ * @property {string | null} currentMiniPhase
17
+ * @property {"high" | "medium" | "low"} confidence
18
+ */
19
+
20
+ /**
21
+ * @typedef {Object} DocumentModel
22
+ * @property {string} documentId
23
+ * @property {string} caseId
24
+ * @property {number | null} nyscefDocNo
25
+ * @property {string | null} title
26
+ * @property {string | null} documentType
27
+ * @property {string | null} filedDateTime
28
+ * @property {string | null} filedBy
29
+ * @property {string} sourceFileName
30
+ * @property {number | null} pageCount
31
+ * @property {string} extractionStatus
32
+ * @property {ReviewStatus} textReviewStatus
33
+ */
34
+
35
+ /**
36
+ * @typedef {Object} DocumentTextVersionModel
37
+ * @property {string} id
38
+ * @property {string} caseId
39
+ * @property {string} documentId
40
+ * @property {"embedded_text" | "ocr_text" | "ai_parsed_text" | "human_reviewed_text"} versionType
41
+ * @property {string} [textContent]
42
+ * @property {unknown} [structuredJson]
43
+ * @property {"pdf_text" | "ocr" | "llm" | "human_review"} extractionMethod
44
+ * @property {ReviewStatus} reviewStatus
45
+ * @property {"system" | "ai" | "human"} createdBy
46
+ * @property {string} createdAt
47
+ */
48
+
49
+ /**
50
+ * @typedef {Object} RuleSourceProvenance
51
+ * @property {string} [sourceAuthority] cplr | uniform | county | judge | part | case_order | later_case_order
52
+ * @property {string} [sourceName]
53
+ * @property {number | null} [sourceDocNo]
54
+ * @property {string} [ruleSourceApplied]
55
+ * @property {number} [authorityRank]
56
+ * @property {unknown} [supersedes]
57
+ * @property {string} [sourceText]
58
+ * @property {number} [sourcePage]
59
+ */
60
+
61
+ /**
62
+ * @typedef {Object} TaskModel
63
+ * @property {string} taskId
64
+ * @property {string} caseId
65
+ * @property {string} [documentId]
66
+ * @property {string} taskDescription
67
+ * @property {string} taskType
68
+ * @property {string | null} responsibleParty
69
+ * @property {string | null} dueDate
70
+ * @property {"fixed" | "calculated" | "no_fixed_due_date" | "needs_review"} dueDateStatus
71
+ * @property {WorkflowStatus} status
72
+ * @property {number} [sourcePage]
73
+ * @property {"high" | "medium" | "low"} confidence
74
+ * @property {string} [docketingNote]
75
+ * @property {string} [sourceAuthority]
76
+ * @property {string} [sourceName]
77
+ * @property {number | null} [sourceDocNo]
78
+ * @property {string} [ruleSourceApplied]
79
+ * @property {number} [authorityRank]
80
+ * @property {unknown} [supersedes]
81
+ * @property {string} [sourceText]
82
+ */
83
+
84
+ /**
85
+ * @typedef {Object} HumanReviewItemModel
86
+ * @property {string} itemId
87
+ * @property {string} caseId
88
+ * @property {string} documentId
89
+ * @property {number} pageNumber
90
+ * @property {string} location
91
+ * @property {string} issue
92
+ * @property {string} reason
93
+ * @property {string} suggestedAction
94
+ * @property {string} [cropFilePath]
95
+ * @property {boolean} blocking
96
+ * @property {"pending" | "reviewed" | "resolved"} status
97
+ */
98
+
99
+ /**
100
+ * @typedef {Object} CaseStateSnapshotModel
101
+ * @property {string} snapshotId
102
+ * @property {string} caseId
103
+ * @property {number | null} afterDocNo
104
+ * @property {string | null} currentPhase
105
+ * @property {string | null} currentMiniPhase
106
+ * @property {unknown[]} confirmedFacts
107
+ * @property {unknown[]} carriedForwardContext
108
+ * @property {TaskModel[]} openTasks
109
+ * @property {TaskModel[]} completedTasks
110
+ * @property {TaskModel[]} conditionalTasks
111
+ * @property {HumanReviewItemModel[]} unresolvedHumanReviewItems
112
+ * @property {unknown[]} conflicts
113
+ * @property {string[]} auditNotes
114
+ * @property {string} createdAt
115
+ */
116
+
117
+ export {};
@@ -1,3 +1,11 @@
1
+ export class AppError extends Error {
2
+ constructor(message, status = 500) {
3
+ super(message);
4
+ this.name = "AppError";
5
+ this.status = status;
6
+ }
7
+ }
8
+
1
9
  export function errorHandler(error, _req, res, _next) {
2
10
  const status = Number.isInteger(error?.status) ? error.status : 500;
3
11
  const message = error?.message || "Internal Server Error";
@@ -0,0 +1,30 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import { join } from "path";
3
+
4
+ /** Consolidated deliverables live directly under file-exchange/exports/. */
5
+ export const CONSOLIDATED_EXPORT_DIR = "file-exchange/exports";
6
+
7
+ export const CONSOLIDATED_FILENAMES = {
8
+ models: "consolidated-models.json",
9
+ prompts: "consolidated-prompts.json",
10
+ fileStructure: "consolidated-file-structure.json"
11
+ };
12
+
13
+ /**
14
+ * Write a consolidated JSON artifact to file-exchange/exports/.
15
+ * @param {string} repoRoot
16
+ * @param {string} filename
17
+ * @param {string} jsonText
18
+ * @returns {Promise<string>} absolute path written
19
+ */
20
+ export async function writeConsolidatedExport(repoRoot, filename, jsonText) {
21
+ const dest = join(repoRoot, CONSOLIDATED_EXPORT_DIR, filename);
22
+ await mkdir(join(repoRoot, CONSOLIDATED_EXPORT_DIR), { recursive: true });
23
+ await writeFile(dest, jsonText, "utf8");
24
+ return dest;
25
+ }
26
+
27
+ /** @deprecated use writeConsolidatedExport */
28
+ export async function mirrorConsolidatedExport(repoRoot, filename, jsonText) {
29
+ return writeConsolidatedExport(repoRoot, filename, jsonText);
30
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * UTC folder stamp for file-exchange imports/exports.
3
+ * Human-readable and lexicographically sortable.
4
+ * @param {Date} [date]
5
+ * @returns {string} e.g. 2026-05-23_15-59-43Z
6
+ */
7
+ export function formatExchangeTimestamp(date = new Date()) {
8
+ const d = date instanceof Date ? date : new Date(date);
9
+ const iso = d.toISOString();
10
+ const [datePart, rest] = iso.split("T");
11
+ const hh = rest.slice(0, 2);
12
+ const mm = rest.slice(3, 5);
13
+ const ss = rest.slice(6, 8);
14
+ return `${datePart}_${hh}-${mm}-${ss}Z`;
15
+ }
16
+
17
+ /**
18
+ * Convert legacy compact stamps (20260523T154523Z) to human-readable form.
19
+ * @param {string} stamp
20
+ * @returns {string}
21
+ */
22
+ export function normalizeExchangeStamp(stamp) {
23
+ const s = String(stamp || "").trim();
24
+ const legacy = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/;
25
+ const m = s.match(legacy);
26
+ if (m) {
27
+ return `${m[1]}-${m[2]}-${m[3]}_${m[4]}-${m[5]}-${m[6]}Z`;
28
+ }
29
+ return s;
30
+ }
31
+
32
+ /**
33
+ * Human-readable stamp for work-log filenames (date + time).
34
+ * @param {Date} [date]
35
+ * @returns {{ date: string, time: string, folder: string }}
36
+ */
37
+ export function formatWorkLogTimestamp(date = new Date()) {
38
+ const d = date instanceof Date ? date : new Date(date);
39
+ const iso = d.toISOString();
40
+ const [datePart, timePart] = iso.slice(0, 16).split("T");
41
+ const time = timePart.replace(":", "-");
42
+ return {
43
+ date: datePart,
44
+ time,
45
+ folder: formatExchangeTimestamp(d)
46
+ };
47
+ }
@@ -0,0 +1,30 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import {
4
+ formatExchangeTimestamp,
5
+ formatWorkLogTimestamp,
6
+ normalizeExchangeStamp
7
+ } from "./formatExchangeTimestamp.js";
8
+
9
+ test("formatExchangeTimestamp", () => {
10
+ const stamp = formatExchangeTimestamp(new Date("2026-05-23T15:45:23.767Z"));
11
+ assert.equal(stamp, "2026-05-23_15-45-23Z");
12
+ });
13
+
14
+ test("normalizeExchangeStamp converts legacy compact stamps", () => {
15
+ assert.equal(
16
+ normalizeExchangeStamp("20260523T154523Z"),
17
+ "2026-05-23_15-45-23Z"
18
+ );
19
+ assert.equal(
20
+ normalizeExchangeStamp("2026-05-23_15-45-23Z"),
21
+ "2026-05-23_15-45-23Z"
22
+ );
23
+ });
24
+
25
+ test("formatWorkLogTimestamp", () => {
26
+ const t = formatWorkLogTimestamp(new Date("2026-05-23T15:45:23.767Z"));
27
+ assert.equal(t.date, "2026-05-23");
28
+ assert.equal(t.time, "15-45");
29
+ assert.equal(t.folder, "2026-05-23_15-45-23Z");
30
+ });
@@ -0,0 +1,42 @@
1
+ # Backend HTTP API reference
2
+
3
+ Base URL (local dev): `http://localhost:3001`
4
+
5
+ Global health:
6
+
7
+ | Method | Path | Description |
8
+ |--------|------|-------------|
9
+ | GET | `/api/health` | Server up |
10
+
11
+ ---
12
+
13
+ ## Endpoint registry
14
+
15
+ Maintained manually when routes change. Enforced by `npm run lint:api-docs`. See [API documentation contract](./architecture/API_DOCUMENTATION_CONTRACT.md).
16
+
17
+ | Method | Path | Module | Description |
18
+ |--------|------|--------|-------------|
19
+ | GET | `/api/_reference/health` | Reference | Example module health |
20
+ | GET | `/api/model-condenser/health` | Model condenser | Module health |
21
+ | POST | `/api/model-condenser/condense` | Model condenser | Regenerate consolidated-models.json |
22
+ | GET | `/api/model-condenser/consolidated` | Model condenser | Read consolidated schema inventory |
23
+
24
+ _Add rows here when you scaffold new modules with `npm run new:module`._
25
+
26
+ ---
27
+
28
+ ## Module index
29
+
30
+ | Module | Base path | API doc | Status |
31
+ |--------|-----------|---------|--------|
32
+ | Reference | `/api/_reference` | [_reference stub] | Example layout |
33
+ | Model condenser | `/api/model-condenser` | [model-condenser/API.md](./model-condenser/API.md) | Active — schema inventory export |
34
+
35
+ ---
36
+
37
+ ## Conventions
38
+
39
+ - **JSON** unless noted (multipart for file uploads).
40
+ - **Errors**: `{ "error": "message" }` with 4xx/5xx status.
41
+ - Route definitions: `backend/src/modules/{module}/routes/`.
42
+ - **New routes:** update `docs/{module}/API.md` and this registry.
@@ -15,9 +15,21 @@ npm create @pukujan/modular-monolith@2 my-platform
15
15
 
16
16
  On branch **`v2`**:
17
17
 
18
+ **Architecture-only** (no domain modules — recommended for boilerplate updates):
19
+
20
+ ```bash
21
+ npm run export:architecture-starter -- --to packages/create-modular-monolith/template
22
+ ```
23
+
24
+ **Full repo copy** (legacy — includes all modules):
25
+
18
26
  ```bash
19
27
  npm run sync:cli-template
20
- # bump version in packages/create-modular-monolith/package.json if needed
28
+ ```
29
+
30
+ Then bump version and publish:
31
+
32
+ ```bash
21
33
  cd packages/create-modular-monolith
22
34
  npm publish --access public
23
35
  ```
@@ -4,10 +4,14 @@ This folder describes the **modular monolith platform starter** and how **archit
4
4
 
5
5
  | Document | Purpose |
6
6
  | --- | --- |
7
+ | [**HTTP API reference**](./API.md) | All backend module endpoints (master index + endpoint registry) |
8
+ | [API documentation contract](./architecture/API_DOCUMENTATION_CONTRACT.md) | Required when adding routes (`npm run lint:api-docs`) |
7
9
  | [Dev log: v2](./DEVLOG_V2.md) | Changes from `main`, contract rationale, benefits/cons, challenges, growth path |
10
+ | [Work log / dev-logs](../work-log/dev-logs/) | Per-session **shipped work** — `{NNN}_{date}_{time}_dev-log_{slug}.md`; see [work-log/](../work-log/) |
8
11
  | [Starter pack](./STARTER_PACK.md) | What ships in the repo, how to run it, and how to add modules |
9
12
  | [Architecture guardrails](./architecture/ARCHITECTURE_GUARDRAILS.md) | Module contracts, boundaries, naming, and how enforcement works |
10
13
  | [Module internal contract](./architecture/MODULE_INTERNAL_CONTRACT.md) | MVC layers, prompts, evals, tests inside each feature module |
11
14
  | [Publishing the CLI](./PUBLISHING.md) | Release `@pukujan/create-modular-monolith` to npm |
15
+ | [Case Filing AI starter](./case-filing-ai/README.md) | Domain blueprint, module split, pipeline, guardrails, and DB schema |
12
16
 
13
17
  Canonical repository: [https://github.com/Pukujan/litigation-workflow-application](https://github.com/Pukujan/litigation-workflow-application)
@@ -30,6 +30,10 @@ git clone https://github.com/Pukujan/litigation-workflow-application.git
30
30
  | `backend/scripts/check-module-layers.mjs` | Intra-module layer import rules (backend) |
31
31
  | `docs/architecture/ARCHITECTURE_GUARDRAILS.md` | Inter-module contract |
32
32
  | `docs/architecture/MODULE_INTERNAL_CONTRACT.md` | Intra-module MVC, prompts, evals, tests |
33
+ | `docs/architecture/REPO_ARTIFACT_LAYOUT.md` | Data roots, file-exchange, golden paths |
34
+ | `file-exchange/` | Dated imports/exports for human↔agent handoff |
35
+ | `AGENTS.md` | **Mandatory** agent workflow (import stamp before `process-batch`) |
36
+ | `work-log/` | Handoffs, study-docs, dev-logs |
33
37
  | `backend/src/modules/_reference/` | Example layout (skipped by loaders) |
34
38
 
35
39
  Guardrails are **documented** and **automated** where practical. See [Architecture guardrails](./architecture/ARCHITECTURE_GUARDRAILS.md) and [Module internal contract](./architecture/MODULE_INTERNAL_CONTRACT.md).
@@ -0,0 +1,112 @@
1
+ # API documentation contract
2
+
3
+ Every **new or changed** HTTP route in `backend/src/modules/*/routes/` must be reflected in markdown **before** the work is considered done (same PR / same change set).
4
+
5
+ This is enforced by `npm run lint:api-docs` (also part of `npm run lint:architecture`).
6
+
7
+ ---
8
+
9
+ ## Two places to update
10
+
11
+ | # | File | What to add |
12
+ |---|------|-------------|
13
+ | 1 | `docs/<module-name>/API.md` | Per-module reference: method, path, description, request/response notes |
14
+ | 2 | `docs/API.md` → **Endpoint registry** | One row per route: full path + short description |
15
+
16
+ Module folder name = docs folder name (e.g. `case-filing-ai` → `docs/case-filing-ai/API.md`).
17
+
18
+ Base path comes from `app.use("/api/...", router)` in the module’s `index.js`.
19
+
20
+ ---
21
+
22
+ ## 1. Module API (`docs/<module>/API.md`)
23
+
24
+ ### Required for every route
25
+
26
+ 1. **Endpoint quick reference** table (top of file, after the header block):
27
+
28
+ ```markdown
29
+ ## Endpoint quick reference
30
+
31
+ | Method | Path | Description |
32
+ |--------|------|-------------|
33
+ | GET | `/health` | Module health and config summary |
34
+ | POST | `/process-batch` | Upload filings and run the master prompt pipeline |
35
+ ```
36
+
37
+ 2. **Detailed section** (recommended): `### \`METHOD /path\`` with body fields, response shape, examples.
38
+
39
+ ### Rules
40
+
41
+ - **Path** column uses the route path **relative to the module base** (starts with `/`), matching Express exactly (including `:param` segments).
42
+ - **Description** is one short sentence: what it does, not how it is implemented.
43
+ - **Method** is uppercase (`GET`, `POST`, …).
44
+ - Do **not** remove old rows when deprecating — mark deprecated routes in the description until removed from code.
45
+
46
+ ### New module
47
+
48
+ `npm run new:module <name>` scaffolds `docs/<name>/API.md` with a health row. Append rows when you add routes.
49
+
50
+ ---
51
+
52
+ ## 2. Consolidated registry (`docs/API.md`)
53
+
54
+ Under `## Endpoint registry`, append one row per route:
55
+
56
+ ```markdown
57
+ | POST | `/api/case-filing-ai/process-batch` | Case Filing AI | Upload filings and run master prompt |
58
+ ```
59
+
60
+ | Column | Content |
61
+ |--------|---------|
62
+ | Method | HTTP verb |
63
+ | Path | Full path including `/api/<module-id>` |
64
+ | Module | Human label (match module index table) |
65
+ | Description | Same intent as module doc (can be slightly shorter) |
66
+
67
+ Keep rows **sorted by module**, then method, then path.
68
+
69
+ The **Module index** table (above the registry) must list every loaded module; stub modules stay “Health only” until domain routes ship.
70
+
71
+ ---
72
+
73
+ ## 3. Optional but encouraged
74
+
75
+ | Artifact | When |
76
+ |----------|------|
77
+ | `frontend/src/modules/<module>/api/*.js` | Wrapper for UI callers |
78
+ | Integration test under `tests/integration/` | Exercises the route |
79
+ | `backend/.env.example` | New env vars |
80
+
81
+ ---
82
+
83
+ ## 4. Checklist (copy when adding a route)
84
+
85
+ ```text
86
+ [ ] Route in backend/src/modules/<module>/routes/
87
+ [ ] Row in docs/<module>/API.md (quick reference + detail section)
88
+ [ ] Row in docs/API.md → Endpoint registry
89
+ [ ] npm run lint:api-docs passes
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 5. Enforcement
95
+
96
+ ```bash
97
+ npm run lint:api-docs # repo root or backend/
98
+ npm run lint:architecture # includes api-docs
99
+ ```
100
+
101
+ The linter compares Express `router.get/post/...` registrations to:
102
+
103
+ - Path (+ method) in `docs/<module>/API.md`
104
+ - Full path (+ method) in `docs/API.md` endpoint registry
105
+
106
+ ---
107
+
108
+ ## Related
109
+
110
+ - [Master API index](../API.md)
111
+ - [Module internal contract](./MODULE_INTERNAL_CONTRACT.md)
112
+ - [Architecture guardrails](./ARCHITECTURE_GUARDRAILS.md)
@@ -0,0 +1,168 @@
1
+ # Architecture contracts — how it works
2
+
3
+ **One-page map** of repo contracts: what they are, how they connect, and how they are enforced.
4
+
5
+ | Quick links | |
6
+ |-------------|---|
7
+ | **Index (machine)** | [contracts/manifest.json](./contracts/manifest.json) |
8
+ | **History** | [contracts/changelog.jsonl](./contracts/changelog.jsonl) |
9
+ | **Paths on disk** | [REPO_ARTIFACT_LAYOUT.md](./REPO_ARTIFACT_LAYOUT.md) |
10
+ | **Lint** | `npm run lint:contracts` · `npm run lint:repo-artifacts` |
11
+
12
+ ---
13
+
14
+ ## What “contract” means here
15
+
16
+ A **contract** is a versioned agreement about paths, filenames, API shapes, or pipeline metadata. It can be:
17
+
18
+ | Form | Example |
19
+ |------|---------|
20
+ | **Markdown spec** | `docs/architecture/contracts/prePushDevLog.contract.md` |
21
+ | **JS constants** | `backend/src/modules/case-filing-ai/contracts/pipelineVersions.js` |
22
+ | **Registry doc** | `docs/API.md` endpoint table |
23
+
24
+ Contracts are **not** runtime filing data. They tell humans and agents where artifacts live and which versions are current.
25
+
26
+ ---
27
+
28
+ ## The contract pipeline (repo level)
29
+
30
+ ```mermaid
31
+ flowchart TB
32
+ subgraph define [Define]
33
+ manifest[manifest.json]
34
+ md[contracts/*.contract.md]
35
+ js[*.contract.js in backend]
36
+ end
37
+
38
+ subgraph use [Use at runtime / workflow]
39
+ batch[Batch pipeline writes pipelineVersions]
40
+ exchange[file-exchange imports/exports]
41
+ devlog[pre-push dev logs]
42
+ condense[condense:all snapshots]
43
+ end
44
+
45
+ subgraph enforce [Enforce]
46
+ lintC[lint:contracts]
47
+ lintR[lint:repo-artifacts]
48
+ lintApi[lint:api-docs]
49
+ end
50
+
51
+ manifest --> md
52
+ manifest --> js
53
+ md --> exchange
54
+ md --> devlog
55
+ md --> condense
56
+ js --> batch
57
+ manifest --> lintC
58
+ manifest --> lintR
59
+ md --> lintApi
60
+ ```
61
+
62
+ ### 1. Register — `manifest.json`
63
+
64
+ Every contract has an entry with:
65
+
66
+ - `version` (e.g. `v001`)
67
+ - `doc` — human-readable spec (required for new contracts)
68
+ - `file` / `utility` / `schema` / scripts — paths lint must verify exist
69
+
70
+ **Source of truth for “what contracts exist”:** [contracts/manifest.json](./contracts/manifest.json)
71
+
72
+ ### 2. Document — `contracts/*.contract.md`
73
+
74
+ Each entry’s `doc` explains purpose, paths, commands, and related contracts.
75
+
76
+ ### 3. Implement — `*.contract.js` (where needed)
77
+
78
+ Code exports version strings and path constants so services and scripts share one definition:
79
+
80
+ | File | Exports |
81
+ |------|---------|
82
+ | `pipelineVersions.js` | `buildPipelineVersions()` on batch outputs |
83
+ | `storageLayout.contract.js` | `BATCH_LAYOUT_VERSION`, folder names |
84
+ | `parsedDocumentArtifacts.contract.js` | Parsed cache filenames |
85
+ | `prePushDevLog.contract.js` | Dev-log paths, tree ignores, npm scripts |
86
+ | `consolidatedExports.contract.js` | `file-exchange/exports/consolidated-*.json` |
87
+
88
+ ### 4. Record changes — `changelog.jsonl`
89
+
90
+ One JSON line per bump: `contract`, `from`, `to`, `reason`, `time`.
91
+
92
+ ### 5. Enforce — npm lint scripts
93
+
94
+ | Command | Checks |
95
+ |---------|--------|
96
+ | `npm run lint:contracts` | Every path listed in `manifest.json` exists |
97
+ | `npm run lint:repo-artifacts` | Key folders + contract docs + golden stub paths |
98
+ | `npm run lint:api-docs` | Routes in code ⊆ `docs/API.md` registry |
99
+
100
+ ---
101
+
102
+ ## Contract catalog (current)
103
+
104
+ | ID | Version | What it governs |
105
+ |----|---------|-----------------|
106
+ | **repoArtifactLayout** | v001 | All canonical roots (`data/`, `evals/`, `file-exchange/`, `work-log/`) |
107
+ | **fileExchange** | v001 | `imports/{stamp}/`, `exports/{stamp}/`, human-readable UTC stamps |
108
+ | **consolidatedExports** | v001 | `exports/consolidated-*.json` + `models/` mirror, `condense:all` |
109
+ | **prePushDevLog** | v001 | Paired `human/*.md` + `agent/*.json`, tree/API/test audits |
110
+ | **apiDocumentationRegistry** | v001 | `docs/API.md`, active/stub/deprecated routes |
111
+ | **caseFilingStorageLayout** | v001 | `batches/batch-NNN/` folder layout |
112
+ | **parsedDocumentArtifacts** | v001 | `parsed-documents/doc-NNN/` file names |
113
+ | **pipelineVersions** | v001 | Version blob on batch outputs (prompt, parser, golden, …) |
114
+ | **ruleAuthority** | v001 | Court rule authority ranks |
115
+
116
+ Per-contract detail: follow the `doc` link in [manifest.json](./contracts/manifest.json).
117
+
118
+ ---
119
+
120
+ ## Case-filing **processing** pipeline (runtime)
121
+
122
+ This is separate from the **contract** pipeline above but uses contract versions:
123
+
124
+ ```mermaid
125
+ flowchart LR
126
+ import[file-exchange import] --> upload[POST process-batch]
127
+ upload --> parse[Parsed doc cache v001]
128
+ parse --> llm[Master prompt v1 / v001]
129
+ llm --> out[outputs + case-snapshot]
130
+ out --> eval[Golden evals]
131
+ eval --> export[exports/ or eval-bundles]
132
+ ```
133
+
134
+ Version defaults come from `pipelineVersions.js` + env `MASTER_PROMPT_VERSION`.
135
+ Batch folders follow `storageLayout.contract.js`.
136
+ HTTP entrypoint: `POST /api/case-filing-ai/process-batch` ([API.md](../API.md)).
137
+
138
+ ---
139
+
140
+ ## Human ↔ agent workflows (contract-driven)
141
+
142
+ | When | Command | Contract |
143
+ |------|---------|----------|
144
+ | Inbound files | `npm run import:file-exchange` | fileExchange |
145
+ | Before push | `npm run dev-log:pre-push` | prePushDevLog |
146
+ | Snapshot handoff | `npm run condense:all` | consolidatedExports |
147
+ | Golden refresh | `npm run ingest:golden-*` | fileExchange + pipelineVersions |
148
+
149
+ ---
150
+
151
+ ## Related architecture docs (not in manifest)
152
+
153
+ | Doc | Scope |
154
+ |-----|--------|
155
+ | [ARCHITECTURE_GUARDRAILS.md](./ARCHITECTURE_GUARDRAILS.md) | Module boundaries, loader, lint:boundaries |
156
+ | [MODULE_INTERNAL_CONTRACT.md](./MODULE_INTERNAL_CONTRACT.md) | Inside one module (routes, services, prompts) |
157
+ | [API_DOCUMENTATION_CONTRACT.md](./API_DOCUMENTATION_CONTRACT.md) | How to maintain `docs/API.md` |
158
+
159
+ ---
160
+
161
+ ## Adding a new contract
162
+
163
+ 1. Add `docs/architecture/contracts/<name>.contract.md`
164
+ 2. Add JS constants under `backend/.../contracts/` if code needs them
165
+ 3. Add entry to [manifest.json](./contracts/manifest.json) with all paths
166
+ 4. Append line to [changelog.jsonl](./contracts/changelog.jsonl)
167
+ 5. Update [REPO_ARTIFACT_LAYOUT.md](./REPO_ARTIFACT_LAYOUT.md) if new roots
168
+ 6. Run `npm run lint:contracts` and `npm run lint:repo-artifacts`
@@ -44,6 +44,8 @@ Every feature module lives at `backend/src/modules/<module-name>/` and **must**
44
44
  | --- | --- | --- |
45
45
  | **index** | `register(app, context)` — mount routes, register listeners | Any layer in **this** module, `src/shared/*`, npm |
46
46
  | **routes** | HTTP mapping, status codes, call services | `services`, `schemas`, `shared`, npm |
47
+
48
+ **HTTP API docs:** Every route must be listed in `docs/<module-name>/API.md` and `docs/API.md` (endpoint registry). See [API documentation contract](./API_DOCUMENTATION_CONTRACT.md). Enforced via `npm run lint:api-docs`.
47
49
  | **services** | Business logic, transactions, AI orchestration | `domain`, `repositories`, `adapters`, `prompts`, `schemas`, `events`, `utils`, `config`, `shared`, npm |
48
50
  | **repositories** | DB/files/API persistence | `domain`, `adapters`, `schemas`, `utils`, `shared`, npm |
49
51
  | **adapters** | Third-party APIs, SDK wrappers | `domain`, `schemas`, `utils`, `shared`, npm |