Class: Aidp::Planning::Builders::AgilePlanBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/planning/builders/agile_plan_builder.rb

Overview

Orchestrates agile planning workflows Coordinates MVP scoping, user testing, feedback analysis, and iteration planning

Instance Method Summary collapse

Constructor Details

#initialize(ai_decision_engine:, config: nil, prompt: nil, document_parser: nil, mvp_scope_generator: nil, user_test_plan_generator: nil, marketing_report_generator: nil, feedback_analyzer: nil, iteration_plan_generator: nil, legacy_research_planner: nil, persona_mapper: nil) ⇒ AgilePlanBuilder

Returns a new instance of AgilePlanBuilder.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 20

def initialize(
  ai_decision_engine:,
  config: nil,
  prompt: nil,
  document_parser: nil,
  mvp_scope_generator: nil,
  user_test_plan_generator: nil,
  marketing_report_generator: nil,
  feedback_analyzer: nil,
  iteration_plan_generator: nil,
  legacy_research_planner: nil,
  persona_mapper: nil
)
  @ai_decision_engine = ai_decision_engine
  @config = config || Aidp::Config.agile_config
  @prompt = prompt || TTY::Prompt.new
  @document_parser = document_parser || Parsers::DocumentParser.new(ai_decision_engine: ai_decision_engine)
  @mvp_scope_generator = mvp_scope_generator || Generators::MVPScopeGenerator.new(
    ai_decision_engine: ai_decision_engine,
    prompt: @prompt,
    config: @config
  )
  @user_test_plan_generator = user_test_plan_generator || Generators::UserTestPlanGenerator.new(
    ai_decision_engine: ai_decision_engine,
    config: @config
  )
  @marketing_report_generator = marketing_report_generator || Generators::MarketingReportGenerator.new(
    ai_decision_engine: ai_decision_engine,
    config: @config
  )
  @feedback_analyzer = feedback_analyzer || Analyzers::FeedbackAnalyzer.new(
    ai_decision_engine: ai_decision_engine,
    config: @config
  )
  @iteration_plan_generator = iteration_plan_generator || Generators::IterationPlanGenerator.new(
    ai_decision_engine: ai_decision_engine,
    config: @config
  )
  @legacy_research_planner = legacy_research_planner || Generators::LegacyResearchPlanner.new(
    ai_decision_engine: ai_decision_engine,
    prompt: @prompt,
    config: @config
  )
  @persona_mapper = persona_mapper || Mappers::PersonaMapper.new(
    ai_decision_engine: ai_decision_engine,
    config: @config,
    mode: :agile
  )
end

Instance Method Details

#analyze_feedback(feedback_path:) ⇒ Hash

Analyze feedback data

Parameters:

  • feedback_path (String)

    Path to feedback data file (CSV/JSON/markdown)

Returns:

  • (Hash)

    Feedback analysis results



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 115

def analyze_feedback(feedback_path:)
  Aidp.log_debug("agile_plan_builder", "analyze_feedback", feedback_path: feedback_path)

  # Parse feedback data
  @prompt.say("Parsing feedback data...")
  parser = Parsers::FeedbackDataParser.new(file_path: feedback_path)
  feedback_data = parser.parse

  @prompt.say("Analyzing #{feedback_data[:response_count]} responses...")

  # Analyze with AI
  analysis = @feedback_analyzer.analyze(feedback_data)
  Aidp.log_debug("agile_plan_builder", "feedback_analyzed",
    findings: analysis[:findings].size,
    recommendations: analysis[:recommendations].size)

  @prompt.ok("Feedback analysis complete!")

  {
    analysis: analysis,
    metadata: {
      generated_at: Time.now.iso8601,
      workflow: "agile_feedback_analysis"
    }
  }
end

#build_mvp_plan(prd_path:, user_priorities: nil) ⇒ Hash

Build complete MVP plan from PRD

Parameters:

  • prd_path (String)

    Path to PRD document

  • user_priorities (Array<String>) (defaults to: nil)

    Optional user priorities

Returns:

  • (Hash)

    Complete MVP plan with all artifacts



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 74

def build_mvp_plan(prd_path:, user_priorities: nil)
  Aidp.log_debug("agile_plan_builder", "build_mvp_plan", prd_path: prd_path)

  # Parse PRD
  prd = parse_prd(prd_path)

  # Generate MVP scope
  @prompt.say("Generating MVP scope...")
  mvp_scope = @mvp_scope_generator.generate(prd: prd, user_priorities: user_priorities)
  Aidp.log_debug("agile_plan_builder", "mvp_scope_generated",
    must_have: mvp_scope[:mvp_features].size,
    deferred: mvp_scope[:deferred_features].size)

  # Generate user test plan
  @prompt.say("Creating user testing plan...")
  test_plan = @user_test_plan_generator.generate(mvp_scope: mvp_scope)
  Aidp.log_debug("agile_plan_builder", "test_plan_generated",
    stages: test_plan[:testing_stages].size)

  # Generate marketing report
  @prompt.say("Generating marketing materials...")
  marketing_report = @marketing_report_generator.generate(mvp_scope: mvp_scope)
  Aidp.log_debug("agile_plan_builder", "marketing_report_generated",
    messages: marketing_report[:key_messages].size)

  @prompt.ok("MVP plan complete!")

  {
    mvp_scope: mvp_scope,
    test_plan: test_plan,
    marketing_report: marketing_report,
    metadata: {
      generated_at: Time.now.iso8601,
      workflow: "agile_mvp"
    }
  }
end

#plan_legacy_research(codebase_path:, language: nil, known_users: nil) ⇒ Hash

