Coverage for src / moai_adk / project / documentation.py: 30.48%

105 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-11-20 20:52 +0900

1""" 

2Documentation generation for SPEC-REDESIGN-001 

3 

4Generates: 

5- product.md: Project vision and value proposition 

6- structure.md: System architecture and components 

7- tech.md: Technology stack and trade-offs 

8""" 

9 

10from copy import deepcopy 

11from pathlib import Path 

12from typing import Any, Dict, List, Optional 

13 

14 

15class DocumentationGenerator: 

16 """Generates project documentation from brainstorm responses. 

17 

18 Produces three complementary markdown documents for agent context: 

19 - product.md: Project vision, users, value, roadmap 

20 - structure.md: System architecture and components 

21 - tech.md: Technology stack, trade-offs, performance, security 

22 

23 Used by project-manager, tdd-implementer, and domain expert agents. 

24 

25 Example: 

26 >>> generator = DocumentationGenerator() 

27 >>> responses = {'project_vision': 'Build fast API', ...} 

28 >>> docs = generator.generate_all_documents(responses) 

29 >>> generator.save_all_documents(docs) 

30 """ 

31 

32 def __init__(self): 

33 """Initialize with built-in documentation templates.""" 

34 self.templates = self._load_templates() 

35 

36 @staticmethod 

37 def _load_templates() -> Dict[str, str]: 

38 """Load documentation templates. 

39 

40 Returns: 

41 Dictionary with 'product', 'structure', 'tech' template strings. 

42 """ 

43 return { 

44 'product': '''# Project Vision 

45 

46## Vision Statement 

47{vision} 

48 

49## Target Users 

50{target_users} 

51 

52## Value Proposition 

53{value_proposition} 

54 

55## Roadmap 

56{roadmap} 

57 

58## AI Analysis Insights 

59{ai_insights} 

60 

61**Generated**: This document was auto-generated based on project analysis. 

62''', 

63 'structure': '''# System Architecture 

64 

65## Architecture Overview 

66{system_architecture} 

67 

68## Core Components 

69{core_components} 

70 

71## Component Relationships 

72{relationships} 

73 

74## Dependencies 

75{dependencies} 

76 

77**Design Notes**: This architecture document provides reference for implementation teams. 

78''', 

79 'tech': '''# Technology Stack 

80 

81## Technology Selection 

82{technology_selection} 

83 

84## Trade-off Analysis 

85{trade_offs} 

86 

87## Performance Considerations 

88{performance} 

89 

90## Security Considerations 

91{security} 

92 

93## Setup Guide 

94{setup_guide} 

95 

96**Version**: Technology stack selection guide, subject to updates. 

97''', 

98 } 

99 

100 def generate_product_md(self, responses: Dict[str, Any]) -> str: 

101 """Generate product.md from brainstorm responses. 

102 

103 Creates marketing and strategic documentation from brainstorm responses. 

104 Includes vision statement, target users, value proposition, and roadmap. 

105 

106 Args: 

107 responses: Brainstorm response dictionary with keys: 

108 - project_vision: High-level project vision 

109 - target_users: Description of target user segment 

110 - value_proposition: Unique value provided 

111 - roadmap: Development roadmap 

112 

113 Returns: 

114 Formatted markdown content for product.md 

115 

116 Example: 

117 >>> responses = { 

118 ... 'project_vision': 'Fast API framework', 

119 ... 'target_users': 'Python developers', 

120 ... 'value_proposition': 'Speed and simplicity', 

121 ... 'roadmap': 'v1.0 in Q1 2025', 

122 ... } 

123 >>> gen = DocumentationGenerator() 

124 >>> content = gen.generate_product_md(responses) 

125 >>> 'Vision' in content 

126 True 

127 """ 

128 template = self.templates['product'] 

129 

130 content = template.format( 

131 vision=responses.get('project_vision', ''), 

132 target_users=responses.get('target_users', ''), 

133 value_proposition=responses.get('value_proposition', ''), 

134 roadmap=responses.get('roadmap', ''), 

135 ai_insights=self._generate_ai_insights(responses), 

136 ) 

137 

138 return content.strip() 

139 

140 def generate_structure_md(self, responses: Dict[str, Any]) -> str: 

