@pukujan/create-modular-monolith 2.0.0 → 2.2.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.
- package/README.md +94 -23
- package/index.js +47 -0
- package/package.json +16 -19
- package/template/.cursor/commands/planning-study-log.md +25 -0
- package/template/.cursor/commands/pre-push-dev-log.md +52 -0
- package/template/.cursor/rules/api-documentation.mdc +21 -0
- package/template/.cursor/rules/file-exchange-inbox.mdc +29 -0
- package/template/.github/workflows/ci.yml +44 -0
- package/template/AGENTS.md +41 -0
- package/template/README.md +25 -55
- package/template/backend/.env.example +38 -0
- package/template/backend/package-lock.json +1118 -24
- package/template/backend/package.json +14 -4
- package/template/backend/scripts/check-module-boundaries.mjs +3 -0
- package/template/backend/src/modules/model-condenser/README.md +7 -0
- package/template/backend/src/modules/model-condenser/config/index.js +20 -0
- package/template/backend/src/modules/model-condenser/events/index.js +1 -0
- package/template/backend/src/modules/model-condenser/index.js +12 -0
- package/template/backend/src/modules/model-condenser/routes/health.routes.js +10 -0
- package/template/backend/src/modules/model-condenser/routes/index.js +10 -0
- package/template/backend/src/modules/model-condenser/routes/modelCondenser.routes.js +44 -0
- package/template/backend/src/modules/model-condenser/services/health.service.js +8 -0
- package/template/backend/src/modules/model-condenser/services/modelCondenser.facade.js +58 -0
- package/template/backend/src/modules/model-condenser/services/modelCondenser.service.js +513 -0
- package/template/backend/src/modules/model-condenser/tests/integration/modelCondenser.routes.test.js +40 -0
- package/template/backend/src/modules/model-condenser/tests/unit/modelCondenser.service.test.js +31 -0
- package/template/backend/src/modules/model-condenser/utils/index.js +1 -0
- package/template/backend/src/shared/contracts/consolidatedExports.contract.js +19 -0
- package/template/backend/src/shared/contracts/prePushDevLog.contract.js +28 -0
- package/template/backend/src/shared/domain/case-filing/core-models.js +117 -0
- package/template/backend/src/shared/http/errors.js +8 -0
- package/template/backend/src/shared/utils/consolidatedExport.js +30 -0
- package/template/backend/src/shared/utils/formatExchangeTimestamp.js +47 -0
- package/template/backend/src/shared/utils/formatExchangeTimestamp.test.js +30 -0
- package/template/backend/src/shared/utils/traceId.js +19 -0
- package/template/docs/API.md +42 -0
- package/template/docs/PUBLISHING.md +13 -1
- package/template/docs/README.md +7 -1
- package/template/docs/STARTER_PACK.md +4 -0
- package/template/docs/architecture/API_DOCUMENTATION_CONTRACT.md +112 -0
- package/template/docs/architecture/CONTRACTS_OVERVIEW.md +180 -0
- package/template/docs/architecture/EVAL_AND_CI.md +79 -0
- package/template/docs/architecture/MODULE_INTERNAL_CONTRACT.md +2 -0
- package/template/docs/architecture/PLATFORM_ARCHITECTURE.md +221 -0
- package/template/docs/architecture/REPO_ARTIFACT_LAYOUT.md +33 -0
- package/template/docs/architecture/contracts/apiDocumentationRegistry.contract.md +40 -0
- package/template/docs/architecture/contracts/changelog.jsonl +12 -0
- package/template/docs/architecture/contracts/consolidatedExports.contract.md +58 -0
- package/template/docs/architecture/contracts/fileExchange.contract.md +47 -0
- package/template/docs/architecture/contracts/manifest.json +39 -0
- package/template/docs/architecture/contracts/prePushDevLog.contract.md +69 -0
- package/template/docs/model-condenser/API.md +102 -0
- package/template/file-exchange/README.md +41 -0
- package/template/file-exchange/exports/.gitkeep +0 -0
- package/template/file-exchange/exports/consolidated-models.json +625 -0
- package/template/file-exchange/imports/.gitkeep +0 -0
- package/template/frontend/.env.example +2 -0
- package/template/frontend/package-lock.json +125 -122
- package/template/frontend/package.json +1 -1
- package/template/frontend/src/index.css +311 -0
- package/template/frontend/src/modules/_reference/services/health-api.js +1 -1
- package/template/frontend/src/shared/api/client.js +67 -5
- package/template/models/.gitkeep +0 -0
- package/template/package.json +13 -4
- package/template/scripts/check-api-docs.mjs +183 -0
- package/template/scripts/condense-file-structure.mjs +44 -0
- package/template/scripts/condense-models.mjs +70 -0
- package/template/scripts/condense-prompts.mjs +161 -0
- package/template/scripts/consolidated-output.mjs +49 -0
- package/template/scripts/export-consolidated-models.mjs +11 -0
- package/template/scripts/git-hooks/pre-push.sample +15 -0
- package/template/scripts/import-to-file-exchange.mjs +43 -0
- package/template/scripts/lib/api-inventory.mjs +182 -0
- package/template/scripts/lib/dev-log-human-format.mjs +360 -0
- package/template/scripts/lib/git-snapshot.mjs +46 -0
- package/template/scripts/lib/module-scaffold.mjs +37 -1
- package/template/scripts/lib/repo-tree.mjs +127 -0
- package/template/scripts/lib/run-tests.mjs +60 -0
- package/template/scripts/lint-contracts.mjs +57 -0
- package/template/scripts/lint-repo-artifacts.mjs +37 -0
- package/template/scripts/new-module.mjs +7 -0
- package/template/scripts/resolve-import-stamp.mjs +50 -0
- package/template/scripts/verify-dev-log.mjs +50 -0
- package/template/scripts/write-pre-push-dev-log.mjs +220 -0
- package/template/work-log/INDEX.md +3 -0
- package/template/work-log/README.md +40 -0
- package/template/work-log/dev-logs/README.md +97 -0
- package/template/work-log/dev-logs/schemas/dev-log-agent.v1.schema.json +119 -0
- package/template/work-log/dev-logs/templates/dev-log-human.template.md +10 -0
- package/template/work-log/handoffs/README.md +36 -0
- package/template/work-log/study-docs/README.md +13 -0
- package/bin/create-modular-monolith.js +0 -132
- package/template/backend/src/modules/_reference/evals/README.md +0 -6
- package/template/backend/src/modules/_reference/evals/datasets/example.cases.json +0 -12
- package/template/backend/src/modules/_reference/evals/runners/example.eval.mjs +0 -25
- package/template/scripts/sync-cli-template.mjs +0 -44
- /package/template/{frontend/src/modules → backend/db/migrations}/.gitkeep +0 -0
|
@@ -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,19 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} [prefix]
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
export function createTraceId(prefix = "trace") {
|
|
8
|
+
const short = randomUUID().replace(/-/g, "").slice(0, 12);
|
|
9
|
+
return `${prefix}_${short}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} batchTraceId
|
|
14
|
+
* @param {number} docIndex
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
export function docTraceId(batchTraceId, docIndex) {
|
|
18
|
+
return `${batchTraceId}_doc${String(docIndex).padStart(3, "0")}`;
|
|
19
|
+
}
|
|
@@ -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
|
-
|
|
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
|
```
|
package/template/docs/README.md
CHANGED
|
@@ -4,10 +4,16 @@ 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 |
|
|
14
|
+
| [Evals, regression, and CI gates](./architecture/EVAL_AND_CI.md) | `test:ci`, GitHub Actions, optional per-case golden |
|
|
15
|
+
| [Evals, regression, and CI gates](./architecture/EVAL_AND_CI.md) | Golden evals, `test:evals`, GitHub Actions gates |
|
|
11
16
|
| [Publishing the CLI](./PUBLISHING.md) | Release `@pukujan/create-modular-monolith` to npm |
|
|
17
|
+
| [Case Filing AI starter](./case-filing-ai/README.md) | Domain blueprint, module split, pipeline, guardrails, and DB schema |
|
|
12
18
|
|
|
13
|
-
Canonical repository: [https://github.com/Pukujan/litigation-
|
|
19
|
+
Canonical repository: [https://github.com/Pukujan/litigation-prompt-engineering](https://github.com/Pukujan/litigation-prompt-engineering)
|
|
@@ -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,180 @@
|
|
|
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
|
+
## Exporting architecture to the npm starter
|
|
162
|
+
|
|
163
|
+
To refresh the **boilerplate CLI template** without domain modules:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm run export:architecture-starter -- --to packages/create-modular-monolith/template
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Output defaults to `export/architecture-starter/`. See `EXPORT_MANIFEST.json` and [PUBLISHING.md](../PUBLISHING.md).
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Adding a new contract
|
|
174
|
+
|
|
175
|
+
1. Add `docs/architecture/contracts/<name>.contract.md`
|
|
176
|
+
2. Add JS constants under `backend/.../contracts/` if code needs them
|
|
177
|
+
3. Add entry to [manifest.json](./contracts/manifest.json) with all paths
|
|
178
|
+
4. Append line to [changelog.jsonl](./contracts/changelog.jsonl)
|
|
179
|
+
5. Update [REPO_ARTIFACT_LAYOUT.md](./REPO_ARTIFACT_LAYOUT.md) if new roots
|
|
180
|
+
6. Run `npm run lint:contracts` and `npm run lint:repo-artifacts`
|