pg_sql_triggers 1.0.0 → 1.0.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.erb_lint.yml +47 -0
  3. data/.rubocop.yml +4 -1
  4. data/CHANGELOG.md +29 -1
  5. data/Goal.md +408 -123
  6. data/README.md +47 -215
  7. data/app/controllers/pg_sql_triggers/application_controller.rb +46 -0
  8. data/app/controllers/pg_sql_triggers/generator_controller.rb +10 -4
  9. data/app/controllers/pg_sql_triggers/migrations_controller.rb +18 -0
  10. data/app/models/pg_sql_triggers/trigger_registry.rb +20 -2
  11. data/app/views/layouts/pg_sql_triggers/application.html.erb +34 -1
  12. data/app/views/pg_sql_triggers/dashboard/index.html.erb +70 -30
  13. data/app/views/pg_sql_triggers/generator/new.html.erb +4 -4
  14. data/app/views/pg_sql_triggers/generator/preview.html.erb +14 -6
  15. data/app/views/pg_sql_triggers/shared/_confirmation_modal.html.erb +189 -0
  16. data/app/views/pg_sql_triggers/shared/_kill_switch_status.html.erb +40 -0
  17. data/app/views/pg_sql_triggers/tables/index.html.erb +0 -2
  18. data/app/views/pg_sql_triggers/tables/show.html.erb +3 -4
  19. data/db/migrate/20251222000001_create_pg_sql_triggers_tables.rb +1 -1
  20. data/docs/README.md +66 -0
  21. data/docs/api-reference.md +663 -0
  22. data/docs/configuration.md +541 -0
  23. data/docs/getting-started.md +135 -0
  24. data/docs/kill-switch.md +586 -0
  25. data/docs/screenshots/.gitkeep +1 -0
  26. data/docs/screenshots/Generate Trigger.png +0 -0
  27. data/docs/screenshots/Triggers Page.png +0 -0
  28. data/docs/screenshots/kill error.png +0 -0
  29. data/docs/screenshots/kill modal for migration down.png +0 -0
  30. data/docs/usage-guide.md +420 -0
  31. data/docs/web-ui.md +339 -0
  32. data/lib/generators/pg_sql_triggers/templates/create_pg_sql_triggers_tables.rb +1 -1
  33. data/lib/generators/pg_sql_triggers/templates/initializer.rb +36 -2
  34. data/lib/pg_sql_triggers/generator/service.rb +1 -1
  35. data/lib/pg_sql_triggers/migration.rb +1 -1
  36. data/lib/pg_sql_triggers/migrator.rb +27 -3
  37. data/lib/pg_sql_triggers/registry/manager.rb +6 -6
  38. data/lib/pg_sql_triggers/sql/kill_switch.rb +300 -0
  39. data/lib/pg_sql_triggers/testing/dry_run.rb +5 -7
  40. data/lib/pg_sql_triggers/testing/safe_executor.rb +23 -11
  41. data/lib/pg_sql_triggers/version.rb +1 -1
  42. data/lib/pg_sql_triggers.rb +12 -0
  43. data/lib/tasks/trigger_migrations.rake +33 -0
  44. metadata +35 -5
