pg_sql_triggers 1.2.0 → 1.4.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +397 -1
  3. data/COVERAGE.md +26 -19
  4. data/GEM_ANALYSIS.md +368 -0
  5. data/Goal.md +276 -155
  6. data/README.md +45 -22
  7. data/app/assets/javascripts/pg_sql_triggers/trigger_actions.js +50 -0
  8. data/app/controllers/concerns/pg_sql_triggers/error_handling.rb +56 -0
  9. data/app/controllers/concerns/pg_sql_triggers/kill_switch_protection.rb +66 -0
  10. data/app/controllers/concerns/pg_sql_triggers/permission_checking.rb +117 -0
  11. data/app/controllers/pg_sql_triggers/application_controller.rb +10 -62
  12. data/app/controllers/pg_sql_triggers/audit_logs_controller.rb +102 -0
  13. data/app/controllers/pg_sql_triggers/dashboard_controller.rb +4 -9
  14. data/app/controllers/pg_sql_triggers/tables_controller.rb +30 -4
  15. data/app/controllers/pg_sql_triggers/triggers_controller.rb +3 -21
  16. data/app/helpers/pg_sql_triggers/permissions_helper.rb +43 -0
  17. data/app/models/pg_sql_triggers/audit_log.rb +106 -0
  18. data/app/models/pg_sql_triggers/trigger_registry.rb +218 -13
  19. data/app/views/layouts/pg_sql_triggers/application.html.erb +25 -6
  20. data/app/views/pg_sql_triggers/audit_logs/index.html.erb +177 -0
  21. data/app/views/pg_sql_triggers/dashboard/index.html.erb +34 -12
  22. data/app/views/pg_sql_triggers/tables/index.html.erb +75 -5
  23. data/app/views/pg_sql_triggers/tables/show.html.erb +17 -6
  24. data/app/views/pg_sql_triggers/triggers/_drop_modal.html.erb +16 -7
  25. data/app/views/pg_sql_triggers/triggers/_re_execute_modal.html.erb +16 -7
  26. data/app/views/pg_sql_triggers/triggers/show.html.erb +26 -6
  27. data/config/routes.rb +2 -14
  28. data/db/migrate/20260103000001_create_pg_sql_triggers_audit_log.rb +28 -0
  29. data/db/migrate/20260228000001_add_for_each_to_pg_sql_triggers_registry.rb +8 -0
  30. data/docs/README.md +15 -5
  31. data/docs/api-reference.md +233 -151
  32. data/docs/audit-trail.md +413 -0
  33. data/docs/configuration.md +28 -7
  34. data/docs/getting-started.md +17 -16
  35. data/docs/permissions.md +369 -0
  36. data/docs/troubleshooting.md +486 -0
  37. data/docs/ui-guide.md +211 -0
  38. data/docs/usage-guide.md +38 -67
  39. data/docs/web-ui.md +251 -128
  40. data/lib/generators/pg_sql_triggers/templates/trigger_dsl.rb.tt +11 -0
  41. data/lib/generators/pg_sql_triggers/templates/trigger_migration_full.rb.tt +29 -0
  42. data/lib/generators/pg_sql_triggers/trigger_generator.rb +83 -0
  43. data/lib/pg_sql_triggers/drift/db_queries.rb +12 -8
  44. data/lib/pg_sql_triggers/drift/detector.rb +51 -38
  45. data/lib/pg_sql_triggers/dsl/trigger_definition.rb +17 -23
  46. data/lib/pg_sql_triggers/engine.rb +14 -0
  47. data/lib/pg_sql_triggers/errors.rb +245 -0
  48. data/lib/pg_sql_triggers/migrator/pre_apply_comparator.rb +8 -9
  49. data/lib/pg_sql_triggers/migrator/safety_validator.rb +32 -12
  50. data/lib/pg_sql_triggers/migrator.rb +53 -6
  51. data/lib/pg_sql_triggers/permissions/checker.rb +9 -2
  52. data/lib/pg_sql_triggers/registry/manager.rb +36 -11
  53. data/lib/pg_sql_triggers/registry/validator.rb +62 -5
  54. data/lib/pg_sql_triggers/registry.rb +141 -8
  55. data/lib/pg_sql_triggers/sql/kill_switch.rb +153 -247
  56. data/lib/pg_sql_triggers/sql.rb +0 -6
  57. data/lib/pg_sql_triggers/testing/function_tester.rb +2 -0
  58. data/lib/pg_sql_triggers/version.rb +1 -1
  59. data/lib/pg_sql_triggers.rb +7 -7
  60. data/pg_sql_triggers.gemspec +53 -0
  61. metadata +35 -18
  62. data/app/controllers/pg_sql_triggers/generator_controller.rb +0 -213
  63. data/app/controllers/pg_sql_triggers/sql_capsules_controller.rb +0 -161
  64. data/app/views/pg_sql_triggers/generator/new.html.erb +0 -388
  65. data/app/views/pg_sql_triggers/generator/preview.html.erb +0 -305
  66. data/app/views/pg_sql_triggers/sql_capsules/new.html.erb +0 -81
  67. data/app/views/pg_sql_triggers/sql_capsules/show.html.erb +0 -85
  68. data/docs/screenshots/.gitkeep +0 -1
  69. data/docs/screenshots/Generate Trigger.png +0 -0
  70. data/docs/screenshots/Triggers Page.png +0 -0
  71. data/docs/screenshots/kill error.png +0 -0
  72. data/docs/screenshots/kill modal for migration down.png +0 -0
  73. data/lib/generators/trigger/migration_generator.rb +0 -60
  74. data/lib/pg_sql_triggers/generator/form.rb +0 -80
  75. data/lib/pg_sql_triggers/generator/service.rb +0 -307
  76. data/lib/pg_sql_triggers/generator.rb +0 -8
  77. data/lib/pg_sql_triggers/sql/capsule.rb +0 -79
  78. data/lib/pg_sql_triggers/sql/executor.rb +0 -200
