speccore 8.3.285 → 8.3.295

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 (143) hide show
  1. package/.agents/skills/spec-run/SKILL.md +16 -0
  2. package/.agents/skills/spec-task-create/SKILL.md +15 -0
  3. package/.agents/skills/spec-unitize/SKILL.md +16 -0
  4. package/README.en.md +16 -3
  5. package/README.md +23 -8
  6. package/dist/cli.js +59 -12
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/about.d.ts.map +1 -1
  9. package/dist/commands/about.js +5 -0
  10. package/dist/commands/about.js.map +1 -1
  11. package/dist/commands/analyze.d.ts.map +1 -1
  12. package/dist/commands/analyze.js +77 -5
  13. package/dist/commands/analyze.js.map +1 -1
  14. package/dist/commands/ask.js +2 -2
  15. package/dist/commands/ask.js.map +1 -1
  16. package/dist/commands/code-index.d.ts.map +1 -1
  17. package/dist/commands/code-index.js +20 -9
  18. package/dist/commands/code-index.js.map +1 -1
  19. package/dist/commands/doc2spec.js +32 -60
  20. package/dist/commands/doc2spec.js.map +1 -1
  21. package/dist/commands/execute.d.ts +1 -0
  22. package/dist/commands/execute.d.ts.map +1 -1
  23. package/dist/commands/execute.js +15 -1
  24. package/dist/commands/execute.js.map +1 -1
  25. package/dist/commands/help.js +14 -5
  26. package/dist/commands/help.js.map +1 -1
  27. package/dist/commands/init.d.ts.map +1 -1
  28. package/dist/commands/init.js +14 -3
  29. package/dist/commands/init.js.map +1 -1
  30. package/dist/commands/iteration/taskify.d.ts.map +1 -1
  31. package/dist/commands/iteration/taskify.js +132 -7
  32. package/dist/commands/iteration/taskify.js.map +1 -1
  33. package/dist/commands/run.d.ts +1 -0
  34. package/dist/commands/run.d.ts.map +1 -1
  35. package/dist/commands/run.js +193 -25
  36. package/dist/commands/run.js.map +1 -1
  37. package/dist/commands/status-panel.d.ts +1 -0
  38. package/dist/commands/status-panel.d.ts.map +1 -1
  39. package/dist/commands/status-panel.js +180 -54
  40. package/dist/commands/status-panel.js.map +1 -1
  41. package/dist/commands/task/new.d.ts +16 -0
  42. package/dist/commands/task/new.d.ts.map +1 -1
  43. package/dist/commands/task/new.js +232 -14
  44. package/dist/commands/task/new.js.map +1 -1
  45. package/dist/commands/verify.d.ts.map +1 -1
  46. package/dist/commands/verify.js +78 -1
  47. package/dist/commands/verify.js.map +1 -1
  48. package/dist/core/analyze-engine.d.ts.map +1 -1
  49. package/dist/core/analyze-engine.js +6 -10
  50. package/dist/core/analyze-engine.js.map +1 -1
  51. package/dist/core/ask-llm.d.ts +7 -0
  52. package/dist/core/ask-llm.d.ts.map +1 -1
  53. package/dist/core/ask-llm.js +45 -0
  54. package/dist/core/ask-llm.js.map +1 -1
  55. package/dist/core/code-graph/incremental-build.d.ts +2 -0
  56. package/dist/core/code-graph/incremental-build.d.ts.map +1 -1
  57. package/dist/core/code-graph/incremental-build.js +6 -5
  58. package/dist/core/code-graph/incremental-build.js.map +1 -1
  59. package/dist/core/code-graph/index.d.ts +2 -0
  60. package/dist/core/code-graph/index.d.ts.map +1 -1
  61. package/dist/core/code-graph/index.js +12 -5
  62. package/dist/core/code-graph/index.js.map +1 -1
  63. package/dist/core/code-scanner.d.ts +19 -4
  64. package/dist/core/code-scanner.d.ts.map +1 -1
  65. package/dist/core/code-scanner.js +193 -77
  66. package/dist/core/code-scanner.js.map +1 -1
  67. package/dist/core/excel-extract.d.ts +16 -2
  68. package/dist/core/excel-extract.d.ts.map +1 -1
  69. package/dist/core/excel-extract.js +54 -12
  70. package/dist/core/excel-extract.js.map +1 -1
  71. package/dist/core/git-integration.d.ts +2 -1
  72. package/dist/core/git-integration.d.ts.map +1 -1
  73. package/dist/core/git-integration.js +38 -14
  74. package/dist/core/git-integration.js.map +1 -1
  75. package/dist/core/global-counters.d.ts +3 -0
  76. package/dist/core/global-counters.d.ts.map +1 -1
  77. package/dist/core/global-counters.js +21 -7
  78. package/dist/core/global-counters.js.map +1 -1
  79. package/dist/core/intent-recognition.d.ts.map +1 -1
  80. package/dist/core/intent-recognition.js +173 -27
  81. package/dist/core/intent-recognition.js.map +1 -1
  82. package/dist/core/plan-store.d.ts +1 -0
  83. package/dist/core/plan-store.d.ts.map +1 -1
  84. package/dist/core/plan-store.js.map +1 -1
  85. package/dist/core/prompt-builder.d.ts.map +1 -1
  86. package/dist/core/prompt-builder.js +168 -140
  87. package/dist/core/prompt-builder.js.map +1 -1
  88. package/dist/core/spec-paths.d.ts.map +1 -1
  89. package/dist/core/spec-paths.js +3 -0
  90. package/dist/core/spec-paths.js.map +1 -1
  91. package/dist/core/spec-skeleton.d.ts.map +1 -1
  92. package/dist/core/spec-skeleton.js +6 -2
  93. package/dist/core/spec-skeleton.js.map +1 -1
  94. package/dist/core/stage-aliases.d.ts +40 -0
  95. package/dist/core/stage-aliases.d.ts.map +1 -0
  96. package/dist/core/stage-aliases.js +110 -0
  97. package/dist/core/stage-aliases.js.map +1 -0
  98. package/dist/core/state.d.ts +11 -0
  99. package/dist/core/state.d.ts.map +1 -1
  100. package/dist/core/state.js +33 -2
  101. package/dist/core/state.js.map +1 -1
  102. package/dist/core/structured-extractor.d.ts.map +1 -1
  103. package/dist/core/structured-extractor.js +7 -0
  104. package/dist/core/structured-extractor.js.map +1 -1
  105. package/dist/core/ui-verify/index.d.ts +2 -2
  106. package/dist/core/ui-verify/index.d.ts.map +1 -1
  107. package/dist/core/ui-verify/index.js +3 -1
  108. package/dist/core/ui-verify/index.js.map +1 -1
  109. package/dist/core/ui-verify/smoke-engine.d.ts.map +1 -1
  110. package/dist/core/ui-verify/smoke-engine.js +36 -0
  111. package/dist/core/ui-verify/smoke-engine.js.map +1 -1
  112. package/dist/core/ui-verify/spec-generator.d.ts +32 -1
  113. package/dist/core/ui-verify/spec-generator.d.ts.map +1 -1
  114. package/dist/core/ui-verify/spec-generator.js +205 -21
  115. package/dist/core/ui-verify/spec-generator.js.map +1 -1
  116. package/dist/core/ui-verify/types.d.ts +2 -0
  117. package/dist/core/ui-verify/types.d.ts.map +1 -1
  118. package/dist/utils/synonyms.d.ts.map +1 -1
  119. package/dist/utils/synonyms.js +15 -0
  120. package/dist/utils/synonyms.js.map +1 -1
  121. package/package.json +3 -2
  122. package/templates/api-design-example.md +338 -0
  123. package/templates/ci/github-actions.yml +44 -0
  124. package/templates/database-example.md +223 -0
  125. package/templates/deploy-docker/README.md +284 -0
  126. package/templates/deploy-docker/deploy-remote.sh +79 -0
  127. package/templates/deploy-docker/docker-compose.yml +113 -0
  128. package/templates/deploy-docker/frontend.Dockerfile +43 -0
  129. package/templates/deploy-docker/nginx.conf +30 -0
  130. package/templates/deploy-examples.yaml +436 -0
  131. package/templates/deploy-java/Dockerfile +50 -0
  132. package/templates/deploy-java/README.md +212 -0
  133. package/templates/deploy-java/deploy.sh +120 -0
  134. package/templates/deploy-java/spring-boot.service +35 -0
  135. package/templates/html/speccore-ask-explain.html +10 -0
  136. package/templates/html/speccore-ask-guide.html +10 -0
  137. package/templates/html/speccore-ask-match.html +10 -0
  138. package/templates/html/speccore-ask-pipeline.html +1 -0
  139. package/templates/html/speccore-ask-result.html +10 -0
  140. package/templates/html/speccore-help.html +241 -0
  141. package/templates/html/speccore-setup-guide.html +289 -0
  142. package/templates/security-example.md +226 -0
  143. package/templates/verify-spec-example.yaml +138 -0
