guardian-framework 0.1.25 → 0.1.27
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/dist/cli.js +333 -29
- package/dist/exports.js +333 -29
- package/package.json +1 -1
- package/templates/pi/architecture/modules/module-template.md +90 -57
- package/templates/pi/extensions/domain-explorer.ts +402 -108
- package/templates/pi/preflight_report.json +1 -1
- package/templates/pi/skills/nextjs-enterprise-codegen.md +303 -293
package/dist/exports.js
CHANGED
|
@@ -995,7 +995,7 @@ __export(exports_package, {
|
|
|
995
995
|
bin: () => bin,
|
|
996
996
|
author: () => author
|
|
997
997
|
});
|
|
998
|
-
var name = "guardian-framework", version = "0.1.
|
|
998
|
+
var name = "guardian-framework", version = "0.1.27", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
|
|
999
999
|
var init_package = __esm(() => {
|
|
1000
1000
|
exports = {
|
|
1001
1001
|
".": {
|
|
@@ -11022,6 +11022,115 @@ Respond with ONLY valid JSON matching this exact structure. Do not include markd
|
|
|
11022
11022
|
"aggregateRoots": "Which entities are aggregate roots and why"
|
|
11023
11023
|
}`;
|
|
11024
11024
|
}
|
|
11025
|
+
function buildFrontendExplorationPrompt(context) {
|
|
11026
|
+
const sanitized = sanitizeBusinessContext(context);
|
|
11027
|
+
return `You are a frontend architecture expert. Analyze the following web application description and extract a structured model focused on user experience, UI concepts, and design principles.
|
|
11028
|
+
|
|
11029
|
+
Business Context:
|
|
11030
|
+
${sanitized}
|
|
11031
|
+
|
|
11032
|
+
Respond with ONLY valid JSON matching this exact structure. Do not include markdown formatting, code fences, or explanatory text:
|
|
11033
|
+
|
|
11034
|
+
{
|
|
11035
|
+
"sessionId": "auto-generated-uuid",
|
|
11036
|
+
"businessContext": "original description",
|
|
11037
|
+
"status": "draft",
|
|
11038
|
+
"actors": [
|
|
11039
|
+
{
|
|
11040
|
+
"name": "UserRole",
|
|
11041
|
+
"description": "Who this user is",
|
|
11042
|
+
"interactions": "What they do in the application"
|
|
11043
|
+
}
|
|
11044
|
+
],
|
|
11045
|
+
"functionalRequirements": [
|
|
11046
|
+
{
|
|
11047
|
+
"id": "FR-001",
|
|
11048
|
+
"requirement": "The user shall be able to...",
|
|
11049
|
+
"priority": "critical|high|medium|low",
|
|
11050
|
+
"boundedContext": "FeatureName"
|
|
11051
|
+
}
|
|
11052
|
+
],
|
|
11053
|
+
"nonFunctionalRequirements": [
|
|
11054
|
+
{
|
|
11055
|
+
"id": "NFR-001",
|
|
11056
|
+
"requirement": "The application shall...",
|
|
11057
|
+
"category": "performance|accessibility|usability|security|maintainability",
|
|
11058
|
+
"target": "Specific measurable target"
|
|
11059
|
+
}
|
|
11060
|
+
],
|
|
11061
|
+
"assumptions": [
|
|
11062
|
+
{
|
|
11063
|
+
"assumption": "We assume that...",
|
|
11064
|
+
"impactIfWrong": "What breaks if this is false",
|
|
11065
|
+
"mitigation": "How we handle it being wrong"
|
|
11066
|
+
}
|
|
11067
|
+
],
|
|
11068
|
+
"boundedContexts": [
|
|
11069
|
+
{
|
|
11070
|
+
"name": "FeatureName",
|
|
11071
|
+
"description": "Brief description of this app feature/section",
|
|
11072
|
+
"entities": ["UIConcept1", "UIConcept2"]
|
|
11073
|
+
}
|
|
11074
|
+
],
|
|
11075
|
+
"entities": [
|
|
11076
|
+
{
|
|
11077
|
+
"name": "UIConceptName",
|
|
11078
|
+
"context": "FeatureName",
|
|
11079
|
+
"type": "ui-concept | user-intent | design-token | app-shell | value-object",
|
|
11080
|
+
"description": "What this UI concept represents"
|
|
11081
|
+
}
|
|
11082
|
+
],
|
|
11083
|
+
"userIntents": [
|
|
11084
|
+
{
|
|
11085
|
+
"name": "UserIntentName",
|
|
11086
|
+
"context": "FeatureName",
|
|
11087
|
+
"description": "What the user is trying to do",
|
|
11088
|
+
"triggeredBy": "What UI action triggers this intent"
|
|
11089
|
+
}
|
|
11090
|
+
],
|
|
11091
|
+
"designPrinciples": [
|
|
11092
|
+
{
|
|
11093
|
+
"principle": "The application is...",
|
|
11094
|
+
"description": "What this principle means in practice",
|
|
11095
|
+
"rationale": "Why this principle exists"
|
|
11096
|
+
}
|
|
11097
|
+
],
|
|
11098
|
+
"navigationPhilosophy": {
|
|
11099
|
+
"contextPreservation": "How the user never loses context",
|
|
11100
|
+
"deepLinking": "How every page is deep-linkable",
|
|
11101
|
+
"multiTab": "How multiple tabs are supported"
|
|
11102
|
+
},
|
|
11103
|
+
"appShell": {
|
|
11104
|
+
"navigation": "Navigation structure",
|
|
11105
|
+
"header": "Header content",
|
|
11106
|
+
"sidebar": "Sidebar content",
|
|
11107
|
+
"commandPalette": "Command palette actions",
|
|
11108
|
+
"globalSearch": "Global search behavior"
|
|
11109
|
+
},
|
|
11110
|
+
"degradationStrategy": [
|
|
11111
|
+
{
|
|
11112
|
+
"feature": "FeatureName",
|
|
11113
|
+
"whenUnavailable": "What happens when this feature's API is down",
|
|
11114
|
+
"degradesTo": "What still works"
|
|
11115
|
+
}
|
|
11116
|
+
],
|
|
11117
|
+
"ubiquitousLanguage": [
|
|
11118
|
+
{
|
|
11119
|
+
"term": "CanonicalTerm",
|
|
11120
|
+
"definition": "Clear definition",
|
|
11121
|
+
"boundedContext": "FeatureName",
|
|
11122
|
+
"aliases": ["AlternativeName1"],
|
|
11123
|
+
"examples": "Usage example"
|
|
11124
|
+
}
|
|
11125
|
+
],
|
|
11126
|
+
"openQuestions": "Any open questions about the application",
|
|
11127
|
+
"designSystem": {
|
|
11128
|
+
"componentLibrary": "Which component library or approach (Tailwind, MUI, custom)",
|
|
11129
|
+
"theming": "How theming works (dark mode, branding)",
|
|
11130
|
+
"accessibility": "Accessibility requirements"
|
|
11131
|
+
}
|
|
11132
|
+
}`;
|
|
11133
|
+
}
|
|
11025
11134
|
function parseExplorationResponse(rawResponse, sessionId) {
|
|
11026
11135
|
try {
|
|
11027
11136
|
let cleaned = rawResponse.trim();
|
|
@@ -11103,6 +11212,14 @@ function coerceEntityType(val) {
|
|
|
11103
11212
|
return "value-object";
|
|
11104
11213
|
if (val === "aggregate-root")
|
|
11105
11214
|
return "aggregate-root";
|
|
11215
|
+
if (val === "ui-concept")
|
|
11216
|
+
return "ui-concept";
|
|
11217
|
+
if (val === "user-intent")
|
|
11218
|
+
return "user-intent";
|
|
11219
|
+
if (val === "design-token")
|
|
11220
|
+
return "design-token";
|
|
11221
|
+
if (val === "app-shell")
|
|
11222
|
+
return "app-shell";
|
|
11106
11223
|
return "entity";
|
|
11107
11224
|
}
|
|
11108
11225
|
function coerceFrPriority(val) {
|
|
@@ -11187,8 +11304,20 @@ async function exploreDomain(context, options) {
|
|
|
11187
11304
|
if (!fs12.existsSync(explorationDir)) {
|
|
11188
11305
|
fs12.mkdirSync(explorationDir, { recursive: true });
|
|
11189
11306
|
}
|
|
11307
|
+
let lang = options?.language;
|
|
11308
|
+
if (!lang) {
|
|
11309
|
+
try {
|
|
11310
|
+
const manifestPath = path11.join(projectDir, "guardian-manifest.json");
|
|
11311
|
+
if (fs12.existsSync(manifestPath)) {
|
|
11312
|
+
const manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf-8"));
|
|
11313
|
+
if (manifest.language)
|
|
11314
|
+
lang = manifest.language;
|
|
11315
|
+
}
|
|
11316
|
+
} catch {}
|
|
11317
|
+
}
|
|
11190
11318
|
const sanitized = sanitizeBusinessContext(context);
|
|
11191
|
-
const
|
|
11319
|
+
const isFrontend = lang === "nextjs" || lang === "angular";
|
|
11320
|
+
const prompt = isFrontend ? buildFrontendExplorationPrompt(sanitized) : buildExplorationPrompt(sanitized);
|
|
11192
11321
|
const promptContent = [
|
|
11193
11322
|
"# Domain Exploration Prompt",
|
|
11194
11323
|
"",
|
|
@@ -11341,6 +11470,18 @@ function extractTable(body, sectionName) {
|
|
|
11341
11470
|
function scaffoldFromExploration(sessionId, options) {
|
|
11342
11471
|
const projectDir = options?.projectDir ?? process.cwd();
|
|
11343
11472
|
const dryRun = options?.dryRun ?? false;
|
|
11473
|
+
let lang = options?.language;
|
|
11474
|
+
if (!lang) {
|
|
11475
|
+
try {
|
|
11476
|
+
const manifestPath = path11.join(projectDir, "guardian-manifest.json");
|
|
11477
|
+
if (fs12.existsSync(manifestPath)) {
|
|
11478
|
+
const manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf-8"));
|
|
11479
|
+
if (manifest.language)
|
|
11480
|
+
lang = manifest.language;
|
|
11481
|
+
}
|
|
11482
|
+
} catch {}
|
|
11483
|
+
}
|
|
11484
|
+
const isFrontend = lang === "nextjs" || lang === "angular";
|
|
11344
11485
|
const sessionResult = readExplorationSession(sessionId, projectDir);
|
|
11345
11486
|
if (!sessionResult) {
|
|
11346
11487
|
throw new Error(`Exploration session not found: ${sessionId}`);
|
|
@@ -11462,76 +11603,239 @@ function scaffoldFromExploration(sessionId, options) {
|
|
|
11462
11603
|
`;
|
|
11463
11604
|
}
|
|
11464
11605
|
}
|
|
11465
|
-
let content =
|
|
11606
|
+
let content = "";
|
|
11607
|
+
if (isFrontend) {
|
|
11608
|
+
const uiConcepts = contextEntities.filter((e2) => e2.type === "ui-concept");
|
|
11609
|
+
const userIntents = contextEntities.filter((e2) => e2.type === "user-intent");
|
|
11610
|
+
const designTokens = contextEntities.filter((e2) => e2.type === "design-token");
|
|
11611
|
+
const appShells = contextEntities.filter((e2) => e2.type === "app-shell");
|
|
11612
|
+
content = `# ${bc.name}
|
|
11466
11613
|
|
|
11467
11614
|
`;
|
|
11468
|
-
|
|
11615
|
+
content += `## Module Status
|
|
11469
11616
|
|
|
11470
11617
|
`;
|
|
11471
|
-
|
|
11618
|
+
content += `**Status:** Planned
|
|
11472
11619
|
`;
|
|
11473
|
-
|
|
11620
|
+
content += `**Last reviewed:** ${timestamp}
|
|
11474
11621
|
`;
|
|
11475
|
-
|
|
11622
|
+
content += `**Source session:** ${sessionId}
|
|
11476
11623
|
|
|
11477
11624
|
`;
|
|
11478
|
-
|
|
11625
|
+
content += `## Description
|
|
11479
11626
|
|
|
11480
11627
|
${bc.description}
|
|
11481
11628
|
|
|
11482
11629
|
`;
|
|
11483
|
-
|
|
11630
|
+
content += `## UI Concepts
|
|
11484
11631
|
|
|
11485
|
-
${componentsSection}
|
|
11486
11632
|
`;
|
|
11487
|
-
|
|
11633
|
+
if (uiConcepts.length === 0) {
|
|
11634
|
+
content += `None defined yet.
|
|
11488
11635
|
|
|
11489
11636
|
`;
|
|
11490
|
-
|
|
11491
|
-
|
|
11637
|
+
} else {
|
|
11638
|
+
for (const uc of uiConcepts) {
|
|
11639
|
+
content += `### ${uc.name}
|
|
11640
|
+
`;
|
|
11641
|
+
content += `**Description:** ${uc.description}
|
|
11492
11642
|
|
|
11493
11643
|
`;
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11644
|
+
}
|
|
11645
|
+
}
|
|
11646
|
+
content += `## User Intents
|
|
11647
|
+
|
|
11497
11648
|
`;
|
|
11649
|
+
if (userIntents.length === 0) {
|
|
11650
|
+
content += `None defined yet.
|
|
11651
|
+
|
|
11652
|
+
`;
|
|
11653
|
+
} else {
|
|
11654
|
+
for (const ui of userIntents) {
|
|
11655
|
+
content += `### ${ui.name}
|
|
11656
|
+
`;
|
|
11657
|
+
content += `**Description:** ${ui.description}
|
|
11658
|
+
|
|
11659
|
+
`;
|
|
11660
|
+
}
|
|
11498
11661
|
}
|
|
11662
|
+
if (designTokens.length > 0) {
|
|
11663
|
+
content += `## Design Tokens
|
|
11664
|
+
|
|
11665
|
+
`;
|
|
11666
|
+
for (const dt of designTokens) {
|
|
11667
|
+
content += `- **${dt.name}** - ${dt.description}
|
|
11668
|
+
`;
|
|
11669
|
+
}
|
|
11670
|
+
content += `
|
|
11671
|
+
`;
|
|
11672
|
+
}
|
|
11673
|
+
if (appShells.length > 0) {
|
|
11674
|
+
content += `## App Shell Integration
|
|
11675
|
+
|
|
11676
|
+
`;
|
|
11677
|
+
for (const as of appShells) {
|
|
11678
|
+
content += `- **${as.name}** - ${as.description}
|
|
11679
|
+
`;
|
|
11680
|
+
}
|
|
11681
|
+
content += `
|
|
11682
|
+
`;
|
|
11683
|
+
}
|
|
11684
|
+
content += `## Design Principles
|
|
11685
|
+
|
|
11686
|
+
`;
|
|
11687
|
+
content += `- The Web application is not responsible for enforcing business rules.
|
|
11688
|
+
`;
|
|
11689
|
+
content += `- The Web application is optimistic.
|
|
11690
|
+
`;
|
|
11691
|
+
content += `- The Web application is resilient.
|
|
11692
|
+
`;
|
|
11693
|
+
content += `- The Web application is accessible.
|
|
11694
|
+
`;
|
|
11695
|
+
content += `- The Web application is stateless whenever possible.
|
|
11696
|
+
`;
|
|
11697
|
+
content += `- The Web application delegates authority to Enterprise.
|
|
11698
|
+
`;
|
|
11699
|
+
content += `- The Web application enhances productivity rather than exposing implementation details.
|
|
11700
|
+
`;
|
|
11499
11701
|
content += `
|
|
11500
11702
|
`;
|
|
11501
|
-
|
|
11502
|
-
|
|
11703
|
+
content += `## Navigation Philosophy
|
|
11704
|
+
|
|
11705
|
+
`;
|
|
11706
|
+
content += `- The user shall never lose context.
|
|
11707
|
+
`;
|
|
11708
|
+
content += `- Every screen belongs to a Brain. Every Brain belongs to a Workspace.
|
|
11709
|
+
`;
|
|
11710
|
+
content += `- Every action should expose the current path.
|
|
11711
|
+
`;
|
|
11712
|
+
content += `- Deep linking shall exist for every page.
|
|
11713
|
+
`;
|
|
11714
|
+
content += `- Browser navigation shall always work.
|
|
11715
|
+
`;
|
|
11716
|
+
content += `- Multiple tabs shall be supported.
|
|
11717
|
+
`;
|
|
11718
|
+
content += `
|
|
11719
|
+
`;
|
|
11720
|
+
content += `## Degradation Strategy
|
|
11721
|
+
|
|
11722
|
+
`;
|
|
11723
|
+
content += `- If a feature API is unavailable, navigation still works.
|
|
11724
|
+
`;
|
|
11725
|
+
content += `- Editing still works.
|
|
11726
|
+
`;
|
|
11727
|
+
content += `- AI features are disabled gracefully, not causing errors.
|
|
11728
|
+
`;
|
|
11729
|
+
content += `- The application renders a degraded UI instead of crashing.
|
|
11730
|
+
`;
|
|
11731
|
+
content += `
|
|
11732
|
+
`;
|
|
11733
|
+
content += `## Ubiquitous Language
|
|
11503
11734
|
|
|
11504
11735
|
`;
|
|
11505
|
-
|
|
11506
|
-
|
|
11736
|
+
if (contextTerms.length === 0) {
|
|
11737
|
+
content += `None defined yet.
|
|
11738
|
+
|
|
11739
|
+
`;
|
|
11740
|
+
} else {
|
|
11741
|
+
content += `| Term | Definition | Aliases |
|
|
11742
|
+
`;
|
|
11743
|
+
content += `|------|-----------|---------|
|
|
11744
|
+
`;
|
|
11745
|
+
for (const t of contextTerms) {
|
|
11746
|
+
content += `| ${t.term} | ${t.definition} | ${t.aliases.join(", ")} |
|
|
11747
|
+
`;
|
|
11748
|
+
}
|
|
11749
|
+
content += `
|
|
11750
|
+
`;
|
|
11751
|
+
}
|
|
11752
|
+
content += `## Dependencies
|
|
11753
|
+
|
|
11754
|
+
`;
|
|
11755
|
+
content += `${depsSection}
|
|
11756
|
+
`;
|
|
11757
|
+
content += `## Key Files
|
|
11758
|
+
|
|
11759
|
+
None yet
|
|
11760
|
+
|
|
11761
|
+
`;
|
|
11762
|
+
content += `## ADRs
|
|
11763
|
+
|
|
11764
|
+
None yet
|
|
11507
11765
|
|
|
11508
11766
|
`;
|
|
11509
11767
|
} else {
|
|
11510
|
-
content
|
|
11768
|
+
content = `# ${bc.name}
|
|
11769
|
+
|
|
11511
11770
|
`;
|
|
11512
|
-
content +=
|
|
11771
|
+
content += `## Module Status
|
|
11772
|
+
|
|
11773
|
+
`;
|
|
11774
|
+
content += `**Status:** Planned
|
|
11775
|
+
`;
|
|
11776
|
+
content += `**Last reviewed:** ${timestamp}
|
|
11513
11777
|
`;
|
|
11514
|
-
|
|
11515
|
-
|
|
11778
|
+
content += `**Source session:** ${sessionId}
|
|
11779
|
+
|
|
11780
|
+
`;
|
|
11781
|
+
content += `## Description
|
|
11782
|
+
|
|
11783
|
+
${bc.description}
|
|
11784
|
+
|
|
11785
|
+
`;
|
|
11786
|
+
content += `## Components
|
|
11787
|
+
|
|
11788
|
+
${componentsSection}
|
|
11789
|
+
`;
|
|
11790
|
+
content += `## Domain Events
|
|
11791
|
+
|
|
11792
|
+
`;
|
|
11793
|
+
if (contextEvents.length === 0) {
|
|
11794
|
+
content += `None defined yet.
|
|
11795
|
+
|
|
11796
|
+
`;
|
|
11797
|
+
} else {
|
|
11798
|
+
for (const ev of contextEvents) {
|
|
11799
|
+
content += `- **${ev.name}** - ${ev.description} (triggered by: ${ev.triggeredBy})
|
|
11800
|
+
`;
|
|
11801
|
+
}
|
|
11802
|
+
content += `
|
|
11516
11803
|
`;
|
|
11517
11804
|
}
|
|
11518
|
-
content +=
|
|
11805
|
+
content += `## Ubiquitous Language
|
|
11806
|
+
|
|
11519
11807
|
`;
|
|
11520
|
-
|
|
11521
|
-
|
|
11808
|
+
if (contextTerms.length === 0) {
|
|
11809
|
+
content += `None defined yet.
|
|
11810
|
+
|
|
11811
|
+
`;
|
|
11812
|
+
} else {
|
|
11813
|
+
content += `| Term | Definition | Aliases |
|
|
11814
|
+
`;
|
|
11815
|
+
content += `|------|-----------|---------|
|
|
11816
|
+
`;
|
|
11817
|
+
for (const t of contextTerms) {
|
|
11818
|
+
content += `| ${t.term} | ${t.definition} | ${t.aliases.join(", ")} |
|
|
11819
|
+
`;
|
|
11820
|
+
}
|
|
11821
|
+
content += `
|
|
11822
|
+
`;
|
|
11823
|
+
}
|
|
11824
|
+
content += `## Dependencies
|
|
11522
11825
|
|
|
11523
11826
|
${depsSection}
|
|
11524
11827
|
`;
|
|
11525
|
-
|
|
11828
|
+
content += `## Key Files
|
|
11526
11829
|
|
|
11527
11830
|
None yet
|
|
11528
11831
|
|
|
11529
11832
|
`;
|
|
11530
|
-
|
|
11833
|
+
content += `## ADRs
|
|
11531
11834
|
|
|
11532
11835
|
None yet
|
|
11533
11836
|
|
|
11534
11837
|
`;
|
|
11838
|
+
}
|
|
11535
11839
|
if (!dryRun) {
|
|
11536
11840
|
fs12.mkdirSync(modulesDir, { recursive: true });
|
|
11537
11841
|
const tempPath = `${filePath}.tmp`;
|
package/package.json
CHANGED
|
@@ -10,18 +10,40 @@ Generated: NEVER (this is the source)
|
|
|
10
10
|
|
|
11
11
|
[Brief description of the module's purpose and scope within the system]
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## DDD Layers
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- [Responsibility 2]
|
|
17
|
-
- [Responsibility 3]
|
|
15
|
+
This module follows Clean Architecture with 4 DDD layers:
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
| Layer | Purpose | Tech |
|
|
18
|
+
|-------|---------|------|
|
|
19
|
+
| `domain/` | Pure business logic, types, errors | Zero framework imports |
|
|
20
|
+
| `application/` | State management, use cases, actions | Stores, Server Actions |
|
|
21
|
+
| `infrastructure/` | External adapters, API clients, SDKs | Fetch, tRPC, GraphQL |
|
|
22
|
+
| `interfaces/` | UI components, pages, layouts | React, Next.js |
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
**Dependency rule:** `domain → application → infrastructure → interfaces` (inward)
|
|
25
|
+
|
|
26
|
+
## Components by Layer
|
|
27
|
+
|
|
28
|
+
### Domain Layer (`domain/`)
|
|
29
|
+
| Component | Description | Framework? |
|
|
30
|
+
|-----------|-------------|------------|
|
|
31
|
+
| [Name] | [Purpose] | ❌ No |
|
|
32
|
+
|
|
33
|
+
### Application Layer (`application/`)
|
|
34
|
+
| Component | Description | Type |
|
|
35
|
+
|-----------|-------------|------|
|
|
36
|
+
| [Name] | [Purpose] | Store / Action / Query |
|
|
37
|
+
|
|
38
|
+
### Infrastructure Layer (`infrastructure/`)
|
|
39
|
+
| Component | Description | Connects to |
|
|
40
|
+
|-----------|-------------|-------------|
|
|
41
|
+
| [Name] | [Purpose] | [API / SDK] |
|
|
42
|
+
|
|
43
|
+
### Interfaces Layer (`interfaces/`)
|
|
44
|
+
| Component | Description | 'use client'? |
|
|
45
|
+
|-----------|-------------|---------------|
|
|
46
|
+
| [Name] | [Purpose] | Yes / No |
|
|
25
47
|
|
|
26
48
|
---
|
|
27
49
|
|
|
@@ -31,35 +53,40 @@ Generated: NEVER (this is the source)
|
|
|
31
53
|
|
|
32
54
|
**Purpose:** [What this component does]
|
|
33
55
|
|
|
34
|
-
**
|
|
56
|
+
**DDL Layer:** `[domain/application/infrastructure/interfaces]`
|
|
57
|
+
|
|
58
|
+
**Implementation File:** `src/[module]/[layer]/[file].ts`
|
|
35
59
|
|
|
36
60
|
**Canonical Reference:** `.pi/architecture/modules/[module-name].md#[component-section]`
|
|
37
61
|
|
|
62
|
+
**States:**
|
|
63
|
+
- **Loading:** [What the user sees during load]
|
|
64
|
+
- **Empty:** [What the user sees when there's no data]
|
|
65
|
+
- **Populated:** [Normal state]
|
|
66
|
+
- **Error:** [What the user sees on failure]
|
|
67
|
+
|
|
38
68
|
**Dependencies:**
|
|
39
69
|
- [Dependency 1]
|
|
40
70
|
- [Dependency 2]
|
|
41
71
|
|
|
42
|
-
**Interface:**
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
// Public interface
|
|
46
|
-
interface [InterfaceName] {
|
|
47
|
-
[method signatures]
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
72
|
---
|
|
52
73
|
|
|
53
74
|
## Data Flow
|
|
54
75
|
|
|
55
76
|
```
|
|
56
|
-
|
|
77
|
+
User Intent
|
|
57
78
|
│
|
|
58
79
|
▼
|
|
59
|
-
|
|
80
|
+
Component (interfaces/) → user action
|
|
60
81
|
│
|
|
61
82
|
▼
|
|
62
|
-
|
|
83
|
+
Store/Server Action (application/) → optimistic update
|
|
84
|
+
│
|
|
85
|
+
▼
|
|
86
|
+
API Client (infrastructure/) → fetch
|
|
87
|
+
│
|
|
88
|
+
▼
|
|
89
|
+
Response → commit or rollback → UI update
|
|
63
90
|
```
|
|
64
91
|
|
|
65
92
|
**Flow Description:**
|
|
@@ -69,40 +96,57 @@ interface [InterfaceName] {
|
|
|
69
96
|
|
|
70
97
|
---
|
|
71
98
|
|
|
99
|
+
## User Intents
|
|
100
|
+
|
|
101
|
+
| Intent | Triggered By | Handled By | Domain Event (backend) |
|
|
102
|
+
|--------|-------------|------------|----------------------|
|
|
103
|
+
| UserClickedThread | Click on thread title | ThreadPanel | ThreadSelected |
|
|
104
|
+
| UserSubmittedComment | Click Submit button | CommentInput | CommentCreated |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Design Principles
|
|
109
|
+
|
|
110
|
+
- This module is **optimistic**: UI updates before API responds
|
|
111
|
+
- This module is **resilient**: failure doesn't crash other modules
|
|
112
|
+
- This module is **stateless**: state lives in stores, not server
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Degradation Strategy
|
|
117
|
+
|
|
118
|
+
| Feature | When Unavailable | User Sees |
|
|
119
|
+
|---------|-----------------|-----------|
|
|
120
|
+
| [Feature] | API is down | [Degraded state] |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
72
124
|
## Dependencies
|
|
73
125
|
|
|
74
126
|
### Depends On
|
|
75
127
|
- **[Module Name]**: [Why/what it provides]
|
|
76
|
-
- **[Module Name]**: [Why/what it provides]
|
|
77
128
|
|
|
78
129
|
### Used By
|
|
79
130
|
- **[Module Name]**: [Why/what it uses]
|
|
80
|
-
- **[Module Name]**: [Why/what it uses]
|
|
81
131
|
|
|
82
132
|
---
|
|
83
133
|
|
|
84
134
|
## Security Considerations
|
|
85
135
|
|
|
86
|
-
| Concern | Mitigation |
|
|
87
|
-
|
|
88
|
-
| [Concern 1] | [Mitigation] |
|
|
89
|
-
| [Concern 2] | [Mitigation] | security-validator |
|
|
90
|
-
|
|
91
|
-
**Authentication/Authorization:**
|
|
92
|
-
- [Auth requirements]
|
|
93
|
-
|
|
94
|
-
**Data Protection:**
|
|
95
|
-
- [Encryption/sanitization requirements]
|
|
136
|
+
| Concern | Mitigation |
|
|
137
|
+
|---------|------------|
|
|
138
|
+
| [Concern 1] | [Mitigation] |
|
|
96
139
|
|
|
97
140
|
---
|
|
98
141
|
|
|
99
142
|
## Testing Requirements
|
|
100
143
|
|
|
101
|
-
| Test Type | Coverage Target |
|
|
102
|
-
|
|
103
|
-
| Unit | [X]% |
|
|
104
|
-
|
|
|
105
|
-
|
|
|
144
|
+
| Layer | Test Type | Coverage Target |
|
|
145
|
+
|-------|-----------|-----------------|
|
|
146
|
+
| Domain | Unit | [X]% |
|
|
147
|
+
| Application | Unit | [X]% |
|
|
148
|
+
| Infrastructure | Integration | [X]% |
|
|
149
|
+
| Interfaces | Component | [X]% |
|
|
106
150
|
|
|
107
151
|
**Key Test Scenarios:**
|
|
108
152
|
- [Scenario 1]
|
|
@@ -113,17 +157,17 @@ interface [InterfaceName] {
|
|
|
113
157
|
|
|
114
158
|
## Error Handling
|
|
115
159
|
|
|
160
|
+
**Domain errors (domain/):**
|
|
116
161
|
```typescript
|
|
117
|
-
// Error types defined in this module
|
|
118
162
|
class [ErrorType] extends Error {
|
|
119
|
-
constructor(message: string) {
|
|
163
|
+
constructor(code: string, message: string, retriable?: boolean) {
|
|
120
164
|
super(message);
|
|
121
165
|
this.name = '[ErrorType]';
|
|
122
166
|
}
|
|
123
167
|
}
|
|
124
168
|
```
|
|
125
169
|
|
|
126
|
-
**
|
|
170
|
+
**Recovery:**
|
|
127
171
|
- [Error 1]: [Recovery strategy]
|
|
128
172
|
- [Error 2]: [Recovery strategy]
|
|
129
173
|
|
|
@@ -131,22 +175,11 @@ class [ErrorType] extends Error {
|
|
|
131
175
|
|
|
132
176
|
## Performance Considerations
|
|
133
177
|
|
|
134
|
-
| Metric | Target |
|
|
135
|
-
|
|
136
|
-
|
|
|
137
|
-
| Throughput | [Y] req/s | [How monitored] |
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Change Log References
|
|
142
|
-
|
|
143
|
-
| Date | Change | Section | Status |
|
|
144
|
-
|------|--------|---------|--------|
|
|
145
|
-
| [date] | [description] | #[section] | [synced/pending] |
|
|
146
|
-
|
|
147
|
-
See full details in `.pi/architecture/CHANGELOG.md`
|
|
178
|
+
| Metric | Target | Strategy |
|
|
179
|
+
|--------|--------|----------|
|
|
180
|
+
| [Metric] | [Target] | [Strategy] |
|
|
148
181
|
|
|
149
182
|
---
|
|
150
183
|
|
|
151
184
|
*Last updated: [date]*
|
|
152
|
-
*Module version: [version]*
|
|
185
|
+
*Module version: [version]*
|