data/docs/README.md CHANGED
@@ -9,12 +9,16 @@ Welcome to the PgSqlTriggers documentation. This directory contains comprehensiv
9
9
 
10
10
  ### Core Guides
11
11
  - **[Usage Guide](usage-guide.md)** - DSL syntax, migrations, and drift detection
12
- - **[Web UI Guide](web-ui.md)** - Using the web dashboard
12
+ - **[UI Guide](ui-guide.md)** - Quick start guide for the web interface
13
+ - **[Web UI Guide](web-ui.md)** - Comprehensive web dashboard documentation
13
14
  - **[Kill Switch Guide](kill-switch.md)** - Production safety features
15
+ - **[Permissions Guide](permissions.md)** - Configuring and using permissions
16
+ - **[Audit Trail Guide](audit-trail.md)** - Viewing and exporting audit logs
14
17
 
15
18
  ### Reference
16
19
  - **[Configuration Reference](configuration.md)** - Complete configuration options
17
20
  - **[API Reference](api-reference.md)** - Console API and programmatic usage
21
+ - **[Troubleshooting Guide](troubleshooting.md)** - Common issues and solutions
18
22
 
19
23
  ## Quick Links
20
24
 
@@ -30,20 +34,26 @@ See [Usage Guide - Declaring Triggers](usage-guide.md#declaring-triggers)
30
34
  See [Usage Guide - Trigger Migrations](usage-guide.md#trigger-migrations)
31
35
 
32
36
  #### Use the web dashboard
33
- See [Web UI Documentation](web-ui.md)
37
+ Start with [UI Guide](ui-guide.md) or see [Web UI Documentation](web-ui.md) for comprehensive details
38
+
39
+ #### Configure permissions
40
+ See [Permissions Guide](permissions.md) or [Configuration - Permission System](configuration.md#permission-system)
41
+
42
+ #### View audit logs
43
+ See [Audit Trail Guide](audit-trail.md)
34
44
 
35
45
  #### Protect production
36
46
  See [Kill Switch Documentation](kill-switch.md)
37
47
 
38
- #### Configure permissions
39
- See [Configuration - Permission System](configuration.md#permission-system)
40
-
41
48
  #### Use the console API
42
49
  See [API Reference](api-reference.md)
43
50
 
44
51
  #### Handle drift detection
45
52
  See [Usage Guide - Drift Detection](usage-guide.md#drift-detection)
46
53
 
54
+ #### Troubleshoot issues
55
+ See [Troubleshooting Guide](troubleshooting.md)
56
+
47
57
  ## Screenshots
48
58
 
49
59
  Screenshots referenced in the documentation are stored in the [screenshots](screenshots/) directory.
@@ -9,6 +9,9 @@ Complete reference for using PgSqlTriggers programmatically from the Rails conso
9
9
  - [Kill Switch API](#kill-switch-api)
10
10
  - [DSL API](#dsl-api)
11
11
  - [TriggerRegistry Model](#triggerregistry-model)
12
+ - [Audit Log API](#audit-log-api)
13
+
14
+ > **Removed in 1.4.0**: `SQL::Capsule` and `SQL::Executor` have been removed. See [CHANGELOG](../CHANGELOG.md) for details.
12
15
 
13
16
  ## Registry API
14
17
 
@@ -97,6 +100,76 @@ end
97
100
 
98
101
  **Returns**: Hash with drift categories
99
102
 
103
+ ### `PgSqlTriggers::Registry.drifted`
104
+
105
+ Returns all triggers that have drifted from their expected state.
106
+
107
+ ```ruby
108
+ drifted_triggers = PgSqlTriggers::Registry.drifted
109
+ # => [
110
+ # { state: "drifted", trigger_name: "users_email_validation", ... },
111
+ # ...
112
+ # ]
113
+
114
+ drifted_triggers.each do |trigger|
115
+ puts "Drifted: #{trigger[:trigger_name]}"
116
+ end
117
+ ```
118
+
119
+ **Returns**: Array of drift result hashes for drifted triggers
120
+
121
+ ### `PgSqlTriggers::Registry.in_sync`
122
+
123
+ Returns all triggers that are in sync with their expected state.
124
+
125
+ ```ruby
126
+ in_sync_triggers = PgSqlTriggers::Registry.in_sync
127
+ # => [
128
+ # { state: "in_sync", trigger_name: "billing_trigger", ... },
129
+ # ...
130
+ # ]
131
+
132
+ puts "In sync triggers: #{in_sync_triggers.count}"
133
+ ```
134
+
135
+ **Returns**: Array of drift result hashes for in-sync triggers
136
+
137
+ ### `PgSqlTriggers::Registry.unknown_triggers`
138
+
139
+ Returns all unknown (external) triggers not managed by this gem.
140
+
141
+ ```ruby
142
+ unknown = PgSqlTriggers::Registry.unknown_triggers
143
+ # => [
144
+ # { state: "unknown", trigger_name: "external_trigger", ... },
145
+ # ...
146
+ # ]
147
+
148
+ unknown.each do |trigger|
149
+ puts "External trigger: #{trigger[:trigger_name]}"
150
+ end
151
+ ```
152
+
153
+ **Returns**: Array of drift result hashes for unknown triggers
154
+
155
+ ### `PgSqlTriggers::Registry.dropped`
156
+
157
+ Returns all triggers that have been dropped from the database.
158
+
159
+ ```ruby
160
+ dropped_triggers = PgSqlTriggers::Registry.dropped
161
+ # => [
162
+ # { state: "dropped", trigger_name: "old_trigger", ... },
163
+ # ...
164
+ # ]
165
+
166
+ dropped_triggers.each do |trigger|
167
+ puts "Dropped: #{trigger[:trigger_name]}"
168
+ end
169
+ ```
170
+
171
+ **Returns**: Array of drift result hashes for dropped triggers
172
+
100
173
  ### `PgSqlTriggers::Registry.validate!`
101
174
 
102
175
  Validates all triggers and raises an error if any are invalid.
@@ -414,124 +487,6 @@ end
414
487
 
415
488
  **Returns**: Result of the block
416
489
 
417
- ## SQL Capsule API
418
-
419
- The SQL Capsule API provides emergency SQL execution capabilities with safety checks.
420
-
421
- ### `PgSqlTriggers::SQL::Capsule.new(name:, environment:, purpose:, sql:, created_at: nil)`
422
-
423
- Creates a new SQL capsule for emergency operations.
424
-
425
- ```ruby
426
- capsule = PgSqlTriggers::SQL::Capsule.new(
427
- name: "fix_user_permissions",
428
- environment: "production",
429
- purpose: "Emergency fix for user permission issue after deployment",
430
- sql: "UPDATE users SET role = 'admin' WHERE email = 'admin@example.com';"
431
- )
432
- ```
433
-
434
- **Parameters**:
435
- - `name` (String): Unique name for the capsule (alphanumeric, underscores, hyphens only)
436
- - `environment` (String): Target environment (e.g., "production", "staging")
437
- - `purpose` (String): Description of what the capsule does and why (required for audit trail)
438
- - `sql` (String): The SQL statement(s) to execute
439
- - `created_at` (Time, optional): Creation timestamp (defaults to current time)
440
-
441
- **Raises**: `ArgumentError` if validation fails
442
-
443
- ### `capsule.checksum`
444
-
445
- Returns the SHA256 checksum of the SQL content.
446
-
447
- ```ruby
448
- capsule = PgSqlTriggers::SQL::Capsule.new(name: "fix", ...)
449
- puts capsule.checksum
450
- # => "a3f5b8c9d2e..."
451
- ```
452
-
453
- **Returns**: String (SHA256 hash)
454
-
455
- ### `capsule.to_h`
456
-
457
- Converts the capsule to a hash for storage or serialization.
458
-
459
- ```ruby
460
- capsule_data = capsule.to_h
461
- # => {
462
- # name: "fix_user_permissions",
463
- # environment: "production",
464
- # purpose: "Emergency fix...",
465
- # sql: "UPDATE users...",
466
- # checksum: "a3f5b8c9d2e...",
467
- # created_at: 2026-01-01 12:00:00 UTC
468
- # }
469
- ```
470
-
471
- **Returns**: Hash
472
-
473
- ## SQL Executor API
474
-
475
- The SQL Executor API handles safe execution of SQL capsules with comprehensive logging.
476
-
477
- ### `PgSqlTriggers::SQL::Executor.execute(capsule, actor:, confirmation: nil, dry_run: false)`
478
-
479
- Executes a SQL capsule with safety checks and logging.
480
-
481
- ```ruby
482
- capsule = PgSqlTriggers::SQL::Capsule.new(
483
- name: "emergency_fix",
484
- environment: "production",
485
- purpose: "Fix critical data corruption",
486
- sql: "UPDATE orders SET status = 'completed' WHERE id IN (123, 456);"
487
- )
488
-
489
- # Execute the capsule
490
- result = PgSqlTriggers::SQL::Executor.execute(
491
- capsule,
492
- actor: { type: "user", id: "admin@example.com" },
493
- confirmation: "EXECUTE SQL"
494
- )
495
-
496
- if result[:success]
497
- puts "SQL executed successfully"
498
- puts "Rows affected: #{result[:data][:rows_affected]}"
499
- else
500
- puts "Execution failed: #{result[:message]}"
501
- end
502
- ```
503
-
504
- **Parameters**:
505
- - `capsule` (Capsule): The SQL capsule to execute
506
- - `actor` (Hash): Information about who is executing (Admin permission required)
507
- - `confirmation` (String, optional): Kill switch confirmation text
508
- - `dry_run` (Boolean): If true, validates without executing (default: false)
509
-
510
- **Returns**: Hash with `:success`, `:message`, and `:data` keys
511
-
512
- **Raises**: Permission and kill switch errors are returned in the result hash
513
-
514
- ### `PgSqlTriggers::SQL::Executor.execute_capsule(capsule_name, actor:, confirmation: nil, dry_run: false)`
515
-
516
- Executes a previously stored SQL capsule by name from the registry.
517
-
518
- ```ruby
519
- # Execute a capsule stored in the registry
520
- result = PgSqlTriggers::SQL::Executor.execute_capsule(
521
- "emergency_fix",
522
- actor: { type: "user", id: "admin@example.com" },
523
- confirmation: "EXECUTE SQL"
524
- )
525
- ```
526
-
527
- **Parameters**:
528
- - `capsule_name` (String): Name of the capsule in the registry
529
- - `actor` (Hash): Information about who is executing
530
- - `confirmation` (String, optional): Kill switch confirmation text
531
- - `dry_run` (Boolean): If true, validates without executing
532
-
533
- **Returns**: Hash with execution results
534
-
535
490
  ## DSL API
536
491
 
537
492
  The DSL API is used to define triggers in your application.
@@ -545,10 +500,10 @@ PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
545
500
  table :users
546
501
  on :insert, :update
547
502
  function :validate_user_email
548
- version 1
549
- enabled false
503
+ self.version = 1
504
+ self.enabled = true
550
505
  timing :before
551
- when_env :production
506
+ for_each_row
552
507
  end
553
508
  ```
554
509
 
@@ -580,7 +535,7 @@ on :insert, :update, :delete
580
535
  ```
581
536
 
582
537
  **Parameters**:
583
- - `events` (Symbols): One or more of `:insert`, `:update`, `:delete`
538
+ - `events` (Symbols): One or more of `:insert`, `:update`, `:delete`, `:truncate`
584
539
 
585
540
  #### `function(function_name)`
586
541
 
@@ -593,37 +548,48 @@ function :validate_user_email
593
548
  **Parameters**:
594
549
  - `function_name` (Symbol): Function name
595
550
 
596
- #### `version(number)`
551
+ #### `self.version = number`
597
552
 
598
553
  Sets the trigger version.
599
554
 
600
555
  ```ruby
601
- version 1
602
- version 2
556
+ self.version = 1 # Increment when trigger logic changes
557
+ self.version = 2
603
558
  ```
604
559
 
605
560
  **Parameters**:
606
561
  - `number` (Integer): Version number
607
562
 
608
- #### `enabled(state)`
563
+ #### `self.enabled = state`
609
564
 
610
- Sets the initial enabled state.
565
+ Sets the initial enabled state. Defaults to `true`.
611
566
 
612
567
  ```ruby
613
- enabled true
614
- enabled false
568
+ self.enabled = true # Trigger is active (default)
569
+ self.enabled = false # Trigger is inactive
615
570
  ```
616
571
 
617
572
  **Parameters**:
618
573
  - `state` (Boolean): Initial state
619
574
 
575
+ #### `for_each_row` / `for_each_statement`
576
+
577
+ Specifies PostgreSQL execution granularity. Defaults to `for_each_row`.
578
+
579
+ ```ruby
580
+ for_each_row # FOR EACH ROW (default)
581
+ for_each_statement # FOR EACH STATEMENT
582
+ ```
583
+
584
+ Stored in the `for_each` column on the registry table and included in checksum calculation.
585
+
620
586
  #### `when_env(*environments)`
621
587
 
622
- Restricts trigger to specific environments.
588
+ **Deprecated.** Restricts trigger to specific environments. Emits a deprecation warning on every call and will be removed in a future major version. Use application-level configuration to gate trigger behaviour by environment instead.
623
589
 
624
590
  ```ruby
625
- when_env :production
626
- when_env :production, :staging
591
+ when_env :production # Deprecated — avoid in new code
592
+ when_env :production, :staging # Deprecated — avoid in new code
627
593
  ```
628
594
 
629
595
  **Parameters**:
@@ -641,8 +607,6 @@ timing :after # Trigger fires after constraint checks
641
607
  **Parameters**:
642
608
  - `timing_value` (Symbol or String): Either `:before` or `:after`
643
609
 
644
- **Returns**: Current timing value if called without argument
645
-
646
610
  ## TriggerRegistry Model
647
611
 
648
612
  The `TriggerRegistry` ActiveRecord model represents a trigger in the registry.
@@ -657,12 +621,13 @@ trigger.table_name # => "users"
657
621
  trigger.function_name # => "validate_user_email"
658
622
  trigger.events # => ["insert", "update"]
659
623
  trigger.version # => 1
660
- trigger.enabled # => false
661
- trigger.timing # => "before" or "after"
662
- trigger.environments # => ["production"]
663
- trigger.condition # => "NEW.status = 'active'" or nil
664
- trigger.created_at # => 2023-12-15 12:00:00 UTC
665
- trigger.updated_at # => 2023-12-15 12:00:00 UTC
624
+ trigger.enabled # => true
625
+ trigger.timing # => "before" or "after"
626
+ trigger.for_each # => "row" or "statement"
627
+ trigger.environments # => [] (when_env is deprecated)
628
+ trigger.condition # => "NEW.status = 'active'" or nil
629
+ trigger.created_at # => 2023-12-15 12:00:00 UTC
630
+ trigger.updated_at # => 2023-12-15 12:00:00 UTC
666
631
  ```
667
632
 
668
633
  ### Instance Methods
@@ -745,7 +710,7 @@ trigger.re_execute!(
745
710
  - `confirmation` (String, optional): Kill switch confirmation text
746
711
  - `actor` (Hash, optional): Information about who is performing the operation
747
712
 
748
- **Raises**: `ArgumentError` if reason is blank or function_body is missing, `PgSqlTriggers::KillSwitchError`, `StandardError`
713
+ **Raises**: `ArgumentError` if reason is blank, `PgSqlTriggers::KillSwitchError`, `StandardError`
749
714
 
750
715
  **Returns**: `true` on success
751
716
 
@@ -833,8 +798,12 @@ triggers = PgSqlTriggers::Registry.list
833
798
  puts "Total triggers: #{triggers.count}"
834
799
 
835
800
  # 4. Check for drift
836
- drift = PgSqlTriggers::Registry.diff
837
- puts "Drifted triggers: #{drift[:drifted].count}"
801
+ drifted = PgSqlTriggers::Registry.drifted
802
+ in_sync = PgSqlTriggers::Registry.in_sync
803
+ unknown = PgSqlTriggers::Registry.unknown_triggers
804
+ dropped = PgSqlTriggers::Registry.dropped
805
+
806
+ puts "Drifted: #{drifted.count}, In Sync: #{in_sync.count}, Unknown: #{unknown.count}, Dropped: #{dropped.count}"
838
807
 
839
808
  # 5. Enable specific trigger
840
809
  trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
@@ -876,16 +845,16 @@ end
876
845
  ### Inspection and Reporting
877
846
 
878
847
  ```ruby
879
- # Generate a drift report
880
- drift = PgSqlTriggers::Registry.diff
881
-
848
+ # Generate a drift report using dedicated query methods
882
849
  puts "=== Drift Report ==="
883
- puts "In Sync: #{drift[:in_sync].count}"
884
- puts "Drifted: #{drift[:drifted].count}"
850
+ puts "In Sync: #{PgSqlTriggers::Registry.in_sync.count}"
851
+ puts "Drifted: #{PgSqlTriggers::Registry.drifted.count}"
852
+ puts "Dropped: #{PgSqlTriggers::Registry.dropped.count}"
853
+ puts "Unknown: #{PgSqlTriggers::Registry.unknown_triggers.count}"
854
+
855
+ # Or get the full categorised hash
856
+ drift = PgSqlTriggers::Registry.diff
885
857
  puts "Manual Override: #{drift[:manual_override].count}"
886
- puts "Disabled: #{drift[:disabled].count}"
887
- puts "Dropped: #{drift[:dropped].count}"
888
- puts "Unknown: #{drift[:unknown].count}"
889
858
 
890
859
  # List all triggers with details
891
860
  triggers = PgSqlTriggers::Registry.list
@@ -897,6 +866,7 @@ triggers.each do |trigger|
897
866
  puts " Function: #{trigger.function_name}"
898
867
  puts " Events: #{trigger.events.join(', ')}"
899
868
  puts " Timing: #{trigger.timing}"
869
+ puts " For Each: #{trigger.for_each}"
900
870
  puts " Version: #{trigger.version}"
901
871
  puts " Enabled: #{trigger.enabled}"
902
872
  puts " Drift: #{trigger.drift_status}"
@@ -922,6 +892,118 @@ rescue StandardError => e
922
892
  end
923
893
  ```
924
894
 
895
+ ## Audit Log API
896
+
897
+ The Audit Log API provides methods for querying and managing audit log entries.
898
+
899
+ ### `PgSqlTriggers::AuditLog`
900
+
901
+ The `AuditLog` model provides methods for querying audit log entries.
902
+
903
+ #### Class Methods
904
+
905
+ ##### `AuditLog.for_trigger_name(trigger_name)`
906
+
907
+ Get audit log entries for a specific trigger.
908
+
909
+ **Parameters:**
910
+ - `trigger_name` (String): The trigger name to query
911
+
912
+ **Returns:** `ActiveRecord::Relation` - Audit log entries for the trigger, ordered by most recent first
913
+
914
+ **Example:**
915
+ ```ruby
916
+ # Get all audit log entries for a specific trigger
917
+ entries = PgSqlTriggers::AuditLog.for_trigger_name("users_email_validation")
918
+ entries.each do |entry|
919
+ puts "#{entry.operation}: #{entry.status} at #{entry.created_at}"
920
+ end
921
+ ```
922
+
923
+ ##### `AuditLog.log_success(...)`
924
+
925
+ Log a successful operation to the audit log.
926
+
927
+ **Parameters:**
928
+ - `operation:` (Symbol, String): The operation being performed (e.g., `:trigger_enable`)
929
+ - `trigger_name:` (String, nil): The trigger name (if applicable)
930
+ - `actor:` (Hash): Information about who performed the action (e.g., `{ type: "UI", id: "123" }`)
931
+ - `environment:` (String, nil): The environment
932
+ - `reason:` (String, nil): Reason for the operation
933
+ - `confirmation_text:` (String, nil): Confirmation text used
934
+ - `before_state:` (Hash, nil): State before operation
935
+ - `after_state:` (Hash, nil): State after operation
936
+ - `diff:` (String, nil): Diff information
937
+
938
+ **Returns:** `AuditLog` instance or `nil` if logging fails
939
+
940
+ **Example:**
941
+ ```ruby
942
+ PgSqlTriggers::AuditLog.log_success(
943
+ operation: :trigger_enable,
944
+ trigger_name: "users_email_validation",
945
+ actor: { type: "Console", id: "admin@example.com" },
946
+ environment: "production",
947
+ before_state: { enabled: false },
948
+ after_state: { enabled: true }
949
+ )
950
+ ```
951
+
952
+ ##### `AuditLog.log_failure(...)`
953
+
954
+ Log a failed operation to the audit log.
955
+
956
+ **Parameters:**
957
+ - `operation:` (Symbol, String): The operation being performed
958
+ - `trigger_name:` (String, nil): The trigger name (if applicable)
959
+ - `actor:` (Hash): Information about who performed the action
960
+ - `environment:` (String, nil): The environment
961
+ - `error_message:` (String): Error message (required)
962
+ - `reason:` (String, nil): Reason for the operation (if provided before failure)
963
+ - `confirmation_text:` (String, nil): Confirmation text used
964
+ - `before_state:` (Hash, nil): State before operation
965
+
966
+ **Returns:** `AuditLog` instance or `nil` if logging fails
967
+
968
+ **Example:**
969
+ ```ruby
970
+ PgSqlTriggers::AuditLog.log_failure(
971
+ operation: :trigger_enable,
972
+ trigger_name: "users_email_validation",
973
+ actor: { type: "UI", id: "user_123" },
974
+ environment: "production",
975
+ error_message: "Trigger does not exist in database",
976
+ before_state: { enabled: false }
977
+ )
978
+ ```
979
+
980
+ #### Scopes
981
+
982
+ The `AuditLog` model provides several useful scopes:
983
+
984
+ - `AuditLog.for_trigger(trigger_name)` - Filter by trigger name
985
+ - `AuditLog.for_operation(operation)` - Filter by operation type
986
+ - `AuditLog.for_environment(env)` - Filter by environment
987
+ - `AuditLog.successful` - Only successful operations
988
+ - `AuditLog.failed` - Only failed operations
989
+ - `AuditLog.recent` - Order by most recent first
990
+
991
+ **Example:**
992
+ ```ruby
993
+ # Get all failed operations in production
994
+ failed_ops = PgSqlTriggers::AuditLog
995
+ .failed
996
+ .for_environment("production")
997
+ .recent
998
+ .limit(10)
999
+
1000
+ # Get all enable operations for a trigger
1001
+ enable_ops = PgSqlTriggers::AuditLog
1002
+ .for_trigger("users_email_validation")
1003
+ .for_operation("trigger_enable")
1004
+ .recent
1005
+ ```
1006
+
925
1007
  ## Next Steps
926
1008
 
927
1009
  - [Usage Guide](usage-guide.md) - Learn the DSL and migration system