claude-agent-framework 1.0.0

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 (111) hide show
  1. package/README.md +128 -0
  2. package/bin/claude-framework +3 -0
  3. package/framework/agents/design-lead.md +240 -0
  4. package/framework/agents/product-owner.md +179 -0
  5. package/framework/agents/tech-lead.md +226 -0
  6. package/framework/commands/ayuda.md +127 -0
  7. package/framework/commands/a/303/261adir.md +98 -0
  8. package/framework/commands/backup.md +397 -0
  9. package/framework/commands/cambiar.md +110 -0
  10. package/framework/commands/cloud.md +457 -0
  11. package/framework/commands/code.md +142 -0
  12. package/framework/commands/debug.md +334 -0
  13. package/framework/commands/deploy.md +383 -0
  14. package/framework/commands/deshacer.md +120 -0
  15. package/framework/commands/estado.md +218 -0
  16. package/framework/commands/explica.md +227 -0
  17. package/framework/commands/feature.md +120 -0
  18. package/framework/commands/git.md +427 -0
  19. package/framework/commands/historial.md +202 -0
  20. package/framework/commands/learn.md +408 -0
  21. package/framework/commands/movil.md +245 -0
  22. package/framework/commands/nuevo.md +118 -0
  23. package/framework/commands/plan.md +134 -0
  24. package/framework/commands/prd.md +113 -0
  25. package/framework/commands/probar.md +148 -0
  26. package/framework/commands/revisar.md +208 -0
  27. package/framework/commands/seeds.md +230 -0
  28. package/framework/commands/seguridad.md +226 -0
  29. package/framework/commands/tasks.md +157 -0
  30. package/framework/skills/architecture/algorithms.md +970 -0
  31. package/framework/skills/architecture/clean-code.md +1080 -0
  32. package/framework/skills/architecture/design-patterns.md +1984 -0
  33. package/framework/skills/architecture/functional-programming.md +972 -0
  34. package/framework/skills/architecture/solid.md +991 -0
  35. package/framework/skills/cloud/cloud-aws.md +848 -0
  36. package/framework/skills/cloud/cloud-azure.md +931 -0
  37. package/framework/skills/cloud/cloud-gcp.md +848 -0
  38. package/framework/skills/cloud/message-queues.md +1229 -0
  39. package/framework/skills/core/accessibility.md +401 -0
  40. package/framework/skills/core/api.md +474 -0
  41. package/framework/skills/core/authentication.md +306 -0
  42. package/framework/skills/core/authorization.md +388 -0
  43. package/framework/skills/core/background-jobs.md +341 -0
  44. package/framework/skills/core/caching.md +473 -0
  45. package/framework/skills/core/code-review.md +341 -0
  46. package/framework/skills/core/controllers.md +290 -0
  47. package/framework/skills/core/cua.md +285 -0
  48. package/framework/skills/core/documentation.md +472 -0
  49. package/framework/skills/core/file-uploads.md +351 -0
  50. package/framework/skills/core/hotwire-native.md +296 -0
  51. package/framework/skills/core/hotwire.md +278 -0
  52. package/framework/skills/core/i18n.md +334 -0
  53. package/framework/skills/core/imports-exports.md +750 -0
  54. package/framework/skills/core/infrastructure.md +337 -0
  55. package/framework/skills/core/models.md +228 -0
  56. package/framework/skills/core/notifications.md +672 -0
  57. package/framework/skills/core/payments.md +581 -0
  58. package/framework/skills/core/performance.md +361 -0
  59. package/framework/skills/core/rails-scaffold.md +131 -0
  60. package/framework/skills/core/search.md +518 -0
  61. package/framework/skills/core/security.md +565 -0
  62. package/framework/skills/core/seeds.md +307 -0
  63. package/framework/skills/core/seo.md +542 -0
  64. package/framework/skills/core/testing.md +393 -0
  65. package/framework/skills/core/views.md +260 -0
  66. package/framework/skills/core/websockets.md +564 -0
  67. package/framework/skills/data/advanced-sql.md +1204 -0
  68. package/framework/skills/data/nosql.md +1141 -0
  69. package/framework/skills/devops/containers-advanced.md +1237 -0
  70. package/framework/skills/devops/debugging.md +834 -0
  71. package/framework/skills/devops/git-workflow.md +752 -0
  72. package/framework/skills/devops/networking.md +932 -0
  73. package/framework/skills/devops/shell-scripting.md +1132 -0
  74. package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
  75. package/framework/sub-agents/cloud-agent.md +677 -0
  76. package/framework/sub-agents/data.md +504 -0
  77. package/framework/sub-agents/debugging-agent.md +554 -0
  78. package/framework/sub-agents/devops.md +483 -0
  79. package/framework/sub-agents/docs.md +176 -0
  80. package/framework/sub-agents/frontend-dev.md +349 -0
  81. package/framework/sub-agents/git-workflow-agent.md +697 -0
  82. package/framework/sub-agents/integrations.md +630 -0
  83. package/framework/sub-agents/native-dev.md +434 -0
  84. package/framework/sub-agents/qa.md +138 -0
  85. package/framework/sub-agents/rails-dev.md +375 -0
  86. package/framework/sub-agents/security.md +526 -0
  87. package/framework/sub-agents/ui.md +437 -0
  88. package/framework/sub-agents/ux.md +284 -0
  89. package/framework/templates/api-spec.md +500 -0
  90. package/framework/templates/component-spec.md +248 -0
  91. package/framework/templates/feature.json +13 -0
  92. package/framework/templates/model-spec.md +318 -0
  93. package/framework/templates/prd-template.md +80 -0
  94. package/framework/templates/task-plan.md +122 -0
  95. package/framework/templates/task-user-story.md +52 -0
  96. package/framework/templates/technical-spec.md +260 -0
  97. package/framework/templates/user-story.md +95 -0
  98. package/package.json +42 -0
  99. package/project-templates/CLAUDE.md +42 -0
  100. package/project-templates/contexts/architecture.md +25 -0
  101. package/project-templates/contexts/conventions.md +46 -0
  102. package/project-templates/contexts/design-system.md +47 -0
  103. package/project-templates/contexts/requirements.md +38 -0
  104. package/project-templates/contexts/stack.md +30 -0
  105. package/project-templates/history/active/models.md +11 -0
  106. package/project-templates/history/changelog.md +15 -0
  107. package/project-templates/workspace/.gitkeep +0 -0
  108. package/src/cli.js +52 -0
  109. package/src/init.js +104 -0
  110. package/src/status.js +75 -0
  111. package/src/update.js +88 -0
