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
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-20 20:52 +0900
1"""
2Documentation generation for SPEC-REDESIGN-001
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"""
10from copy import deepcopy
11from pathlib import Path
12from typing import Any, Dict, List, Optional
15class DocumentationGenerator:
16 """Generates project documentation from brainstorm responses.
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
23 Used by project-manager, tdd-implementer, and domain expert agents.
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 """
32 def __init__(self):
33 """Initialize with built-in documentation templates."""
34 self.templates = self._load_templates()
36 @staticmethod
37 def _load_templates() -> Dict[str, str]:
38 """Load documentation templates.
40 Returns:
41 Dictionary with 'product', 'structure', 'tech' template strings.
42 """
43 return {
44 'product': '''# Project Vision
46## Vision Statement
47{vision}
49## Target Users
50{target_users}
52## Value Proposition
53{value_proposition}
55## Roadmap
56{roadmap}
58## AI Analysis Insights
59{ai_insights}
61**Generated**: This document was auto-generated based on project analysis.
62''',
63 'structure': '''# System Architecture
65## Architecture Overview
66{system_architecture}
68## Core Components
69{core_components}
71## Component Relationships
72{relationships}
74## Dependencies
75{dependencies}
77**Design Notes**: This architecture document provides reference for implementation teams.
78''',
79 'tech': '''# Technology Stack
81## Technology Selection
82{technology_selection}
84## Trade-off Analysis
85{trade_offs}
87## Performance Considerations
88{performance}
90## Security Considerations
91{security}
93## Setup Guide
94{setup_guide}
96**Version**: Technology stack selection guide, subject to updates.
97''',
98 }
100 def generate_product_md(self, responses: Dict[str, Any]) -> str:
101 """Generate product.md from brainstorm responses.
103 Creates marketing and strategic documentation from brainstorm responses.
104 Includes vision statement, target users, value proposition, and roadmap.
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
113 Returns:
114 Formatted markdown content for product.md
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']
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 )
138 return content.strip()
140 def generate_structure_md(self, responses: Dict[str, Any]) -> str:
141 """Generate structure.md from brainstorm responses.
143 Creates architecture documentation for system design.
144 Includes architecture overview, components, relationships, dependencies.
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
153 Returns:
154 Formatted markdown content for structure.md
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']
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 )
177 return content.strip()
179 def generate_tech_md(self, responses: Dict[str, Any]) -> str:
180 """Generate tech.md from brainstorm responses.
182 Creates technical documentation for technology decisions.
183 Includes tech stack, trade-offs, performance, security, setup.
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
193 Returns:
194 Formatted markdown content for tech.md
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']
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 )
219 return content.strip()
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.
227 Produces complete documentation set: product, structure, tech.
229 Args:
230 brainstorm_responses: Brainstorm responses with keys for
231 product, structure, and tech generation
233 Returns:
234 Dictionary with 'product', 'structure', 'tech' keys and
235 markdown content as values.
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 }
250 @staticmethod
251 def _generate_ai_insights(responses: Dict[str, Any]) -> str:
252 """Generate AI analysis insights from responses.
254 Analyzes brainstorm responses and generates insights about
255 completeness and quality.
257 Args:
258 responses: Brainstorm response dictionary
260 Returns:
261 Formatted insights text with bullet points or status message.
262 """
263 # In real implementation, would call AI analysis
264 insights = []
266 if 'project_vision' in responses:
267 insights.append('- Vision is clear and actionable')
269 if 'target_users' in responses:
270 insights.append('- Target user segment identified')
272 if 'value_proposition' in responses:
273 insights.append('- Value proposition articulated')
275 return '\n'.join(insights) if insights else 'AI analysis pending'
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.
284 Writes product.md, structure.md, and tech.md to .moai/project/
285 directory. Creates directory if it doesn't exist.
287 Args:
288 documents: Dictionary with 'product', 'structure', 'tech' keys
289 base_path: Directory to save documents (default: .moai/project)
291 Returns:
292 None
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)
303 file_mapping = {
304 'product': 'product.md',
305 'structure': 'structure.md',
306 'tech': 'tech.md',
307 }
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')
314 def load_document(self, doc_name: str, base_path: Path = Path('.moai/project')) -> Optional[str]:
315 """Load a generated document from disk.
317 Reads markdown document content for use by agents.
318 Returns None if file doesn't exist.
320 Args:
321 doc_name: Document filename (e.g., 'product.md', 'structure.md', 'tech.md')
322 base_path: Directory containing documents (default: .moai/project)
324 Returns:
325 Document content as string, or None if file not found.
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
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)
342 minimal_templates = {
343 'product.md': '''# Project Vision
345## Vision Statement
346[Add your project vision here]
348## Target Users
349[Describe your target users]
351## Value Proposition
352[Explain the unique value]
354## Roadmap
355[Outline your development roadmap]
356''',
357 'structure.md': '''# System Architecture
359## Architecture Overview
360[Describe the system architecture]
362## Core Components
363[List and describe core components]
365## Component Relationships
366[Explain how components interact]
368## Dependencies
369[Document external dependencies]
370''',
371 'tech.md': '''# Technology Stack
373## Technology Selection
374[List selected technologies and frameworks]
376## Trade-off Analysis
377[Explain trade-offs made]
379## Performance Considerations
380[Document performance requirements]
382## Security Considerations
383[Document security measures]
385## Setup Guide
386[Provide setup instructions]
387''',
388 }
390 for filename, content in minimal_templates.items():
391 filepath = base_path / filename
392 filepath.write_text(content, encoding='utf-8')
395class BrainstormQuestionGenerator:
396 """Generates brainstorm questions for different depths"""
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 ]
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
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
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()
513class AgentContextInjector:
514 """Injects project documentation into agent context"""
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)
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}'
531 return config
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)
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}'
548 return config
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)
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}'
566 return config