@@ -0,0 +1,289 @@
1
+ <!DOCTYPE html><html lang="zh-CN" data-theme="ocean"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>SpecCore — 项目配置引导</title>
2
+ <style>
3
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;900&family=JetBrains+Mono:wght@400;600;700&display=swap');
4
+ [data-theme="ocean"]{--cyan:#0ea5e9;--bg:#0b1929;--card:rgba(13,31,56,.95);--border:rgba(14,165,233,.15);--text:#bae6fd;--muted:#5b7fa5;--green:#14b8a6;--orange:#f97316;--purple:#6366f1;--red:#ef4444}
5
+ *{margin:0;padding:0;box-sizing:border-box}
6
+ body{font-family:'JetBrains Mono',monospace;background:var(--bg);color:var(--text);min-height:100vh;padding:24px 20px;position:relative}
7
+ .scanlines{position:fixed;inset:0;pointer-events:none;z-index:99;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,240,255,.015) 2px,rgba(0,240,255,.015) 4px)}
8
+ .grid-pattern{position:fixed;inset:0;pointer-events:none;z-index:0;background-image:linear-gradient(rgba(14,165,233,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(14,165,233,.03) 1px,transparent 1px);background-size:60px 60px}
9
+ h1{font-family:'Orbitron',sans-serif;font-size:28px;font-weight:900;background:linear-gradient(135deg,var(--cyan),var(--purple));-webkit-background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:2px;text-align:center;text-shadow:0 0 20px rgba(14,165,233,.4);animation:titleGlow 3s ease-in-out infinite}
10
+ @keyframes titleGlow{0%,100%{text-shadow:0 0 20px rgba(14,165,233,.4),0 0 60px rgba(14,165,233,.15)}50%{text-shadow:0 0 30px rgba(14,165,233,.7),0 0 80px rgba(14,165,233,.3)}}
11
+ .sub{color:var(--muted);font-size:11px;letter-spacing:1px;text-align:center;margin-top:4px}
12
+ .header-card{text-align:center;padding:16px 0 12px;margin-bottom:8px;position:relative;border-bottom:1px solid rgba(14,165,233,.1)}
13
+ .header-card::after{content:'';position:absolute;bottom:-1px;left:20%;right:20%;height:1px;background:linear-gradient(90deg,transparent,var(--cyan),transparent)}
14
+ .container{max-width:960px;margin:0 auto;position:relative;z-index:1;background:rgba(13,31,56,.85);border:1px solid var(--border);border-radius:16px;padding:24px 20px;overflow:hidden}
15
+ .container::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);animation:scanX 3s linear infinite}
16
+ .container::after{content:'';position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);animation:scanX-rev 3s linear infinite}
17
+ .container .vline{position:absolute;top:0;width:1px;bottom:0;pointer-events:none;z-index:2}
18
+ .container .vline.l{left:0;background:linear-gradient(180deg,transparent,var(--cyan),transparent);animation:scanY-rev 3s linear infinite}
19
+ .container .vline.r{right:0;background:linear-gradient(180deg,transparent,var(--cyan),transparent);animation:scanY 3s linear infinite}
20
+ .card-bg{position:absolute;inset:0;pointer-events:none;z-index:5;background:radial-gradient(ellipse at 50% 10%,rgba(14,165,233,.2) 0%,transparent 70%);animation:cardGlow 3s ease-in-out infinite;transform-origin:top center}
21
+ @keyframes cardGlow{0%,100%{opacity:.5;transform:scale(1)}50%{opacity:1;transform:scale(1.6)}}
22
+ @keyframes scanX{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
23
+ @keyframes scanX-rev{0%{transform:translateX(100%)}100%{transform:translateX(-100%)}}
24
+ @keyframes scanY{0%{transform:translateY(-100%)}100%{transform:translateY(100%)}}
25
+ @keyframes scanY-rev{0%{transform:translateY(100%)}100%{transform:translateY(-100%)}}
26
+ .step{margin:16px 0;padding:18px;background:rgba(13,31,56,.75);border:1px solid var(--border);border-radius:12px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(14,165,233,.08),inset 0 1px 24px rgba(14,165,233,.04);transition:box-shadow .3s ease,border-color .3s ease}
27
+ .step:hover{box-shadow:0 0 30px rgba(14,165,233,.15),inset 0 1px 30px rgba(14,165,233,.08);border-color:rgba(14,165,233,.3)}
28
+ .step-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;background:linear-gradient(135deg,var(--cyan),var(--purple));color:#fff;font-weight:900;font-size:13px;margin-right:10px;flex-shrink:0}
29
+ .step-header{display:flex;align-items:center;margin-bottom:12px}
30
+ .step-title{font-size:15px;font-weight:700;color:var(--cyan)}
31
+ .step-required{display:inline-block;padding:2px 8px;font-size:9px;border-radius:4px;background:rgba(239,68,68,.15);color:var(--red);margin-left:8px;font-weight:600}
32
+ .step-optional{display:inline-block;padding:2px 8px;font-size:9px;border-radius:4px;background:rgba(14,165,233,.1);color:var(--cyan);margin-left:8px}
33
+ .step-desc{font-size:11px;color:var(--muted);margin:8px 0;line-height:1.6}
34
+ .file-box{background:rgba(14,165,233,.06);border:1px solid rgba(14,165,233,.12);border-radius:8px;padding:12px;margin:10px 0;font-size:11px}
35
+ .file-path{color:var(--cyan);font-weight:600;font-size:12px}
36
+ .field-list{margin:8px 0;padding-left:8px}
37
+ .field-item{display:flex;align-items:flex-start;gap:8px;margin:6px 0;font-size:11px;line-height:1.5}
38
+ .field-check{color:var(--green);flex-shrink:0;font-size:13px}
39
+ .field-warn{color:var(--orange);flex-shrink:0;font-size:13px}
40
+ .field-name{color:var(--text);font-weight:600;min-width:100px}
41
+ .field-desc{color:var(--muted)}
42
+ .method-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:10px 0}
43
+ .method-card{padding:12px;border-radius:8px;border:1px solid rgba(255,255,255,.06);background:rgba(255,255,255,.02)}
44
+ .method-title{font-size:11px;font-weight:700;margin-bottom:6px}
45
+ .method-card.m1 .method-title{color:var(--green)}
46
+ .method-card.m2 .method-title{color:var(--orange)}
47
+ .method-card.m3 .method-title{color:var(--cyan)}
48
+ .method-card.m4 .method-title{color:var(--purple)}
49
+ .method-cmd{font-size:10px;color:var(--muted);background:rgba(0,0,0,.2);padding:4px 8px;border-radius:4px;margin-top:6px;word-break:break-all}
50
+ .flow-bar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;justify-content:center;padding:16px;margin:16px 0;background:var(--card);border:1px solid var(--border);border-radius:12px}
51
+ .flow-node{padding:8px 14px;border-radius:8px;font-size:11px;font-weight:600;border:1px solid}
52
+ .flow-node.n1{border-color:var(--green);color:var(--green);background:rgba(20,184,166,.08)}
53
+ .flow-node.n2{border-color:var(--cyan);color:var(--cyan);background:rgba(14,165,233,.08)}
54
+ .flow-node.n3{border-color:var(--orange);color:var(--orange);background:rgba(249,115,22,.08)}
55
+ .flow-node.n4{border-color:var(--purple);color:var(--purple);background:rgba(99,102,241,.08)}
56
+ .flow-arrow{color:var(--muted);font-size:14px}
57
+ .kb-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin:10px 0}
58
+ .kb-card{padding:10px;border-radius:8px;border:1px solid rgba(255,255,255,.06);background:rgba(255,255,255,.02);text-align:center}
59
+ .kb-icon{font-size:20px;margin-bottom:4px}
60
+ .kb-name{font-size:11px;font-weight:600;color:var(--text)}
61
+ .kb-desc{font-size:9px;color:var(--muted);margin-top:4px}
62
+ .start-bar{display:block;text-align:center;padding:16px;margin:20px 0 8px;background:linear-gradient(135deg,var(--cyan) 0%,#0284c7 100%);border-radius:40px;color:#fff;font-weight:600;font-size:14px;box-shadow:0 0 30px rgba(14,165,233,.3);cursor:pointer;letter-spacing:1px;text-decoration:none;transition:all .3s;position:relative;z-index:1}
63
+ .start-bar:hover{box-shadow:0 0 45px rgba(14,165,233,.5);transform:translateY(-1px)}
64
+ .action-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin:20px 0}
65
+ .action-card{padding:16px;border-radius:12px;border:1px solid var(--border);background:rgba(13,31,56,.7);text-align:center;cursor:pointer;text-decoration:none;transition:all .3s;position:relative;z-index:1}
66
+ .action-card.primary{background:linear-gradient(135deg,var(--cyan) 0%,#0284c7 100%);border-color:var(--cyan);color:#fff}
67
+ .action-card.secondary{border-color:rgba(14,165,233,.2);color:var(--text)}
68
+ .action-card:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(14,165,233,.2)}
69
+ .action-icon{font-size:28px;margin-bottom:8px}
70
+ .action-title{font-size:13px;font-weight:700;margin-bottom:4px}
71
+ .action-desc{font-size:10px;color:var(--muted);line-height:1.4}
72
+ .action-card.primary .action-desc{color:rgba(255,255,255,.8)}
73
+ .faq-section{margin:16px 0;padding:16px;background:rgba(13,31,56,.6);border:1px solid var(--border);border-radius:12px}
74
+ .faq-title{font-size:13px;font-weight:700;color:var(--cyan);margin-bottom:12px}
75
+ .faq-item{margin:10px 0;padding:10px 12px;border-radius:8px;background:rgba(14,165,233,.04);border:1px solid rgba(14,165,233,.1)}
76
+ .faq-q{font-size:11px;font-weight:600;color:var(--text);margin-bottom:6px}
77
+ .faq-a{font-size:10px;color:var(--muted);line-height:1.6}
78
+ .footer{text-align:center;color:var(--muted);font-size:10px;margin-top:20px;padding-top:12px;border-top:1px solid rgba(255,255,255,.04)}
79
+ </style></head><body>
80
+ <div class="scanlines"></div><div class="grid-pattern"></div>
81
+ <div class="container">
82
+ <div class="vline l"></div><div class="vline r"></div><div class="card-bg"></div>
83
+ <div class="header-card">
84
+ <h1>SPECCORE</h1>
85
+ <div class="sub">项目配置引导 · {{PROJECT_NAME}}</div>
86
+ </div>
87
+
88
+ <div class="step">
89
+ <div class="step-header"><span class="step-num">1</span><span class="step-title">技术宪法</span><span class="step-required">必填</span></div>
90
+ <div class="step-desc">AI 的「最高指令」—— 所有需求分析、任务拆分、代码生成全部据此执行。决定了生成代码的技术栈、命名规范、错误码体系。</div>
91
+ <div class="file-box">
92
+ <div class="file-path">📄 .speccore/CONSTITUTION.md</div>
93
+ <div class="step-desc" style="color:var(--green);margin-bottom:8px">✅ init 已自动检测:工程名、Git 仓库地址。其余字段可通过以下方式完善:</div>
94
+ <div class="method-grid" style="grid-template-columns:1fr 1fr;margin-bottom:10px">
95
+ <div class="method-card m1"><div class="method-title">🤖 方式 1:AI 扫描工程代码(推荐)</div><div class="step-desc">AI 读取源码自动识别技术栈、框架、命名风格,直接写入。说不同的话,改不同的范围:</div><div class="method-cmd" style="margin-top:4px">/spec-ask "分析代码,完善技术宪法" <span style="color:var(--green)">← 只改宪法</span></div><div class="method-cmd">/spec-ask "分析项目,完善所有配置" <span style="color:var(--cyan)">← 宪法+团队+索引</span></div><div class="method-cmd">/spec-ask "扫描代码,生成代码索引" <span style="color:var(--orange)">← 只建索引</span></div></div>
96
+ <div class="method-card m2"><div class="method-title">✍️ 方式 2:手动编辑</div><div class="step-desc">打开文件按注释提示填写,只填必填项即可,其余按需补充</div><div class="method-cmd">编辑 .speccore/CONSTITUTION.md</div></div>
97
+ </div>
98
+ <div style="margin:10px 0;padding:10px 12px;border-radius:8px;border:1px solid rgba(14,165,233,.15);background:rgba(14,165,233,.04)">
99
+ <div style="font-size:12px;font-weight:700;color:var(--cyan);margin-bottom:4px">🔍 全局分析(了解现有项目推荐)</div>
100
+ <div class="step-desc">一句话扫描所有工程源码,自动生成技术栈、接口清单、数据模型等 8 类文档。适合接手新项目时快速摸清全貌:</div>
101
+ <div class="method-cmd">/spec-ask "全局分析所有工程代码" <span style="color:var(--green)">← 意图式</span></div>
102
+ <div class="method-cmd">/spec-analyze --scope global <span style="color:var(--orange)">← 显式命令</span></div>
103
+ <div style="font-size:10px;color:var(--muted);margin-top:4px">--scope global — 全项目范围(非迭代级),在 AI 对话框中输入</div>
104
+ <div class="step-desc" style="margin-top:4px">📂 输出到 .speccore/GLOBAL/platforms/{端名}/,每端独立一套(TECH_STACK / API_INVENTORY / DATA_MODEL ...)<br>⏱ 与迭代分析不同:全局分析扫源码生成项目文档,迭代分析读需求生成技术规格(步骤 6 做的事)</div>
105
+ </div>
106
+ <div class="field-list">
107
+ <div class="field-item"><span class="field-check">✅</span><span class="field-name">项目信息表</span><span class="field-desc">— 工程名 / 源码路径 / Git 仓库(init 已自动填写)</span></div>
108
+ <div class="field-item"><span class="field-check">✅</span><span class="field-name">技术栈</span><span class="field-desc">— 后端语言+框架、前端框架、数据库、缓存</span></div>
109
+ <div class="field-item"><span class="field-check">✅</span><span class="field-name">命名规范</span><span class="field-desc">— API 路径、错误码、数据库、代码命名风格</span></div>
110
+ <div class="field-item"><span class="field-warn">⬜</span><span class="field-name">异常码体系</span><span class="field-desc">— 按模块定义错误码表(可选,按需补充)</span></div>
111
+ <div class="field-item"><span class="field-warn">⬜</span><span class="field-name">Git 分支策略</span><span class="field-desc">— 默认分支、任务分支、保护分支规则(可选)</span></div>
112
+ </div>
113
+ <div class="step-desc" style="margin-top:8px;color:var(--cyan)">💡 作用:AI 生成代码时严格遵循这里的技术栈。例如写了 Spring Boot + MySQL,AI 就不会生成 NestJS + PostgreSQL 的代码。</div>
114
+ </div>
115
+ <div style="margin-top:12px;padding:10px 12px;border-radius:8px;border:1px solid rgba(99,102,241,.15);background:rgba(99,102,241,.04)">
116
+ <div style="font-size:12px;font-weight:700;color:var(--purple);margin-bottom:6px">📋 双配置系统(v8.3.25+)</div>
117
+ <div class="step-desc" style="margin-bottom:8px">除 CONSTITUTION.md 外,init 还自动生成了两个 YAML 配置文件,分别控制系统级和项目级行为:</div>
118
+ <div class="method-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
119
+ <div class="method-card m3"><div class="method-title">⚙️ .speccore.yml — 系统配置</div><div class="step-desc">控制 CLI 运行时行为:质量门禁、AI 路由、自动化策略。所有字段已带中文注释,按需修改即可。</div><div class="method-cmd" style="margin-top:4px">quality_gates / arbitration / settings / ask</div></div>
120
+ <div class="method-card m4"><div class="method-title">🏗️ .speccore/PROJECT.yaml — 项目配置</div><div class="step-desc">定义工程列表、源码路径、Git 配置。init 时 platforms 为空,需手动添加你的后端/前端工程。</div><div class="method-cmd" style="margin-top:4px">platforms / git / code_scope</div></div>
121
+ </div>
122
+ <div class="step-desc" style="font-size:10px">💡 快速配置:用 AI 扫描代码自动填写 — <code>/spec-ask "分析项目,完善所有配置"</code></div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="step">
127
+ <div class="step-header"><span class="step-num">2</span><span class="step-title">配置团队排期</span><span class="step-optional">可选</span></div>
128
+ <div class="step-desc">填写团队成员和可用天数。AI 拆分任务时会根据团队规模自动调整粒度,一个端可以有多个负责人,作为拆分时的默认责任人参考(后期可手动修改)。</div>
129
+ <div class="file-box">
130
+ <div class="file-path">📄 Iteration-xxx/STAFFING.md(步骤 3 创建迭代后生成)</div>
131
+ <div class="step-desc">格式示例:<br>
132
+ | 成员 | 角色 | 负责端 | 每周可用天数 |<br>
133
+ | 张三 | 后端 | API 服务 | 5 |<br>
134
+ | 李四 | 前端 | Web, H5 | 4 |<br>
135
+ | 王五 | 全栈 | Admin | 3 |</div>
136
+ <div class="step-desc" style="color:var(--green)">💡 联动:≤3人 → 粗粒度拆分 | 4-8人 → 中粒度(默认)| >8人 → 细粒度拆分</div>
137
+ </div>
138
+ </div>
139
+
140
+ <div class="step">
141
+ <div class="step-header"><span class="step-num">3</span><span class="step-title">创建迭代</span><span class="step-required">必填</span></div>
142
+ <div class="step-desc">迭代是一组需求的载体,包含需求文档、任务、代码等所有内容。先创建一个迭代,再把需求放进去。</div>
143
+ <div class="file-box">
144
+ <div class="file-path">📁 创建后生成的目录结构</div>
145
+ <div class="step-desc">
146
+ Iteration-xxx/<br>
147
+ ├── 010-requirements/ ← 放需求文档的地方<br>
148
+ ├── 020-specs/ ← AI 分析后生成的技术规格<br>
149
+ └── 030-tasks/ ← AI 拆分后的开发任务
150
+ </div>
151
+ <div class="method-cmd" style="margin-top:8px">speccore iteration create -n &lt;迭代短名&gt; --topic &lt;中文描述&gt;</div>
152
+ <div style="margin-top:8px;font-size:10px;color:var(--muted)">-n &lt;迭代短名&gt; — 自定义英文名(如 login / Q1),后续命令用它引用<br>--topic &lt;中文描述&gt; — 迭代用途说明(如 "登录功能")</div>
153
+ <div class="step-desc" style="color:var(--cyan);margin-top:8px">💡 这是 CLI 命令,在终端中执行。创建后在下方步骤导入需求时用这个短名引用。</div>
154
+ </div>
155
+ </div>
156
+
157
+ <div class="step">
158
+ <div class="step-header"><span class="step-num">4</span><span class="step-title">导入需求</span><span class="step-required">必填</span></div>
159
+ <div class="step-desc">把产品需求放进步骤 3 创建的迭代中。推荐直接用自然语言描述,AI 会帮你整理成标准需求文档:</div>
160
+ <div class="method-grid" style="grid-template-columns:1fr 1fr">
161
+ <div class="method-card m1"><div class="method-title">🤖 自然语言(推荐)</div><div class="step-desc">用口语描述需求 → AI 澄清 → 你确认 → 自动生成标准需求文档,支持反复修改</div><div class="method-cmd" style="margin-top:4px">/spec-ask "新增用户登录功能"</div></div>
162
+ <div class="method-card m2"><div class="method-title">📎 文件导入</div><div class="step-desc">把 Word / PDF / Markdown 文档交给 AI,自动提取需求并转换</div><div class="method-cmd" style="margin-top:4px">/spec-ask "导入 PRD.docx 到 my-iter"</div></div>
163
+ </div>
164
+ <div class="step-desc" style="color:var(--muted);margin-top:4px">还有更多方式:📂 把文件丢到 .speccore/inbox/ 目录自动识别 | ✍️ 直接编辑迭代下 010-requirements/ 目录</div>
165
+ <div class="step-desc" style="color:var(--green)">💡 导入后,下一步 AI 分析会自动读取这些需求文档,生成 ANALYSIS.md、TECH.md 等 7 份技术规格。</div>
166
+ </div>
167
+
168
+ <div class="step">
169
+ <div class="step-header"><span class="step-num">5</span><span class="step-title">知识库与规则</span><span class="step-optional">按需补充</span></div>
170
+ <div class="step-desc">以下内容按需补充,AI 在工作时会读取作为参考:</div>
171
+ <div class="kb-grid">
172
+ <div class="kb-card"><div class="kb-icon">📐</div><div class="kb-name">PATTERNS/</div><div class="kb-desc">代码模式模板<br>定义组件/服务/中间件的标准写法</div></div>
173
+ <div class="kb-card"><div class="kb-icon">📏</div><div class="kb-name">RULES/</div><div class="kb-desc">代码审查规则<br>定义 Code Review 的检查项</div></div>
174
+ <div class="kb-card"><div class="kb-icon">🗺️</div><div class="kb-name">PROJECT/</div><div class="kb-desc">项目全景文档<br>架构/团队/依赖关系</div></div>
175
+ <div class="kb-card"><div class="kb-icon">📄</div><div class="kb-name">templates/</div><div class="kb-desc">用户自定义文档模板<br>覆盖或扩展 analyze 生成的规格风格</div></div>
176
+ </div>
177
+ </div>
178
+
179
+ <div class="step">
180
+ <div class="step-header"><span class="step-num">6</span><span class="step-title">开始开发</span></div>
181
+ <div class="step-desc">一切就绪,按以下流程推进开发:</div>
182
+ <div class="flow-bar">
183
+ <span class="flow-node n2">需求分析</span><span class="flow-arrow">→</span>
184
+ <span class="flow-node n3">任务拆分</span><span class="flow-arrow">→</span>
185
+ <span class="flow-node n2">执行开发</span><span class="flow-arrow">→</span>
186
+ <span class="flow-node n1">验证交付</span><span class="flow-arrow">→</span>
187
+ <span class="flow-node n2">质量验证</span>
188
+ </div>
189
+ <div style="margin:12px 0;padding:12px;border-radius:8px;border:1px solid rgba(20,184,166,.2);background:rgba(20,184,166,.04)">
190
+ <div style="font-size:12px;font-weight:700;color:var(--green);margin-bottom:8px">📋 完整示例流程</div>
191
+ <div class="method-cmd" style="margin-bottom:4px"># 1. 创建迭代(终端执行)</div>
192
+ <div class="method-cmd" style="margin-bottom:8px">speccore iteration create -n login --topic "登录功能"</div>
193
+ <div class="method-cmd" style="margin-bottom:4px"># 2. 分析需求(AI 对话框)</div>
194
+ <div class="method-cmd" style="margin-bottom:8px">/spec-ask "分析 login 的需求"</div>
195
+ <div class="method-cmd" style="margin-bottom:4px"># 3. 拆分任务(AI 对话框)</div>
196
+ <div class="method-cmd" style="margin-bottom:8px">/spec-ask "拆分 login 的任务"</div>
197
+ <div class="method-cmd" style="margin-bottom:4px"># 4. 执行开发(AI 对话框)</div>
198
+ <div class="method-cmd" style="margin-bottom:8px">/spec-ask "开发 Task-001"</div>
199
+ <div class="method-cmd" style="margin-bottom:4px"># 5. 质量验证(终端执行)</div>
200
+ <div class="method-cmd" style="margin-bottom:8px">speccore verify -t Task-001 --ui</div>
201
+ <div class="method-cmd" style="margin-bottom:4px"># 6. 提交归档(AI 对话框)</div>
202
+ <div class="method-cmd">/spec-ask "完成 Task-001"</div>
203
+ </div>
204
+ <div class="method-grid" style="grid-template-columns:1fr 1fr;margin-top:12px">
205
+ <div class="method-card m1"><div class="method-title">🤖 方式 A:意图式(推荐)</div><div class="step-desc">用自然语言告诉 AI,每步自动判断:</div><div class="method-cmd" style="margin-top:4px">/spec-ask "分析 my-iter 的需求"</div><div class="method-cmd">/spec-ask "拆分任务"</div><div class="method-cmd">/spec-ask "开发 Task-001"</div><div class="method-cmd">/spec-ask "完成 Task-001"</div></div>
206
+ <div class="method-card m2"><div class="method-title">⌨️ 方式 B:显式命令(也在 AI 对话框中使用)</div><div class="step-desc">命令模板,将 &lt;参数&gt; 替换为你的实际值:</div><div class="method-cmd" style="margin-top:4px">/spec-analyze -I &lt;迭代名&gt;</div><div class="method-cmd">/spec-taskify -i &lt;迭代名&gt;</div><div class="method-cmd">/spec-execute -t &lt;任务名&gt;</div><div class="method-cmd">/spec-done -t &lt;任务名&gt;</div><div style="margin-top:8px;font-size:10px;color:var(--muted)">-I &lt;迭代名&gt; — analyze 用大写 -I,其余用小写 -i<br>-t &lt;任务名&gt; — Task-001 / Task-002 ...<br>--prompt 已内置在 Skill 中,无需手动添加</div></div>
207
+ </div>
208
+ <div class="step-desc" style="color:var(--cyan)">💡 两种方式都在 AI 对话框中使用,可以混用。例如先用意图式分析,再用显式命令执行特定任务。</div>
209
+ </div>
210
+
211
+ <div style="margin:16px 0 8px;font-size:13px;font-weight:700;color:var(--cyan)">⚡ 自动化模式</div>
212
+ <div style="padding:12px;border-radius:8px;border:1px solid rgba(14,165,233,.15);background:rgba(14,165,233,.04)">
213
+ <div style="font-size:11px;font-weight:700;color:var(--cyan);margin-bottom:8px">🎯 三种执行模式(按需选择)</div>
214
+ <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px">
215
+ <div style="padding:10px;border-radius:6px;border:1px solid rgba(20,184,166,.2);background:rgba(20,184,166,.04)">
216
+ <div style="font-size:10px;font-weight:700;color:var(--green);margin-bottom:4px">🔒 全程确认</div>
217
+ <div class="step-desc" style="font-size:9px">每步展示结果,等你确认后再继续。适合首次使用。</div>
218
+ <div class="method-cmd" style="font-size:9px">/spec-ask "分析 my-iter 的需求"</div>
219
+ </div>
220
+ <div style="padding:10px;border-radius:6px;border:1px solid rgba(249,115,22,.2);background:rgba(249,115,22,.04)">
221
+ <div style="font-size:10px;font-weight:700;color:var(--orange);margin-bottom:4px">⚡ 半自动</div>
222
+ <div class="step-desc" style="font-size:9px">分析和拆分自动完成,执行开发前暂停。适合日常开发。</div>
223
+ <div class="method-cmd" style="font-size:9px">/spec-ask "分析 my-iter 并拆分任务"</div>
224
+ </div>
225
+ <div style="padding:10px;border-radius:6px;border:1px solid rgba(99,102,241,.2);background:rgba(99,102,241,.04)">
226
+ <div style="font-size:10px;font-weight:700;color:var(--purple);margin-bottom:4px">🚀 全自动</div>
227
+ <div class="step-desc" style="font-size:9px">一键跑完整个流水线,不中途暂停。适合熟悉后批量推进。</div>
228
+ <div class="method-cmd" style="font-size:9px">/spec-ask "全自动推进 my-iter"</div>
229
+ </div>
230
+ </div>
231
+ <div class="step-desc" style="margin-top:8px;font-size:10px">💡 <code>speccore run</code> 是流水线入口:无参即智能续跑(检测断点从第一个未完成阶段继续),也可按预设流水线或起止点自动执行。快捷语法糖(v8.3.290+):<code>speccore run develop</code>(preset 直呼)、<code>speccore run smoke</code>(单阶段快捷)、<code>speccore run split to execute</code>(阶段范围)——高频操作不必依赖 ask 引擎。</div>
232
+ </div>
233
+
234
+ <div style="margin:16px 0 8px;font-size:13px;font-weight:700;color:var(--cyan)">📚 提示词库(快速上手)</div>
235
+ <div style="padding:12px;border-radius:8px;border:1px solid rgba(99,102,241,.2);background:rgba(99,102,241,.04)">
236
+ <div class="step-desc">内置常用操作模板,按场景分类(核心流程/迭代管理/分析文档/开发执行),复制即用:</div>
237
+ <div class="method-cmd" style="margin-bottom:8px">speccore prompts</div>
238
+ <div style="font-size:10px;color:var(--muted);margin-top:4px">打开提示词库页面,浏览预设模板,点击复制自动带上 /spec-ask 前缀</div>
239
+ <div style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap">
240
+ <span style="padding:4px 8px;border-radius:4px;background:rgba(14,165,233,.1);color:var(--cyan);font-size:9px">🔍 分析需求</span>
241
+ <span style="padding:4px 8px;border-radius:4px;background:rgba(249,115,22,.1);color:var(--orange);font-size:9px">🧩 拆分任务</span>
242
+ <span style="padding:4px 8px;border-radius:4px;background:rgba(20,184,166,.1);color:var(--green);font-size:9px">▶️ 执行任务</span>
243
+ <span style="padding:4px 8px;border-radius:4px;background:rgba(99,102,241,.1);color:var(--purple);font-size:9px">📊 查看进度</span>
244
+ </div>
245
+ </div>
246
+
247
+ <div style="margin:16px 0 8px;font-size:13px;font-weight:700;color:var(--cyan)">📖 重新查看本指南</div>
248
+ <div class="step-desc">本指南保存在 <code>outputs/speccore-setup-guide.html</code>,随时可在浏览器中打开查看。<br>也可以让 AI 重新展示:/spec-ask "打开配置引导"</div>
249
+
250
+ <div class="faq-section">
251
+ <div class="faq-title">❓ 常见问题</div>
252
+ <div class="faq-item">
253
+ <div class="faq-q">Q: 我怎么知道 CONSTITUTION.md 填对了?</div>
254
+ <div class="faq-a">A: 不用完美!init 已自动填写工程名和 Git 仓库。技术栈可以用 AI 扫描:<code>/spec-ask "分析代码,完善技术宪法"</code>。必填项只有技术栈(后端/前端/数据库),其他按需补充。</div>
255
+ </div>
256
+ <div class="faq-item">
257
+ <div class="faq-q">Q: 团队排期不填会怎样?</div>
258
+ <div class="faq-a">A: 不影响使用。AI 会用默认的中粒度拆分(4-8人规模)。后续需要时再编辑 Iteration-xxx/STAFFING.md 即可。</div>
259
+ </div>
260
+ <div class="faq-item">
261
+ <div class="faq-q">Q: 我能改迭代名吗?</div>
262
+ <div class="faq-a">A: 可以。用 <code>speccore rename --iteration 旧名 新名</code> 或在 AI 对话框说 <code>/spec-ask "把迭代 old-name 重命名为 new-name"</code>。</div>
263
+ </div>
264
+ <div class="faq-item">
265
+ <div class="faq-q">Q: 需求文档放哪?</div>
266
+ <div class="faq-a">A: 放到迭代目录下的 <code>010-requirements/</code> 文件夹。或者直接用自然语言描述:<code>/spec-ask "新增用户登录功能"</code>,AI 会自动生成标准需求文档。</div>
267
+ </div>
268
+ </div>
269
+
270
+ <div class="action-grid">
271
+ <a class="action-card primary" href="#" onclick="alert('请在终端执行:\nspeccore iteration create -n xxx --topic \"xxx\"')">
272
+ <div class="action-icon">🚀</div>
273
+ <div class="action-title">创建第一个迭代</div>
274
+ <div class="action-desc">开始你的第一个开发周期</div>
275
+ </a>
276
+ <a class="action-card secondary" href="speccore-prompts.html">
277
+ <div class="action-icon">📚</div>
278
+ <div class="action-title">查看提示词库</div>
279
+ <div class="action-desc">浏览常用操作模板</div>
280
+ </a>
281
+ <a class="action-card secondary" href="speccore-setup-guide.html">
282
+ <div class="action-icon">📖</div>
283
+ <div class="action-title">重新看配置指南</div>
284
+ <div class="action-desc">随时回顾初始化步骤</div>
285
+ </a>
286
+ </div>
287
+
288
+ <div class="footer">SpecCore v{{VERSION}} · 项目配置引导 · {{PROJECT_NAME}}</div>
289
+ </div></body></html>
@@ -0,0 +1,226 @@
1
+ # 安全规范示例
2
+
3
+ > 本文件为 Web 应用安全规范示例,覆盖 OWASP Top 10 常见风险及防御措施。
4
+ > 复制到项目后按需修改,或作为 `.speccore/RULES/security.md` 的素材。
5
+
6
+ ---
7
+
8
+ ## 1. 认证与授权
9
+
10
+ ### 1.1 密码安全
11
+
12
+ | 规则 | 要求 |
13
+ |:---|:---|
14
+ | 最小长度 | 8 位 |
15
+ | 复杂度 | 大小写字母 + 数字 + 特殊字符,至少两种 |
16
+ | 哈希算法 | bcrypt / scrypt / Argon2,禁止 MD5 / SHA1 |
17
+ | 盐值 | 每个密码独立随机盐 |
18
+ | 历史密码 | 禁止复用最近 5 次密码 |
19
+ | 错误提示 | 登录失败时统一提示"用户名或密码错误",不暴露账号是否存在 |
20
+
21
+ ### 1.2 会话管理
22
+
23
+ | 规则 | 要求 |
24
+ |:---|:---|
25
+ | Token 有效期 | Access Token 2 小时,Refresh Token 7 天 |
26
+ | Token 存储 | 禁止 localStorage 存敏感 Token,使用 httpOnly Cookie |
27
+ | 并发登录 | 同一账号最多 3 处同时登录,超限踢掉最早会话 |
28
+ | 异常检测 | 异地登录、短时间内大量失败尝试 → 触发二次验证或锁定账号 |
29
+ | 登出处理 | Token 加入黑名单,立即失效 |
30
+
31
+ ### 1.3 权限控制
32
+
33
+ - **最小权限原则:** 每个角色只给完成工作所需的最小权限
34
+ - **数据权限隔离:** 用户只能访问自己的数据,管理员只能访问本组织数据
35
+ - **敏感操作二次确认:** 删除账号、修改密码、转账等操作需再次验证身份
36
+ - **API 鉴权全覆盖:** 每个接口必须有鉴权注解/装饰器,禁止默认公开
37
+
38
+ ---
39
+
40
+ ## 2. 输入校验
41
+
42
+ ### 2.1 通用规则
43
+
44
+ - **服务端必须校验:** 前端校验只是体验优化,服务端校验才是安全防线
45
+ - **白名单优先:** 明确允许什么,而不是禁止什么
46
+ - **参数化查询:** 所有数据库操作必须使用预编译语句,禁止字符串拼接 SQL
47
+
48
+ ### 2.2 各类型输入校验
49
+
50
+ | 类型 | 校验规则 | 示例 |
51
+ |:---|:---|:---|
52
+ | 手机号 | `^1[3-9]\d{9}$` | 13800138000 |
53
+ | 邮箱 | RFC 5322 简化版,长度 ≤ 128 | user@example.com |
54
+ | 用户名 | 2-20 位,中文/字母/数字/下划线,不以数字开头 | user_123 |
55
+ | 密码 | 8-32 位,至少两种字符类型 | MyP@ssw0rd |
56
+ | URL | 协议限定 http/https,禁止 file/javascript | https://example.com |
57
+ | 整数 | 明确范围,防止溢出 | 1 ~ 999999 |
58
+ | 文件路径 | 禁止 `../` `..\` 路径遍历 | — |
59
+ | HTML 内容 | 富文本必须白名单过滤标签 | 只允许 `<p>` `<b>` `<i>` 等安全标签 |
60
+
61
+ ### 2.3 文件上传安全
62
+
63
+ - **白名单校验后缀:** 只允许 `.jpg` `.png` `.pdf` 等预期格式
64
+ - **MIME 类型校验:** 不能仅靠后缀,需读取文件头验证真实类型
65
+ - **大小限制:** 单文件最大 50MB,超出拒绝
66
+ - **病毒扫描:** 文件上传后先扫描再落盘
67
+ - **存储隔离:** 上传文件存储在非 Web 目录,通过接口代理访问
68
+ - **重命名存储:** 使用随机文件名 + 原始文件名映射,防止覆盖攻击
69
+
70
+ ---
71
+
72
+ ## 3. 输出编码
73
+
74
+ ### 3.1 XSS 防御
75
+
76
+ | 场景 | 防御方式 |
77
+ |:---|:---|
78
+ | 反射型 XSS | 所有 URL 参数输出到页面时 HTML 编码 |
79
+ | 存储型 XSS | 入库前过滤/编码,出库时再次编码 |
80
+ | DOM 型 XSS | 禁止 `innerHTML` / `document.write`,使用 `textContent` |
81
+ | 富文本 | 使用 DOMPurify 等库白名单过滤标签 |
82
+
83
+ **编码规则:**
84
+ ```
85
+ < → &lt;
86
+ > → &gt;
87
+ " → &quot;
88
+ ' → &#x27;
89
+ & → &amp;
90
+ ```
91
+
92
+ ### 3.2 JSONP / CORS
93
+
94
+ - **禁止 JSONP:** 使用 CORS 代替,防止回调劫持
95
+ - **CORS 白名单:** `Access-Control-Allow-Origin` 必须指定具体域名,禁止 `*`
96
+ - **Credentials 限制:** 携带 Cookie 的请求必须同时校验 Origin
97
+
98
+ ---
99
+
100
+ ## 4. 敏感数据处理
101
+
102
+ ### 4.1 传输加密
103
+
104
+ - **全站 HTTPS:** 禁止 HTTP 访问,HSTS 头 `max-age` ≥ 31536000
105
+ - **敏感接口额外加密:** 支付、身份证等字段使用 AES-256-GCM 加密传输
106
+ - **证书管理:** 使用 Let's Encrypt 自动续期,到期前 30 天告警
107
+
108
+ ### 4.2 存储加密
109
+
110
+ | 数据类型 | 加密方式 | 说明 |
111
+ |:---|:---|:---|
112
+ | 密码 | bcrypt (cost=12) | 不可逆哈希 |
113
+ | 身份证号 | AES-256-GCM | 对称加密,密钥存 KMS |
114
+ | 银行卡号 | AES-256-GCM + 脱敏展示 | 展示时只显示后 4 位 |
115
+ | 手机号 | 脱敏存储 | 138****8000 |
116
+ | Token | HMAC-SHA256 签名 | 防止篡改 |
117
+
118
+ ### 4.3 日志脱敏
119
+
120
+ **禁止打印:**
121
+ - 密码、Token、Session ID
122
+ - 身份证号、银行卡号
123
+ - 手机号(可脱敏后打印)
124
+ - 加密密钥
125
+
126
+ **日志示例:**
127
+ ```
128
+ # ❌ 错误
129
+ [ERROR] 用户登录失败,密码=123456,手机号=13800138000
130
+
131
+ # ✅ 正确
132
+ [INFO] 用户登录失败,userId=10086,reason=密码错误
133
+ ```
134
+
135
+ ---
136
+
137
+ ## 5. 常见攻击防御
138
+
139
+ ### 5.1 SQL 注入
140
+
141
+ **防御:**
142
+ - 全部使用预编译语句 / ORM 参数化查询
143
+ - 禁止字符串拼接 SQL
144
+ - 数据库账号最小权限(禁止 DROP/GRANT)
145
+
146
+ **危险代码:**
147
+ ```java
148
+ // ❌ 错误
149
+ String sql = "SELECT * FROM users WHERE name = '" + name + "'";
150
+
151
+ // ✅ 正确
152
+ String sql = "SELECT * FROM users WHERE name = ?";
153
+ PreparedStatement ps = conn.prepareStatement(sql);
154
+ ps.setString(1, name);
155
+ ```
156
+
157
+ ### 5.2 CSRF
158
+
159
+ **防御:**
160
+ - 使用 `SameSite=Strict` Cookie
161
+ - 敏感操作加 CSRF Token 校验
162
+ - 校验 `Origin` / `Referer` 头
163
+
164
+ ### 5.3 SSRF
165
+
166
+ **防御:**
167
+ - 禁止服务端请求用户传入的 URL
168
+ - 如需请求,校验目标 IP 不在内网段(10.x.x.x, 172.16-31.x.x, 192.168.x.x)
169
+ - 使用白名单限制可访问的外部域名
170
+
171
+ ### 5.4 越权访问
172
+
173
+ **防御:**
174
+ - 每个数据操作前校验当前用户是否有权访问该数据
175
+ - 禁止通过修改 URL 参数访问他人数据(如 `/orders/{id}` 必须校验订单归属)
176
+ - 管理员接口单独路由前缀 `/admin/`,加额外鉴权层
177
+
178
+ ### 5.5 重放攻击
179
+
180
+ **防御:**
181
+ - 接口加时间戳校验(请求时间 ±5 分钟内有效)
182
+ - 敏感接口加 Nonce(一次性随机数)
183
+ - 支付类接口必须幂等
184
+
185
+ ---
186
+
187
+ ## 6. 安全 Headers
188
+
189
+ ```
190
+ Strict-Transport-Security: max-age=31536000; includeSubDomains
191
+ Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
192
+ X-Content-Type-Options: nosniff
193
+ X-Frame-Options: DENY
194
+ X-XSS-Protection: 1; mode=block
195
+ Referrer-Policy: strict-origin-when-cross-origin
196
+ Permissions-Policy: geolocation=(), microphone=(), camera=()
197
+ ```
198
+
199
+ ---
200
+
201
+ ## 7. 安全开发清单
202
+
203
+ ### 7.1 代码提交前
204
+
205
+ - [ ] 密码/密钥未硬编码在代码中
206
+ - [ ] 无 `console.log` 打印敏感信息
207
+ - [ ] SQL 全部使用参数化查询
208
+ - [ ] 用户输入全部校验后再使用
209
+ - [ ] 文件上传有类型/大小限制
210
+
211
+ ### 7.2 上线前
212
+
213
+ - [ ] HTTPS 已配置,HTTP 自动跳转
214
+ - [ ] 安全 Headers 已全部添加
215
+ - [ ] 敏感接口有速率限制
216
+ - [ ] 日志已脱敏处理
217
+ - [ ] 数据库账号权限最小化
218
+ - [ ] 第三方依赖无已知高危漏洞(`npm audit` / `snyk` 扫描)
219
+ - [ ] 渗透测试通过(或至少自查 OWASP Top 10)
220
+
221
+ ### 7.3 运行期
222
+
223
+ - [ ] 异常登录告警(异地、短时间大量失败)
224
+ - [ ] 敏感操作审计日志(谁在什么时间做了什么)
225
+ - [ ] 定期轮换密钥(Token 签名密钥、数据库加密密钥)
226
+ - [ ] 安全漏洞响应流程(发现漏洞后 24 小时内修复)