141 """Generate structure.md from brainstorm responses. 

142 

143 Creates architecture documentation for system design. 

144 Includes architecture overview, components, relationships, dependencies. 

145 

146 Args: 

147 responses: Brainstorm response dictionary with keys: 

148 - system_architecture: Architecture overview 

149 - core_components: List/description of core components 

150 - relationships: How components interact 

151 - dependencies: External dependencies 

152 

153 Returns: 

154 Formatted markdown content for structure.md 

155 

156 Example: 

157 >>> responses = { 

158 ... 'system_architecture': 'Microservices', 

159 ... 'core_components': 'API, Database, Cache', 

160 ... 'relationships': 'API calls Database', 

161 ... 'dependencies': 'PostgreSQL, Redis', 

162 ... } 

163 >>> gen = DocumentationGenerator() 

164 >>> content = gen.generate_structure_md(responses) 

165 >>> 'Architecture' in content.lower() 

166 True 

167 """ 

168 template = self.templates['structure'] 

169 

170 content = template.format( 

171 system_architecture=responses.get('system_architecture', ''), 

172 core_components=responses.get('core_components', ''), 

173 relationships=responses.get('relationships', ''), 

174 dependencies=responses.get('dependencies', ''), 

175 ) 

176 

177 return content.strip() 

178 

179 def generate_tech_md(self, responses: Dict[str, Any]) -> str: 

180 """Generate tech.md from brainstorm responses. 

181 

182 Creates technical documentation for technology decisions. 

183 Includes tech stack, trade-offs, performance, security, setup. 

184 

185 Args: 

186 responses: Brainstorm response dictionary with keys: 

187 - technology_selection: Technologies chosen 

188 - trade_offs: Trade-offs made in tech selection 

189 - performance: Performance requirements 

190 - security: Security considerations 

191 - setup_guide: How to set up the tech stack 

192 

193 Returns: 

194 Formatted markdown content for tech.md 

195 

196 Example: 

197 >>> responses = { 

198 ... 'technology_selection': 'Python, FastAPI, PostgreSQL', 

199 ... 'trade_offs': 'FastAPI over Django for performance', 

200 ... 'performance': 'Sub-100ms latency', 

201 ... 'security': 'OAuth2, TLS', 

202 ... 'setup_guide': 'pip install -r requirements.txt', 

203 ... } 

204 >>> gen = DocumentationGenerator() 

205 >>> content = gen.generate_tech_md(responses) 

206 >>> 'Technology' in content 

207 True 

208 """ 

209 template = self.templates['tech'] 

210 

211 content = template.format( 

212 technology_selection=responses.get('technology_selection', ''), 

213 trade_offs=responses.get('trade_offs', ''), 

214 performance=responses.get('performance', ''), 

215 security=responses.get('security', ''), 

216 setup_guide=responses.get('setup_guide', ''), 

217 ) 

218 

219 return content.strip() 

220 

221 def generate_all_documents( 

222 self, 

223 brainstorm_responses: Dict[str, Any], 

224 ) -> Dict[str, str]: 

225 """Generate all three documents from brainstorm responses. 

226 

227 Produces complete documentation set: product, structure, tech. 

228 

229 Args: 

230 brainstorm_responses: Brainstorm responses with keys for 

231 product, structure, and tech generation 

232 

233 Returns: 

234 Dictionary with 'product', 'structure', 'tech' keys and 

235 markdown content as values. 

236 

237 Example: 

238 >>> gen = DocumentationGenerator() 

239 >>> responses = {...} 

240 >>> docs = gen.generate_all_documents(responses) 

241 >>> len(docs) 

242 3 

243 """ 

244 return { 

245 'product': self.generate_product_md(brainstorm_responses), 

246 'structure': self.generate_structure_md(brainstorm_responses), 

247 'tech': self.generate_tech_md(brainstorm_responses), 

248 } 

249 

250 @staticmethod 

251 def _generate_ai_insights(responses: Dict[str, Any]) -> str: 

252 """Generate AI analysis insights from responses. 

253 

254 Analyzes brainstorm responses and generates insights about 

255 completeness and quality. 

256 

257 Args: 

258 responses: Brainstorm response dictionary 

259 

260 Returns: 

261 Formatted insights text with bullet points or status message. 

262 """ 

263 # In real implementation, would call AI analysis 

264 insights = [] 

265 

266 if 'project_vision' in responses: 

267 insights.append('- Vision is clear and actionable') 

268 

269 if 'target_users' in responses: 

270 insights.append('- Target user segment identified') 

271 

272 if 'value_proposition' in responses: 

273 insights.append('- Value proposition articulated') 

274 

275 return '\n'.join(insights) if insights else 'AI analysis pending' 

276 

277 def save_all_documents( 

278 self, 

279 documents: Dict[str, str], 

280 base_path: Path = Path('.moai/project'), 

281 ) -> None: 