Plan user research for existing/legacy codebase

Parameters:

  • codebase_path (String)

    Path to codebase directory

  • language (String) (defaults to: nil)

    Optional primary language

  • known_users (String) (defaults to: nil)

    Optional known user segments

Returns:

  • (Hash)

    Research plan



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 188

def plan_legacy_research(codebase_path:, language: nil, known_users: nil)
  Aidp.log_debug("agile_plan_builder", "plan_legacy_research",
    codebase_path: codebase_path)

  @prompt.say("Analyzing codebase...")
  research_plan = @legacy_research_planner.generate(
    codebase_path: codebase_path,
    language: language,
    known_users: known_users
  )
  Aidp.log_debug("agile_plan_builder", "research_plan_generated",
    features: research_plan[:current_features].size,
    questions: research_plan[:research_questions].size)

  # Generate user test plan based on research priorities
  @prompt.say("Creating user testing plan...")
  # Create a minimal MVP scope structure for test plan generation
  mvp_scope_for_testing = {
    mvp_features: research_plan[:current_features],
    metadata: {
      user_priorities: ["Understand existing user experience", "Identify pain points", "Discover improvement opportunities"]
    }
  }
  test_plan = @user_test_plan_generator.generate(mvp_scope: mvp_scope_for_testing)

  @prompt.ok("Legacy research plan complete!")

  {
    research_plan: research_plan,
    test_plan: test_plan,
    metadata: {
      generated_at: Time.now.iso8601,
      workflow: "agile_legacy_research"
    }
  }
end

#plan_next_iteration(feedback_analysis_path:, current_mvp_path: nil) ⇒ Hash

Plan next iteration based on feedback

Parameters:

  • feedback_analysis_path (String)

    Path to feedback analysis document

  • current_mvp_path (String) (defaults to: nil)

    Optional path to current MVP scope

Returns:

  • (Hash)

    Iteration plan



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 146

def plan_next_iteration(feedback_analysis_path:, current_mvp_path: nil)
  Aidp.log_debug("agile_plan_builder", "plan_next_iteration",
    feedback_path: feedback_analysis_path,
    mvp_path: current_mvp_path)

  # Parse feedback analysis
  @prompt.say("Loading feedback analysis...")
  feedback_analysis = parse_feedback_analysis(feedback_analysis_path)

  # Parse current MVP if provided
  current_mvp = nil
  if current_mvp_path
    @prompt.say("Loading current MVP scope...")
    current_mvp = parse_mvp_scope(current_mvp_path)
  end

  # Generate iteration plan
  @prompt.say("Planning next iteration...")
  iteration_plan = @iteration_plan_generator.generate(
    feedback_analysis: feedback_analysis,
    current_mvp: current_mvp
  )
  Aidp.log_debug("agile_plan_builder", "iteration_plan_generated",
    improvements: iteration_plan[:improvements].size,
    tasks: iteration_plan[:tasks].size)

  @prompt.ok("Iteration plan complete!")

  {
    iteration_plan: iteration_plan,
    metadata: {
      generated_at: Time.now.iso8601,
      workflow: "agile_iteration"
    }
  }
end

#write_artifacts(plan_data, output_dir: ".aidp/docs") ⇒ Object

Write all artifacts to files

Parameters:

  • plan_data (Hash)

    Plan data from any workflow

  • output_dir (String) (defaults to: ".aidp/docs")

    Directory to write files



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/aidp/planning/builders/agile_plan_builder.rb', line 228

def write_artifacts(plan_data, output_dir: ".aidp/docs")
  Aidp.log_debug("agile_plan_builder", "write_artifacts", output_dir: output_dir)

  FileUtils.mkdir_p(output_dir)

  artifacts_written = []

  # Write MVP scope if present
  if plan_data[:mvp_scope]
    path = File.join(output_dir, "MVP_SCOPE.md")
    content = @mvp_scope_generator.format_as_markdown(plan_data[:mvp_scope])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "MVP_SCOPE.md")
  end

  # Write test plan if present
  if plan_data[:test_plan]
    path = File.join(output_dir, "USER_TEST_PLAN.md")
    content = @user_test_plan_generator.format_as_markdown(plan_data[:test_plan])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "USER_TEST_PLAN.md")
  end

  # Write marketing report if present
  if plan_data[:marketing_report]
    path = File.join(output_dir, "MARKETING_REPORT.md")
    content = @marketing_report_generator.format_as_markdown(plan_data[:marketing_report])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "MARKETING_REPORT.md")
  end

  # Write feedback analysis if present
  if plan_data[:analysis]
    path = File.join(output_dir, "USER_FEEDBACK_ANALYSIS.md")
    content = @feedback_analyzer.format_as_markdown(plan_data[:analysis])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "USER_FEEDBACK_ANALYSIS.md")
  end

  # Write iteration plan if present
  if plan_data[:iteration_plan]
    path = File.join(output_dir, "NEXT_ITERATION_PLAN.md")
    content = @iteration_plan_generator.format_as_markdown(plan_data[:iteration_plan])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "NEXT_ITERATION_PLAN.md")
  end

  # Write research plan if present
  if plan_data[:research_plan]
    path = File.join(output_dir, "LEGACY_USER_RESEARCH_PLAN.md")
    content = @legacy_research_planner.format_as_markdown(plan_data[:research_plan])
    File.write(path, content)
    artifacts_written << path
    Aidp.log_debug("agile_plan_builder", "wrote_artifact", file: "LEGACY_USER_RESEARCH_PLAN.md")
  end

  @prompt.ok("Wrote #{artifacts_written.size} artifacts to #{output_dir}")
  artifacts_written
end