@@ -0,0 +1,541 @@
1
+ # Configuration Reference
2
+
3
+ Complete reference for configuring PgSqlTriggers in your Rails application.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Configuration File](#configuration-file)
9
+ - [Core Settings](#core-settings)
10
+ - [Kill Switch Configuration](#kill-switch-configuration)
11
+ - [Permission System](#permission-system)
12
+ - [Environment Detection](#environment-detection)
13
+ - [Advanced Configuration](#advanced-configuration)
14
+ - [Examples](#examples)
15
+
16
+ ## Overview
17
+
18
+ PgSqlTriggers is configured through an initializer file. All configuration is done within the `PgSqlTriggers.configure` block.
19
+
20
+ ## Configuration File
21
+
22
+ The default configuration file is created during installation:
23
+
24
+ ```ruby
25
+ # config/initializers/pg_sql_triggers.rb
26
+ PgSqlTriggers.configure do |config|
27
+ # Your configuration here
28
+ end
29
+ ```
30
+
31
+ ## Core Settings
32
+
33
+ ### `default_environment`
34
+
35
+ Specifies how to detect the current environment.
36
+
37
+ - **Type**: Lambda/Proc
38
+ - **Default**: `-> { Rails.env }`
39
+ - **Returns**: String or Symbol
40
+
41
+ ```ruby
42
+ config.default_environment = -> { Rails.env }
43
+
44
+ # Custom environment detection
45
+ config.default_environment = -> {
46
+ ENV['APP_ENV'] || Rails.env
47
+ }
48
+
49
+ # Static environment
50
+ config.default_environment = -> { 'production' }
51
+ ```
52
+
53
+ ### `mount_path`
54
+
55
+ Customize where the web UI is mounted (configured in routes, not initializer).
56
+
57
+ ```ruby
58
+ # config/routes.rb
59
+ Rails.application.routes.draw do
60
+ mount PgSqlTriggers::Engine, at: "/admin/triggers"
61
+ end
62
+ ```
63
+
64
+ ## Kill Switch Configuration
65
+
66
+ ### `kill_switch_enabled`
67
+
68
+ Master toggle for the kill switch system.
69
+
70
+ - **Type**: Boolean
71
+ - **Default**: `true`
72
+
73
+ ```ruby
74
+ # Enable kill switch (recommended)
75
+ config.kill_switch_enabled = true
76
+
77
+ # Disable kill switch (not recommended for production)
78
+ config.kill_switch_enabled = false
79
+ ```
80
+
81
+ ### `kill_switch_environments`
82
+
83
+ List of environments where the kill switch is active.
84
+
85
+ - **Type**: Array of Symbols
86
+ - **Default**: `[:production, :staging]`
87
+
88
+ ```ruby
89
+ # Default: protect production and staging
90
+ config.kill_switch_environments = %i[production staging]
91
+
92
+ # Protect additional environments
93
+ config.kill_switch_environments = %i[production staging qa demo]
94
+
95
+ # Only protect production
96
+ config.kill_switch_environments = [:production]
97
+
98
+ # Protect all except development
99
+ config.kill_switch_environments = %i[production staging test qa uat]
100
+ ```
101
+
102
+ ### `kill_switch_confirmation_required`
103
+
104
+ Whether confirmation text is required for overrides.
105
+
106
+ - **Type**: Boolean
107
+ - **Default**: `true`
108
+
109
+ ```ruby
110
+ # Require confirmation text (recommended)
111
+ config.kill_switch_confirmation_required = true
112
+
113
+ # Only require ENV override (less safe)
114
+ config.kill_switch_confirmation_required = false
115
+ ```
116
+
117
+ ### `kill_switch_confirmation_pattern`
118
+
119
+ Defines the format of required confirmation text.
120
+
121
+ - **Type**: Lambda/Proc
122
+ - **Parameter**: `operation` (Symbol)
123
+ - **Returns**: String
124
+ - **Default**: `->(operation) { "EXECUTE #{operation.to_s.upcase}" }`
125
+
126
+ ```ruby
127
+ # Default pattern
128
+ config.kill_switch_confirmation_pattern = ->(operation) {
129
+ "EXECUTE #{operation.to_s.upcase}"
130
+ }
131
+
132
+ # Include date
133
+ config.kill_switch_confirmation_pattern = ->(operation) {
134
+ date = Date.today.strftime('%Y%m%d')
135
+ "EXECUTE-#{operation.to_s.upcase}-#{date}"
136
+ }
137
+
138
+ # Include environment
139
+ config.kill_switch_confirmation_pattern = ->(operation) {
140
+ env = Rails.env.upcase
141
+ "#{env}-#{operation.to_s.upcase}"
142
+ }
143
+
144
+ # Custom prefix
145
+ config.kill_switch_confirmation_pattern = ->(operation) {
146
+ "CONFIRM-PRODUCTION-#{operation.to_s.upcase}"
147
+ }
148
+ ```
149
+
150
+ ### `kill_switch_logger`
151
+
152
+ Logger for kill switch events.
153
+
154
+ - **Type**: Logger instance
155
+ - **Default**: `Rails.logger`
156
+
157
+ ```ruby
158
+ # Use Rails logger (default)
159
+ config.kill_switch_logger = Rails.logger
160
+
161
+ # Separate log file
162
+ config.kill_switch_logger = Logger.new(
163
+ Rails.root.join('log', 'kill_switch.log')
164
+ )
165
+
166
+ # Custom formatter
167
+ kill_switch_logger = Logger.new(Rails.root.join('log', 'kill_switch.log'))
168
+ kill_switch_logger.formatter = proc do |severity, datetime, progname, msg|
169
+ "[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{msg}\n"
170
+ end
171
+ config.kill_switch_logger = kill_switch_logger
172
+
173
+ # Multiple destinations
174
+ require 'logger'
175
+ config.kill_switch_logger = Logger.new(STDOUT)
176
+ config.kill_switch_logger.extend(ActiveSupport::Logger.broadcast(
177
+ Logger.new(Rails.root.join('log', 'kill_switch.log'))
178
+ ))
179
+ ```
180
+
181
+ ## Permission System
182
+
183
+ ### `permission_checker`
184
+
185
+ Custom authorization logic for the web UI and API.
186
+
187
+ - **Type**: Lambda/Proc
188
+ - **Parameters**:
189
+ - `actor` (Hash): Information about who is performing the action
190
+ - `action` (Symbol): The action being performed
191
+ - `environment` (String): Current environment
192
+ - **Returns**: Boolean
193
+ - **Default**: `->(_actor, _action, _environment) { true }`
194
+
195
+ ```ruby
196
+ # Default: allow all (development only!)
197
+ config.permission_checker = ->(_actor, _action, _environment) { true }
198
+
199
+ # Basic user check
200
+ config.permission_checker = ->(actor, action, environment) {
201
+ user = User.find_by(id: actor[:id])
202
+ user.present?
203
+ }
204
+
205
+ # Role-based permissions
206
+ config.permission_checker = ->(actor, action, environment) {
207
+ user = User.find_by(id: actor[:id])
208
+ return false unless user
209
+
210
+ case action
211
+ when :view
212
+ user.present?
213
+ when :operate
214
+ user.operator? || user.admin?
215
+ when :admin
216
+ user.admin?
217
+ else
218
+ false
219
+ end
220
+ }
221
+
222
+ # Environment-specific permissions
223
+ config.permission_checker = ->(actor, action, environment) {
224
+ user = User.find_by(id: actor[:id])
225
+ return false unless user
226
+
227
+ if environment.to_s == 'production'
228
+ # Stricter in production
229
+ user.admin?
230
+ else
231
+ # More permissive in other environments
232
+ user.developer? || user.admin?
233
+ end
234
+ }
235
+
236
+ # Integration with Pundit
237
+ config.permission_checker = ->(actor, action, environment) {
238
+ user = User.find_by(id: actor[:id])
239
+ policy = PgSqlTriggersPolicy.new(user, :pg_sql_triggers)
240
+
241
+ case action
242
+ when :view
243
+ policy.read?
244
+ when :operate
245
+ policy.operate?
246
+ when :admin
247
+ policy.admin?
248
+ else
249
+ false
250
+ end
251
+ }
252
+
253
+ # Integration with CanCanCan
254
+ config.permission_checker = ->(actor, action, environment) {
255
+ user = User.find_by(id: actor[:id])
256
+ ability = Ability.new(user)
257
+
258
+ case action
259
+ when :view
260
+ ability.can?(:read, :pg_sql_triggers)
261
+ when :operate
262
+ ability.can?(:operate, :pg_sql_triggers)
263
+ when :admin
264
+ ability.can?(:admin, :pg_sql_triggers)
265
+ else
266
+ false
267
+ end
268
+ }
269
+ ```
270
+
271
+ ### Permission Levels
272
+
273
+ The permission checker should handle three levels:
274
+
275
+ #### `:view` (Read-Only)
276
+ - View triggers and status
277
+ - View migrations
278
+ - View drift information
279
+ - Access console read-only methods
280
+
281
+ #### `:operate`
282
+ - All `:view` permissions
283
+ - Enable/disable triggers
284
+ - Run migrations
285
+ - Apply generated triggers
286
+
287
+ #### `:admin`
288
+ - All `:operate` permissions
289
+ - Drop triggers
290
+ - Execute SQL capsules
291
+ - Modify registry directly
292
+
293
+ ## Environment Detection
294
+
295
+ ### Custom Environment Logic
296
+
297
+ ```ruby
298
+ # Use environment variable
299
+ config.default_environment = -> {
300
+ ENV['DEPLOYMENT_ENV'] || Rails.env
301
+ }
302
+
303
+ # Detect from hostname
304
+ config.default_environment = -> {
305
+ hostname = Socket.gethostname
306
+ case hostname
307
+ when /prod/
308
+ 'production'
309
+ when /staging/
310
+ 'staging'
311
+ else
312
+ Rails.env
313
+ end
314
+ }
315
+
316
+ # Use Rails credentials
317
+ config.default_environment = -> {
318
+ Rails.application.credentials.environment || Rails.env
319
+ }
320
+ ```
321
+
322
+ ## Advanced Configuration
323
+
324
+ ### Complete Example
325
+
326
+ ```ruby
327
+ # config/initializers/pg_sql_triggers.rb
328
+ PgSqlTriggers.configure do |config|
329
+ # Environment Detection
330
+ config.default_environment = -> { Rails.env }
331
+
332
+ # Kill Switch Settings
333
+ config.kill_switch_enabled = true
334
+ config.kill_switch_environments = %i[production staging]
335
+ config.kill_switch_confirmation_required = true
336
+
337
+ # Custom confirmation pattern with date
338
+ config.kill_switch_confirmation_pattern = ->(operation) {
339
+ date = Date.today.strftime('%Y%m%d')
340
+ "EXECUTE-#{operation.to_s.upcase}-#{date}"
341
+ }
342
+
343
+ # Dedicated kill switch logger
344
+ kill_switch_logger = Logger.new(
345
+ Rails.root.join('log', 'kill_switch.log'),
346
+ 10, # Keep 10 old log files
347
+ 1024 * 1024 * 10 # 10 MB per file
348
+ )
349
+ kill_switch_logger.formatter = proc do |severity, datetime, progname, msg|
350
+ "[#{datetime.iso8601}] [#{severity}] #{msg}\n"
351
+ end
352
+ config.kill_switch_logger = kill_switch_logger
353
+
354
+ # Role-based permission system
355
+ config.permission_checker = ->(actor, action, environment) {
356
+ user = User.find_by(id: actor[:id])
357
+ return false unless user
358
+
359
+ case action
360
+ when :view
361
+ user.has_role?(:viewer, :operator, :admin)
362
+ when :operate
363
+ user.has_role?(:operator, :admin)
364
+ when :admin
365
+ user.has_role?(:admin)
366
+ else
367
+ false
368
+ end
369
+ }
370
+ end
371
+ ```
372
+
373
+ ### Environment-Specific Configuration
374
+
375
+ ```ruby
376
+ # config/initializers/pg_sql_triggers.rb
377
+ PgSqlTriggers.configure do |config|
378
+ # Common settings
379
+ config.default_environment = -> { Rails.env }
380
+ config.kill_switch_enabled = true
381
+
382
+ # Environment-specific settings
383
+ case Rails.env.to_sym
384
+ when :production
385
+ config.kill_switch_environments = [:production]
386
+ config.kill_switch_confirmation_required = true
387
+ config.kill_switch_confirmation_pattern = ->(op) {
388
+ "PRODUCTION-EXECUTE-#{op.to_s.upcase}-#{SecureRandom.hex(2)}"
389
+ }
390
+
391
+ config.permission_checker = ->(actor, action, environment) {
392
+ user = User.find_by(id: actor[:id])
393
+ user&.admin? # Only admins in production
394
+ }
395
+
396
+ when :staging
397
+ config.kill_switch_environments = [:staging]
398
+ config.kill_switch_confirmation_required = true
399
+ config.kill_switch_confirmation_pattern = ->(op) {
400
+ "STAGING-#{op.to_s.upcase}"
401
+ }
402
+
403
+ config.permission_checker = ->(actor, action, environment) {
404
+ user = User.find_by(id: actor[:id])
405
+ user&.developer? || user&.admin?
406
+ }
407
+
408
+ when :development
409
+ config.kill_switch_environments = []
410
+ config.kill_switch_confirmation_required = false
411
+
412
+ config.permission_checker = ->(_actor, _action, _environment) { true }
413
+
414
+ when :test
415
+ config.kill_switch_enabled = false
416
+ config.permission_checker = ->(_actor, _action, _environment) { true }
417
+ end
418
+ end
419
+ ```
420
+
421
+ ## Examples
422
+
423
+ ### Production-Grade Configuration
424
+
425
+ ```ruby
426
+ PgSqlTriggers.configure do |config|
427
+ # Use Rails environment
428
+ config.default_environment = -> { Rails.env }
429
+
430
+ # Enable kill switch
431
+ config.kill_switch_enabled = true
432
+ config.kill_switch_environments = %i[production staging]
433
+ config.kill_switch_confirmation_required = true
434
+
435
+ # Date-based confirmation
436
+ config.kill_switch_confirmation_pattern = ->(operation) {
437
+ "EXECUTE-#{operation.to_s.upcase}-#{Date.today.strftime('%Y%m%d')}"
438
+ }
439
+
440
+ # Structured logging
441
+ config.kill_switch_logger = ActiveSupport::TaggedLogging.new(
442
+ Logger.new(Rails.root.join('log', 'kill_switch.log'))
443
+ )
444
+
445
+ # Integration with existing authorization
446
+ config.permission_checker = ->(actor, action, environment) {
447
+ user = User.find_by(id: actor[:id])
448
+ return false unless user
449
+
450
+ policy = PgSqlTriggersPolicy.new(user, :triggers)
451
+
452
+ case action
453
+ when :view
454
+ policy.read?
455
+ when :operate
456
+ policy.write?
457
+ when :admin
458
+ policy.admin?
459
+ else
460
+ false
461
+ end
462
+ }
463
+ end
464
+ ```
465
+
466
+ ### Development-Friendly Configuration
467
+
468
+ ```ruby
469
+ PgSqlTriggers.configure do |config|
470
+ config.default_environment = -> { Rails.env }
471
+
472
+ if Rails.env.development?
473
+ # Disabled kill switch for development
474
+ config.kill_switch_enabled = false
475
+ config.permission_checker = ->(_actor, _action, _environment) { true }
476
+ else
477
+ # Standard production settings
478
+ config.kill_switch_enabled = true
479
+ config.kill_switch_environments = %i[production staging]
480
+ config.kill_switch_confirmation_required = true
481
+
482
+ config.permission_checker = ->(actor, action, environment) {
483
+ user = User.find_by(id: actor[:id])
484
+ user&.admin?
485
+ }
486
+ end
487
+ end
488
+ ```
489
+
490
+ ### Multi-Tenant Configuration
491
+
492
+ ```ruby
493
+ PgSqlTriggers.configure do |config|
494
+ # Detect environment from tenant
495
+ config.default_environment = -> {
496
+ tenant = Apartment::Tenant.current
497
+ tenant == 'production_tenant' ? 'production' : Rails.env
498
+ }
499
+
500
+ config.kill_switch_enabled = true
501
+ config.kill_switch_environments = [:production]
502
+
503
+ # Tenant-aware permissions
504
+ config.permission_checker = ->(actor, action, environment) {
505
+ user = User.find_by(id: actor[:id])
506
+ return false unless user
507
+
508
+ tenant = Apartment::Tenant.current
509
+
510
+ # Check user has permission for current tenant
511
+ user.can_access_tenant?(tenant) && user.has_permission?(action)
512
+ }
513
+ end
514
+ ```
515
+
516
+ ## Configuration Validation
517
+
518
+ Verify your configuration is correct:
519
+
520
+ ```ruby
521
+ # In Rails console
522
+ PgSqlTriggers.configuration.kill_switch_enabled
523
+ # => true
524
+
525
+ PgSqlTriggers.configuration.kill_switch_environments
526
+ # => [:production, :staging]
527
+
528
+ PgSqlTriggers.configuration.default_environment.call
529
+ # => "development"
530
+
531
+ # Test permission checker
532
+ actor = { id: 1, type: 'console' }
533
+ PgSqlTriggers.configuration.permission_checker.call(actor, :view, 'production')
534
+ # => true or false
535
+ ```
536
+
537
+ ## Next Steps
538
+
539
+ - [Kill Switch](kill-switch.md) - Understand production safety features
540
+ - [Web UI](web-ui.md) - Configure the web interface
541
+ - [Getting Started](getting-started.md) - Initial setup guide
@@ -0,0 +1,135 @@
1
+ # Getting Started with PgSqlTriggers
2
+
3
+ This guide will help you install and set up PgSqlTriggers in your Rails application.
4
+
5
+ ## Installation
6
+
7
+ ### 1. Add the Gem
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'pg_sql_triggers'
13
+ ```
14
+
15
+ ### 2. Install Dependencies
16
+
17
+ Execute the bundle command:
18
+
19
+ ```bash
20
+ bundle install
21
+ ```
22
+
23
+ ### 3. Run the Installer
24
+
25
+ Run the installation generator:
26
+
27
+ ```bash
28
+ rails generate pg_sql_triggers:install
29
+ rails db:migrate
30
+ ```
31
+
32
+ This will:
33
+ 1. Create an initializer at `config/initializers/pg_sql_triggers.rb`
34
+ 2. Create migrations for the registry table
35
+ 3. Mount the engine at `/pg_sql_triggers`
36
+
37
+ ## Verify Installation
38
+
39
+ After installation, you should have:
40
+
41
+ - **Initializer**: `config/initializers/pg_sql_triggers.rb` with default configuration
42
+ - **Registry Table**: `pg_sql_triggers_registry` table in your database
43
+ - **Web UI**: Accessible at `http://localhost:3000/pg_sql_triggers`
44
+ - **Trigger Directory**: `db/triggers/` for storing trigger migrations
45
+
46
+ ## Quick Start Example
47
+
48
+ ### 1. Create Your First Trigger Definition
49
+
50
+ Create a trigger definition file:
51
+
52
+ ```ruby
53
+ # app/triggers/users_email_validation.rb
54
+ PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
55
+ table :users
56
+ on :insert, :update
57
+ function :validate_user_email
58
+
59
+ version 1
60
+ enabled false
61
+
62
+ when_env :production
63
+ end
64
+ ```
65
+
66
+ ### 2. Generate a Migration
67
+
68
+ Create a trigger migration to implement the function:
69
+
70
+ ```bash
71
+ rails generate trigger:migration add_email_validation
72
+ ```
73
+
74
+ Edit the generated migration in `db/triggers/`:
75
+
76
+ ```ruby
77
+ # db/triggers/YYYYMMDDHHMMSS_add_email_validation.rb
78
+ class AddEmailValidation < PgSqlTriggers::Migration
79
+ def up
80
+ execute <<-SQL
81
+ CREATE OR REPLACE FUNCTION validate_user_email()
82
+ RETURNS TRIGGER AS $$
83
+ BEGIN
84
+ IF NEW.email !~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' THEN
85
+ RAISE EXCEPTION 'Invalid email format';
86
+ END IF;
87
+ RETURN NEW;
88
+ END;
89
+ $$ LANGUAGE plpgsql;
90
+
91
+ CREATE TRIGGER user_email_validation
92
+ BEFORE INSERT OR UPDATE ON users
93
+ FOR EACH ROW
94
+ EXECUTE FUNCTION validate_user_email();
95
+ SQL
96
+ end
97
+
98
+ def down
99
+ execute <<-SQL
100
+ DROP TRIGGER IF EXISTS user_email_validation ON users;
101
+ DROP FUNCTION IF EXISTS validate_user_email();
102
+ SQL
103
+ end
104
+ end
105
+ ```
106
+
107
+ ### 3. Run the Migration
108
+
109
+ Apply the trigger migration:
110
+
111
+ ```bash
112
+ rake trigger:migrate
113
+ ```
114
+
115
+ ### 4. Access the Web UI
116
+
117
+ Open your browser and navigate to:
118
+
119
+ ```
120
+ http://localhost:3000/pg_sql_triggers
121
+ ```
122
+
123
+ You should see your trigger listed in the dashboard.
124
+
125
+ ## Next Steps
126
+
127
+ - [Usage Guide](usage-guide.md) - Learn about the DSL and migration system
128
+ - [Web UI Documentation](web-ui.md) - Explore the web dashboard features
129
+ - [Kill Switch](kill-switch.md) - Understand production safety features
130
+ - [Configuration](configuration.md) - Configure advanced settings
131
+ - [API Reference](api-reference.md) - Console commands and programmatic access
132
+
133
+ ## Examples Repository
134
+
135
+ For working examples and a complete demonstration of PgSqlTriggers in action, check out the [example repository](https://github.com/samaswin87/pg_triggers_example).