282 """Save all generated documents to disk. 

283 

284 Writes product.md, structure.md, and tech.md to .moai/project/ 

285 directory. Creates directory if it doesn't exist. 

286 

287 Args: 

288 documents: Dictionary with 'product', 'structure', 'tech' keys 

289 base_path: Directory to save documents (default: .moai/project) 

290 

291 Returns: 

292 None 

293 

294 Example: 

295 >>> gen = DocumentationGenerator() 

296 >>> docs = {'product': '...', 'structure': '...', 'tech': '...'} 

297 >>> gen.save_all_documents(docs) 

298 >>> (Path('.moai/project') / 'product.md').exists() 

299 True 

300 """ 

301 base_path.mkdir(parents=True, exist_ok=True) 

302 

303 file_mapping = { 

304 'product': 'product.md', 

305 'structure': 'structure.md', 

306 'tech': 'tech.md', 

307 } 

308 

309 for doc_type, filename in file_mapping.items(): 

310 if doc_type in documents: 

311 filepath = base_path / filename 

312 filepath.write_text(documents[doc_type], encoding='utf-8') 

313 

314 def load_document(self, doc_name: str, base_path: Path = Path('.moai/project')) -> Optional[str]: 

315 """Load a generated document from disk. 

316 

317 Reads markdown document content for use by agents. 

318 Returns None if file doesn't exist. 

319 

320 Args: 

321 doc_name: Document filename (e.g., 'product.md', 'structure.md', 'tech.md') 

322 base_path: Directory containing documents (default: .moai/project) 

323 

324 Returns: 

325 Document content as string, or None if file not found. 

326 

327 Example: 

328 >>> gen = DocumentationGenerator() 

329 >>> content = gen.load_document('product.md') 

330 >>> 'Vision' in content if content else False 

331 True 

332 """ 

333 filepath = base_path / doc_name 

334 if filepath.exists(): 

335 return filepath.read_text(encoding='utf-8') 

336 return None 

337 

338 def create_minimal_templates(self, base_path: Path = Path('.moai/project')) -> None: 

339 """Create minimal template files for Quick Start mode""" 

340 base_path.mkdir(parents=True, exist_ok=True) 

341 

342 minimal_templates = { 

343 'product.md': '''# Project Vision 

344 

345## Vision Statement 

346[Add your project vision here] 

347 

348## Target Users 

349[Describe your target users] 

350 

351## Value Proposition 

352[Explain the unique value] 

353 

354## Roadmap 

355[Outline your development roadmap] 

356''', 

357 'structure.md': '''# System Architecture 

358 

359## Architecture Overview 

360[Describe the system architecture] 

361 

362## Core Components 

363[List and describe core components] 

364 

365## Component Relationships 

366[Explain how components interact] 

367 

368## Dependencies 

369[Document external dependencies] 

370''', 

371 'tech.md': '''# Technology Stack 

372 

373## Technology Selection 

374[List selected technologies and frameworks] 

375 

376## Trade-off Analysis 

377[Explain trade-offs made] 

378 

379## Performance Considerations 

380[Document performance requirements] 

381 

382## Security Considerations 

383[Document security measures] 

384 

385## Setup Guide 

386[Provide setup instructions] 

387''', 

388 } 

389 

390 for filename, content in minimal_templates.items(): 

391 filepath = base_path / filename 

392 filepath.write_text(content, encoding='utf-8') 

393 

394 

395class BrainstormQuestionGenerator: 

396 """Generates brainstorm questions for different depths""" 

397 

398 @staticmethod 

399 def get_quick_questions() -> List[Dict[str, str]]: 

400 """Get Quick (5-10 min) brainstorm questions""" 

401 return [ 

402 { 

403 'id': 'q1_vision', 

404 'question': 'What is your project vision in one sentence?', 

405 'category': 'vision', 

406 }, 

407 { 

408 'id': 'q2_users', 

409 'question': 'Who are your target users?', 

410 'category': 'vision', 

411 }, 

412 { 

413 'id': 'q3_architecture', 

414 'question': 'What is the basic system architecture?', 

415 'category': 'architecture', 

416 }, 

417 { 

418 'id': 'q4_tech', 

419 'question': 'What are your key technologies?', 

420 'category': 'tech', 

421 }, 

422 { 

423 'id': 'q5_team', 

424 'question': 'What is your team composition?', 

425 'category': 'team', 

426 }, 

427 ] 

428 

429 @staticmethod 

430 def get_standard_questions() -> List[Dict[str, str]]: 

431 """Get Standard (10-15 min) brainstorm questions""" 

432 quick = BrainstormQuestionGenerator.get_quick_questions() 