@@ -0,0 +1,834 @@
1
+ # Skill: Debugging
2
+
3
+ ## Purpose
4
+
5
+ Técnicas y herramientas de depuración para encontrar y solucionar bugs en aplicaciones Ruby on Rails de forma eficiente.
6
+
7
+ ## Herramientas de Debugging
8
+
9
+ ### Debug Gem (Rails 7+)
10
+
11
+ ```ruby
12
+ # Gemfile (incluido por defecto en Rails 7+)
13
+ group :development, :test do
14
+ gem "debug", platforms: %i[mri mingw x64_mingw]
15
+ end
16
+ ```
17
+
18
+ ```ruby
19
+ # En cualquier parte del código
20
+ def process_order(order)
21
+ debugger # Pausa ejecución aquí
22
+
23
+ total = calculate_total(order)
24
+ # ...
25
+ end
26
+ ```
27
+
28
+ ### Byebug
29
+
30
+ ```ruby
31
+ # Gemfile
32
+ group :development, :test do
33
+ gem "byebug"
34
+ end
35
+ ```
36
+
37
+ ```ruby
38
+ # Uso
39
+ def problematic_method
40
+ byebug # Punto de parada
41
+
42
+ result = complex_calculation
43
+ result
44
+ end
45
+ ```
46
+
47
+ ### Pry
48
+
49
+ ```ruby
50
+ # Gemfile
51
+ group :development, :test do
52
+ gem "pry-rails"
53
+ gem "pry-byebug" # Combina pry con debugging
54
+ end
55
+ ```
56
+
57
+ ```ruby
58
+ # Uso
59
+ def analyze_data(data)
60
+ binding.pry # Abre consola interactiva
61
+
62
+ processed = data.map { |d| transform(d) }
63
+ processed
64
+ end
65
+ ```
66
+
67
+ ### Binding.irb (Sin gems adicionales)
68
+
69
+ ```ruby
70
+ # Disponible en Ruby 2.5+
71
+ def investigate_bug
72
+ binding.irb # Abre IRB en este punto
73
+
74
+ # código a investigar
75
+ end
76
+ ```
77
+
78
+ ## Comandos del Debugger
79
+
80
+ ### Navegación
81
+
82
+ | Comando | Alias | Descripción |
83
+ |---------|-------|-------------|
84
+ | `step` | `s` | Entrar en el método |
85
+ | `next` | `n` | Siguiente línea (sin entrar) |
86
+ | `finish` | `fin` | Salir del método actual |
87
+ | `continue` | `c` | Continuar ejecución |
88
+ | `up` | | Subir en el stack frame |
89
+ | `down` | | Bajar en el stack frame |
90
+
91
+ ### Inspección
92
+
93
+ | Comando | Descripción |
94
+ |---------|-------------|
95
+ | `where` / `bt` | Ver backtrace completo |
96
+ | `list` / `l` | Ver código alrededor |
97
+ | `info locals` | Ver variables locales |
98
+ | `info args` | Ver argumentos del método |
99
+ | `p expression` | Evaluar expresión |
100
+ | `pp object` | Pretty print de objeto |
101
+
102
+ ### Breakpoints
103
+
104
+ ```ruby
105
+ # En debug gem
106
+ break app/models/user.rb:25 # Línea específica
107
+ break User#validate # Método específico
108
+ break if user.admin? # Breakpoint condicional
109
+ delete 1 # Eliminar breakpoint 1
110
+ info breakpoints # Listar breakpoints
111
+
112
+ # En byebug
113
+ break 25 # Línea 25 del archivo actual
114
+ break User#save # Método save de User
115
+ condition 1 user.email.nil? # Condición en breakpoint 1
116
+ ```
117
+
118
+ ### Ejemplo de sesión de debugging
119
+
120
+ ```ruby
121
+ # app/models/order.rb
122
+ class Order < ApplicationRecord
123
+ def calculate_total
124
+ debugger
125
+
126
+ subtotal = line_items.sum(&:total)
127
+ tax = subtotal * tax_rate
128
+ shipping = calculate_shipping
129
+
130
+ subtotal + tax + shipping
131
+ end
132
+ end
133
+
134
+ # En el debugger:
135
+ (rdbg) p subtotal # => 100.0
136
+ (rdbg) p tax_rate # => 0.21
137
+ (rdbg) p tax # => 21.0
138
+ (rdbg) n # Siguiente línea
139
+ (rdbg) p shipping # => nil # Aquí está el bug!
140
+ (rdbg) s # Entrar en calculate_shipping
141
+ (rdbg) where # Ver stack trace
142
+ (rdbg) c # Continuar
143
+ ```
144
+
145
+ ## Rails Console
146
+
147
+ ### Comandos útiles
148
+
149
+ ```ruby
150
+ # Iniciar consola
151
+ rails console
152
+ rails c
153
+
154
+ # Consola en sandbox (rollback al salir)
155
+ rails console --sandbox
156
+
157
+ # Consola en producción (cuidado!)
158
+ RAILS_ENV=production rails console
159
+
160
+ # Recargar código modificado
161
+ reload!
162
+
163
+ # Acceder al último valor retornado
164
+ _
165
+
166
+ # Ver SQL generado
167
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
168
+
169
+ # O para una query específica
170
+ User.where(active: true).to_sql
171
+ ```
172
+
173
+ ### Helper y app
174
+
175
+ ```ruby
176
+ # Acceder a helpers de vistas
177
+ helper.number_to_currency(1234.50)
178
+ helper.time_ago_in_words(3.days.ago)
179
+ helper.link_to("Home", "/")
180
+
181
+ # Hacer requests HTTP
182
+ app.get "/"
183
+ app.response.status # => 200
184
+ app.response.body # HTML
185
+
186
+ app.post "/users", params: { user: { name: "Test" } }
187
+
188
+ # Acceder a rutas
189
+ app.users_path
190
+ app.root_url
191
+ ```
192
+
193
+ ### Inspección de objetos
194
+
195
+ ```ruby
196
+ # Ver métodos de un objeto
197
+ User.new.methods.sort
198
+ User.new.methods.grep(/name/)
199
+
200
+ # Ver source de un método
201
+ User.instance_method(:full_name).source_location
202
+ User.method(:find).source_location
203
+
204
+ # Con pry
205
+ $ User#full_name # Ver source
206
+ ? User#full_name # Ver documentación
207
+
208
+ # Ver ancestros
209
+ User.ancestors
210
+
211
+ # Ver asociaciones
212
+ User.reflect_on_all_associations.map(&:name)
213
+
214
+ # Ver columnas
215
+ User.column_names
216
+ User.columns_hash["email"]
217
+ ```
218
+
219
+ ## Logging
220
+
221
+ ### Niveles de log
222
+
223
+ ```ruby
224
+ # config/environments/development.rb
225
+ config.log_level = :debug # :debug, :info, :warn, :error, :fatal
226
+
227
+ # En código
228
+ Rails.logger.debug "Valor de x: #{x}"
229
+ Rails.logger.info "Usuario creado: #{user.id}"
230
+ Rails.logger.warn "Parámetro deprecado usado"
231
+ Rails.logger.error "Fallo en payment: #{error.message}"
232
+ Rails.logger.fatal "Sistema no puede continuar"
233
+ ```
234
+
235
+ ### Tagged Logging
236
+
237
+ ```ruby
238
+ # config/application.rb
239
+ config.log_tags = [:request_id, :remote_ip]
240
+
241
+ # Uso manual
242
+ Rails.logger.tagged("OrderProcessor", "User:#{user.id}") do
243
+ Rails.logger.info "Procesando orden"
244
+ # [OrderProcessor] [User:123] Procesando orden
245
+ end
246
+ ```
247
+
248
+ ### Custom Logger
249
+
250
+ ```ruby
251
+ # lib/debug_logger.rb
252
+ class DebugLogger
253
+ def self.log(context, data = {})
254
+ return unless Rails.env.development?
255
+
256
+ message = {
257
+ timestamp: Time.current.iso8601,
258
+ context: context,
259
+ caller: caller[0],
260
+ **data
261
+ }
262
+
263
+ Rails.logger.debug message.to_json
264
+ end
265
+ end
266
+
267
+ # Uso
268
+ DebugLogger.log("PaymentService", amount: 100, user_id: user.id)
269
+ ```
270
+
271
+ ### Silenciar logs temporalmente
272
+
273
+ ```ruby
274
+ # Silenciar ActiveRecord
275
+ ActiveRecord::Base.logger.silence do
276
+ # Queries aquí no se loguean
277
+ User.find_each { |u| process(u) }
278
+ end
279
+
280
+ # Log a archivo específico
281
+ debug_log = Logger.new(Rails.root.join("log/debug.log"))
282
+ debug_log.info "Investigando bug..."
283
+ ```
284
+
285
+ ## Stack Traces
286
+
287
+ ### Leer un stack trace
288
+
289
+ ```
290
+ NoMethodError: undefined method 'total' for nil:NilClass
291
+
292
+ app/models/order.rb:25:in `calculate_total'
293
+ app/services/checkout_service.rb:15:in `process'
294
+ app/controllers/orders_controller.rb:10:in `create'
295
+ ```
296
+
297
+ **Leer de abajo hacia arriba:**
298
+ 1. El error empezó en `orders_controller.rb:10`
299
+ 2. Llamó a `checkout_service.rb:15`
300
+ 3. Que llamó a `order.rb:25` donde ocurrió el error
301
+
302
+ ### Filtrar stack trace
303
+
304
+ ```ruby
305
+ # config/initializers/backtrace_silencers.rb
306
+ Rails.backtrace_cleaner.add_silencer { |line| line.include?("/gems/") }
307
+
308
+ # Ver backtrace completo
309
+ Rails.backtrace_cleaner.remove_silencers!
310
+
311
+ # En una excepción
312
+ begin
313
+ risky_operation
314
+ rescue => e
315
+ puts e.message
316
+ puts e.backtrace.first(10).join("\n")
317
+
318
+ # Con Rails cleaner
319
+ puts Rails.backtrace_cleaner.clean(e.backtrace).join("\n")
320
+ end
321
+ ```
322
+
323
+ ### Capturar contexto
324
+
325
+ ```ruby
326
+ # Guardar contexto cuando ocurre un error
327
+ class ApplicationController < ActionController::Base
328
+ rescue_from StandardError do |exception|
329
+ context = {
330
+ user_id: current_user&.id,
331
+ params: params.to_unsafe_h,
332
+ session: session.to_h,
333
+ url: request.url,
334
+ method: request.method
335
+ }
336
+
337
+ Rails.logger.error "Error: #{exception.message}"
338
+ Rails.logger.error "Context: #{context.to_json}"
339
+ Rails.logger.error exception.backtrace.first(20).join("\n")
340
+
341
+ raise exception
342
+ end
343
+ end
344
+ ```
345
+
346
+ ## Estrategias de Debugging
347
+
348
+ ### Divide y vencerás
349
+
350
+ ```ruby
351
+ # Bug: el resultado es incorrecto
352
+ def complex_calculation(data)
353
+ # Dividir en pasos y verificar cada uno
354
+ step1 = transform_data(data)
355
+ Rails.logger.debug "After step1: #{step1.inspect}"
356
+
357
+ step2 = filter_data(step1)
358
+ Rails.logger.debug "After step2: #{step2.inspect}"
359
+
360
+ step3 = aggregate_data(step2)
361
+ Rails.logger.debug "After step3: #{step3.inspect}"
362
+
363
+ step3
364
+ end
365
+ ```
366
+
367
+ ### Rubber Duck Debugging
368
+
369
+ ```ruby
370
+ # Explicar el código línea por línea:
371
+ def find_discount(user, cart)
372
+ # 1. Obtengo todos los cupones activos del usuario
373
+ coupons = user.coupons.active
374
+
375
+ # 2. Filtro los que aplican a los productos del carrito
376
+ applicable = coupons.select { |c| c.applies_to?(cart) }
377
+
378
+ # 3. Ordeno por descuento y tomo el mejor
379
+ # ESPERA... ¿qué pasa si applicable está vacío?
380
+ best = applicable.max_by(&:discount_percent)
381
+
382
+ # 4. Retorno el descuento
383
+ best.discount_percent # NoMethodError si best es nil!
384
+ end
385
+
386
+ # Fix:
387
+ best&.discount_percent || 0
388
+ ```
389
+
390
+ ### Binary Search (para bugs de regresión)
391
+
392
+ ```ruby
393
+ # Si algo funcionaba antes y ahora no:
394
+
395
+ # 1. Usar git bisect
396
+ # git bisect start
397
+ # git bisect bad HEAD
398
+ # git bisect good v1.0.0
399
+ # git bisect run bundle exec rspec spec/models/order_spec.rb
400
+
401
+ # 2. Manual: comentar mitad del código
402
+ def process_order(order)
403
+ validate_order(order)
404
+ # calculate_taxes(order)
405
+ # apply_discounts(order)
406
+ # process_payment(order)
407
+ # send_confirmation(order)
408
+ end
409
+ # Si funciona, el bug está en la mitad comentada
410
+ # Seguir dividiendo hasta encontrarlo
411
+ ```
412
+
413
+ ### Añadir assertions temporales
414
+
415
+ ```ruby
416
+ def transfer_money(from, to, amount)
417
+ # Assertions para encontrar estado inesperado
418
+ raise "from is nil!" if from.nil?
419
+ raise "to is nil!" if to.nil?
420
+ raise "amount must be positive: #{amount}" unless amount.positive?
421
+ raise "insufficient funds: #{from.balance} < #{amount}" if from.balance < amount
422
+
423
+ from.balance -= amount
424
+ to.balance += amount
425
+
426
+ # Verificar invariantes
427
+ raise "from balance negative!" if from.balance.negative?
428
+ end
429
+ ```
430
+
431
+ ## Profiling
432
+
433
+ ### Rack Mini Profiler
434
+
435
+ ```ruby
436
+ # Gemfile
437
+ group :development do
438
+ gem "rack-mini-profiler"
439
+ gem "memory_profiler"
440
+ gem "stackprof"
441
+ end
442
+ ```
443
+
444
+ ```ruby
445
+ # En cualquier request, aparece badge con timing
446
+ # Añadir ?pp=flamegraph para flamegraph
447
+ # Añadir ?pp=analyze-memory para memoria
448
+ ```
449
+
450
+ ### Memory Profiler
451
+
452
+ ```ruby
453
+ # En consola o código
454
+ require "memory_profiler"
455
+
456
+ report = MemoryProfiler.report do
457
+ # Código a analizar
458
+ 1000.times { User.all.to_a }
459
+ end
460
+
461
+ report.pretty_print(to_file: "tmp/memory_report.txt")
462
+
463
+ # Métricas clave:
464
+ # - Total allocated: memoria usada
465
+ # - Total retained: memoria no liberada (posible leak)
466
+ ```
467
+
468
+ ### StackProf (CPU profiling)
469
+
470
+ ```ruby
471
+ require "stackprof"
472
+
473
+ # Profile bloque de código
474
+ StackProf.run(mode: :cpu, out: "tmp/stackprof.dump") do
475
+ # Código lento
476
+ heavy_computation
477
+ end
478
+
479
+ # Analizar resultados
480
+ # stackprof tmp/stackprof.dump --text
481
+ # stackprof tmp/stackprof.dump --method 'Object#slow_method'
482
+
483
+ # Profile request completo
484
+ # En config/initializers/stackprof.rb
485
+ if Rails.env.development?
486
+ require "stackprof"
487
+ use StackProf::Middleware, enabled: true,
488
+ mode: :cpu,
489
+ interval: 1000,
490
+ save_every: 5
491
+ end
492
+ ```
493
+
494
+ ### Benchmark
495
+
496
+ ```ruby
497
+ require "benchmark"
498
+
499
+ # Medir tiempo
500
+ time = Benchmark.measure do
501
+ User.all.each { |u| process(u) }
502
+ end
503
+ puts time # 0.234567
504
+
505
+ # Comparar alternativas
506
+ Benchmark.bm(20) do |x|
507
+ x.report("each:") { users.each { |u| process(u) } }
508
+ x.report("find_each:") { User.find_each { |u| process(u) } }
509
+ x.report("in_batches:") { User.in_batches { |batch| batch.each { |u| process(u) } } }
510
+ end
511
+
512
+ # Benchmark/ips para comparaciones más precisas
513
+ require "benchmark/ips"
514
+
515
+ Benchmark.ips do |x|
516
+ x.report("string +") { "hello" + " " + "world" }
517
+ x.report("string interpolation") { "hello #{'world'}" }
518
+ x.compare!
519
+ end
520
+ ```
521
+
522
+ ## N+1 Queries
523
+
524
+ ### Bullet Gem
525
+
526
+ ```ruby
527
+ # Gemfile
528
+ group :development do
529
+ gem "bullet"
530
+ end
531
+
532
+ # config/environments/development.rb
533
+ config.after_initialize do
534
+ Bullet.enable = true
535
+ Bullet.alert = true # Popup en browser
536
+ Bullet.bullet_logger = true # Log a bullet.log
537
+ Bullet.console = true # Console.log
538
+ Bullet.rails_logger = true # Rails logger
539
+ Bullet.add_footer = true # Footer en página
540
+ end
541
+ ```
542
+
543
+ ### Detectar manualmente
544
+
545
+ ```ruby
546
+ # Activar logging de SQL
547
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
548
+
549
+ # En consola
550
+ User.all.each { |u| puts u.posts.count }
551
+ # Verás N+1 queries: 1 para users + N para posts
552
+
553
+ # Usar explain
554
+ User.includes(:posts).explain
555
+ # Muestra plan de ejecución
556
+ ```
557
+
558
+ ### Solucionar N+1
559
+
560
+ ```ruby
561
+ # ANTES (N+1)
562
+ @users = User.all
563
+ # En vista: user.posts.count genera query por usuario
564
+
565
+ # DESPUÉS (eager loading)
566
+ @users = User.includes(:posts)
567
+ # o
568
+ @users = User.preload(:posts)
569
+ # o para joins
570
+ @users = User.eager_load(:posts)
571
+
572
+ # Diferencias:
573
+ # includes: Rails decide si usar JOIN o queries separadas
574
+ # preload: Siempre queries separadas
575
+ # eager_load: Siempre LEFT OUTER JOIN
576
+
577
+ # Counter cache para counts
578
+ class Post < ApplicationRecord
579
+ belongs_to :user, counter_cache: true
580
+ end
581
+ # Requiere columna posts_count en users
582
+ ```
583
+
584
+ ## Error Tracking
585
+
586
+ ### Sentry
587
+
588
+ ```ruby
589
+ # Gemfile
590
+ gem "sentry-ruby"
591
+ gem "sentry-rails"
592
+
593
+ # config/initializers/sentry.rb
594
+ Sentry.init do |config|
595
+ config.dsn = Rails.application.credentials.sentry_dsn
596
+ config.environment = Rails.env
597
+ config.breadcrumbs_logger = [:active_support_logger, :http_logger]
598
+
599
+ # Sample rate (0.0 a 1.0)
600
+ config.traces_sample_rate = 0.5
601
+
602
+ # Filtrar datos sensibles
603
+ config.before_send = lambda do |event, hint|
604
+ event.extra.delete(:password)
605
+ event
606
+ end
607
+ end
608
+
609
+ # Capturar errores manualmente
610
+ begin
611
+ risky_operation
612
+ rescue => e
613
+ Sentry.capture_exception(e, extra: { user_id: current_user.id })
614
+ raise
615
+ end
616
+
617
+ # Añadir contexto
618
+ Sentry.set_user(id: user.id, email: user.email)
619
+ Sentry.set_tags(feature: "checkout")
620
+ Sentry.set_context("order", { id: order.id, total: order.total })
621
+ ```
622
+
623
+ ### Honeybadger
624
+
625
+ ```ruby
626
+ # Gemfile
627
+ gem "honeybadger"
628
+
629
+ # config/honeybadger.yml
630
+ api_key: <%= Rails.application.credentials.honeybadger_api_key %>
631
+ env: <%= Rails.env %>
632
+
633
+ # Uso
634
+ Honeybadger.notify(exception, context: { user_id: user.id })
635
+ ```
636
+
637
+ ### Rollbar
638
+
639
+ ```ruby
640
+ # Gemfile
641
+ gem "rollbar"
642
+
643
+ # config/initializers/rollbar.rb
644
+ Rollbar.configure do |config|
645
+ config.access_token = Rails.application.credentials.rollbar_token
646
+ config.environment = Rails.env
647
+ end
648
+
649
+ # Uso
650
+ Rollbar.error(exception, user_id: user.id)
651
+ ```
652
+
653
+ ## Reproducir Bugs
654
+
655
+ ### Seeds para estado específico
656
+
657
+ ```ruby
658
+ # db/seeds/bug_reproduction.rb
659
+ # Crear datos que reproducen el bug
660
+
661
+ user = User.create!(
662
+ email: "test@example.com",
663
+ password: "password123"
664
+ )
665
+
666
+ # Estado específico que causa el bug
667
+ order = Order.create!(
668
+ user: user,
669
+ status: "pending",
670
+ total: 0 # Edge case que causa división por cero
671
+ )
672
+
673
+ puts "Bug reproduction data created"
674
+ puts "User ID: #{user.id}"
675
+ puts "Order ID: #{order.id}"
676
+ ```
677
+
678
+ ### Fixtures de test
679
+
680
+ ```yaml
681
+ # spec/fixtures/users.yml
682
+ bug_user:
683
+ email: user_with_bug@example.com
684
+ name: Bug User
685
+
686
+ # spec/fixtures/orders.yml
687
+ problematic_order:
688
+ user: bug_user
689
+ status: pending
690
+ total: 0
691
+ ```
692
+
693
+ ### Script de reproducción
694
+
695
+ ```ruby
696
+ #!/usr/bin/env ruby
697
+ # scripts/reproduce_bug_123.rb
698
+
699
+ require_relative "../config/environment"
700
+
701
+ puts "Reproduciendo Bug #123..."
702
+
703
+ # 1. Crear estado inicial
704
+ user = User.create!(email: "test#{Time.now.to_i}@test.com", password: "password")
705
+ order = user.orders.create!(status: "pending")
706
+
707
+ # 2. Ejecutar acción que causa el bug
708
+ begin
709
+ CheckoutService.new(order).process
710
+ rescue => e
711
+ puts "Bug reproducido!"
712
+ puts "Error: #{e.message}"
713
+ puts e.backtrace.first(5).join("\n")
714
+ end
715
+
716
+ # 3. Limpiar
717
+ user.destroy
718
+ ```
719
+
720
+ ### Pasos claros
721
+
722
+ ```markdown
723
+ ## Bug #123: Error al procesar orden vacía
724
+
725
+ ### Pasos para reproducir:
726
+ 1. Crear usuario: `user = User.create!(email: "test@test.com", password: "pass")`
727
+ 2. Crear orden sin items: `order = user.orders.create!()`
728
+ 3. Intentar checkout: `CheckoutService.new(order).process`
729
+
730
+ ### Resultado esperado:
731
+ Error claro indicando que la orden está vacía
732
+
733
+ ### Resultado actual:
734
+ `ZeroDivisionError: divided by 0`
735
+
736
+ ### Causa raíz:
737
+ En `order.rb:45`, se divide total entre número de items sin verificar que no sea cero.
738
+
739
+ ### Fix:
740
+ ```ruby
741
+ def average_item_price
742
+ return 0 if line_items.empty?
743
+ total / line_items.count
744
+ end
745
+ ```
746
+ ```
747
+
748
+ ## Debugging en Producción
749
+
750
+ ### Logs estructurados
751
+
752
+ ```ruby
753
+ # config/environments/production.rb
754
+ config.log_formatter = proc do |severity, time, progname, msg|
755
+ {
756
+ timestamp: time.iso8601,
757
+ level: severity,
758
+ message: msg,
759
+ app: "myapp",
760
+ env: Rails.env
761
+ }.to_json + "\n"
762
+ end
763
+ ```
764
+
765
+ ### Investigar sin reproducir
766
+
767
+ ```ruby
768
+ # Añadir logging temporal
769
+ class OrderProcessor
770
+ def process(order)
771
+ Rails.logger.info({
772
+ event: "order_processing_start",
773
+ order_id: order.id,
774
+ user_id: order.user_id,
775
+ items_count: order.line_items.count,
776
+ total: order.total
777
+ }.to_json)
778
+
779
+ result = do_processing(order)
780
+
781
+ Rails.logger.info({
782
+ event: "order_processing_complete",
783
+ order_id: order.id,
784
+ result: result
785
+ }.to_json)
786
+
787
+ result
788
+ rescue => e
789
+ Rails.logger.error({
790
+ event: "order_processing_error",
791
+ order_id: order.id,
792
+ error: e.message,
793
+ backtrace: e.backtrace.first(10)
794
+ }.to_json)
795
+
796
+ raise
797
+ end
798
+ end
799
+ ```
800
+
801
+ ### Console en producción (con cuidado)
802
+
803
+ ```bash
804
+ # Conectar a producción
805
+ RAILS_ENV=production rails console
806
+
807
+ # SIEMPRE usar transacciones para investigar
808
+ ActiveRecord::Base.transaction do
809
+ # Investigar...
810
+ order = Order.find(123)
811
+ order.calculate_total
812
+
813
+ raise ActiveRecord::Rollback # No guardar cambios
814
+ end
815
+
816
+ # Solo lectura
817
+ Order.find(123).attributes
818
+ User.where(created_at: 1.day.ago..).count
819
+ ```
820
+
821
+ ## Checklist de Debugging
822
+
823
+ ### Cuando encuentras un bug:
824
+
825
+ 1. [ ] Reproducir el bug de forma consistente
826
+ 2. [ ] Aislar el problema (quitar código hasta que desaparezca)
827
+ 3. [ ] Añadir logging/breakpoints en puntos clave
828
+ 4. [ ] Verificar entrada vs salida esperada
829
+ 5. [ ] Revisar código reciente (git log, git blame)
830
+ 6. [ ] Buscar patrones similares en el código
831
+ 7. [ ] Escribir test que falle
832
+ 8. [ ] Aplicar fix
833
+ 9. [ ] Verificar que el test pase
834
+ 10. [ ] Verificar que no haya regresiones