433 additional = [ 

434 { 

435 'id': 'q6_tradeoffs_1', 

436 'question': 'What major trade-offs did you make?', 

437 'category': 'tradeoffs', 

438 }, 

439 { 

440 'id': 'q7_tradeoffs_2', 

441 'question': 'What alternatives did you consider?', 

442 'category': 'tradeoffs', 

443 }, 

444 { 

445 'id': 'q8_performance', 

446 'question': 'What are your performance requirements?', 

447 'category': 'performance', 

448 }, 

449 { 

450 'id': 'q9_security', 

451 'question': 'What security considerations are important?', 

452 'category': 'security', 

453 }, 

454 { 

455 'id': 'q10_scalability', 

456 'question': 'How should the system scale?', 

457 'category': 'scalability', 

458 }, 

459 ] 

460 return quick + additional 

461 

462 @staticmethod 

463 def get_deep_questions() -> List[Dict[str, str]]: 

464 """Get Deep (25-30 min) brainstorm questions""" 

465 standard = BrainstormQuestionGenerator.get_standard_questions() 

466 additional = [ 

467 { 

468 'id': 'q11_competitors_1', 

469 'question': 'What competitors exist in this space?', 

470 'category': 'market', 

471 }, 

472 { 

473 'id': 'q12_competitors_2', 

474 'question': 'How do you differentiate from competitors?', 

475 'category': 'market', 

476 }, 

477 { 

478 'id': 'q13_market', 

479 'question': 'What market trends are relevant?', 

480 'category': 'market', 

481 }, 

482 { 

483 'id': 'q14_innovation', 

484 'question': 'What innovative approaches are you using?', 

485 'category': 'innovation', 

486 }, 

487 { 

488 'id': 'q15_costs', 

489 'question': 'What is your cost model?', 

490 'category': 'business', 

491 }, 

492 { 

493 'id': 'q16_best_practices', 

494 'question': 'What best practices are you following?', 

495 'category': 'practices', 

496 }, 

497 ] 

498 return standard + additional 

499 

500 @staticmethod 

501 def get_questions_by_depth(depth: str) -> List[Dict[str, str]]: 

502 """Get questions for specified depth""" 

503 if depth == 'quick': 

504 return BrainstormQuestionGenerator.get_quick_questions() 

505 elif depth == 'standard': 

506 return BrainstormQuestionGenerator.get_standard_questions() 

507 elif depth == 'deep': 

508 return BrainstormQuestionGenerator.get_deep_questions() 

509 else: 

510 return BrainstormQuestionGenerator.get_quick_questions() 

511 

512 

513class AgentContextInjector: 

514 """Injects project documentation into agent context""" 

515 

516 @staticmethod 

517 def inject_project_manager_context( 

518 agent_config: Dict[str, Any], 

519 base_path: Path = Path('.moai/project'), 

520 ) -> Dict[str, Any]: 

521 """Inject product.md into project-manager agent""" 

522 config = deepcopy(agent_config) 

523 

524 doc_path = base_path / 'product.md' 

525 if doc_path.exists(): 

526 content = doc_path.read_text(encoding='utf-8') 

527 if 'system_context' not in config: 

528 config['system_context'] = '' 

529 config['system_context'] += f'\n\n## Project Documentation\n{content}' 

530 

531 return config 

532 

533 @staticmethod 

534 def inject_tdd_implementer_context( 

535 agent_config: Dict[str, Any], 

536 base_path: Path = Path('.moai/project'), 

537 ) -> Dict[str, Any]: 

538 """Inject structure.md into tdd-implementer agent""" 

539 config = deepcopy(agent_config) 

540 

541 doc_path = base_path / 'structure.md' 

542 if doc_path.exists(): 

543 content = doc_path.read_text(encoding='utf-8') 

544 if 'architecture_context' not in config: 

545 config['architecture_context'] = '' 

546 config['architecture_context'] += f'\n\n## Architecture Reference\n{content}' 

547 

548 return config 

549 

550 @staticmethod 

551 def inject_domain_expert_context( 

552 agent_config: Dict[str, Any], 

553 agent_type: str, # 'backend_expert' or 'frontend_expert' 

554 base_path: Path = Path('.moai/project'), 

555 ) -> Dict[str, Any]: 

556 """Inject tech.md into domain expert agents""" 

557 config = deepcopy(agent_config) 

558 

559 doc_path = base_path / 'tech.md' 

560 if doc_path.exists(): 

561 content = doc_path.read_text(encoding='utf-8') 

562 if 'tech_context' not in config: 

563 config['tech_context'] = '' 

564 config['tech_context'] += f'\n\n## Technology Stack Reference\n{content}' 

565 

566 return config