rails_claude_skills 0.1.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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.yml +134 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +11 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.yml +129 -0
  5. data/.github/ISSUE_TEMPLATE/question.yml +90 -0
  6. data/.github/dependabot.yml +19 -0
  7. data/.github/workflows/ci.yml +77 -0
  8. data/.github/workflows/release.yml +66 -0
  9. data/.rubocop.yml +52 -0
  10. data/CHANGELOG.md +94 -0
  11. data/CLAUDE.md +332 -0
  12. data/CODE_OF_CONDUCT.md +134 -0
  13. data/CONTRIBUTING.md +580 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +544 -0
  16. data/Rakefile +8 -0
  17. data/lib/generators/claude/agent/agent_generator.rb +71 -0
  18. data/lib/generators/claude/agent/templates/agent.md.tt +62 -0
  19. data/lib/generators/claude/command/command_generator.rb +50 -0
  20. data/lib/generators/claude/command/templates/command.md.tt +28 -0
  21. data/lib/generators/claude/commands_library/create-pr.md +27 -0
  22. data/lib/generators/claude/commands_library/dbchange.md +19 -0
  23. data/lib/generators/claude/commands_library/quality.md +20 -0
  24. data/lib/generators/claude/commands_library/stimulus.md +19 -0
  25. data/lib/generators/claude/commands_library/turbo-feature.md +17 -0
  26. data/lib/generators/claude/install/install_generator.rb +211 -0
  27. data/lib/generators/claude/install/templates/README.md.tt +59 -0
  28. data/lib/generators/claude/install/templates/USAGE +28 -0
  29. data/lib/generators/claude/install/templates/agents/api-dev.md.tt +46 -0
  30. data/lib/generators/claude/install/templates/agents/fullstack-dev.md.tt +48 -0
  31. data/lib/generators/claude/install/templates/agents/rails-developer.md.tt +40 -0
  32. data/lib/generators/claude/install/templates/settings.local.json.tt +13 -0
  33. data/lib/generators/claude/rule/rule_generator.rb +175 -0
  34. data/lib/generators/claude/rule/templates/rule.md.tt +7 -0
  35. data/lib/generators/claude/rules_library/code-style.md +37 -0
  36. data/lib/generators/claude/rules_library/database.md +47 -0
  37. data/lib/generators/claude/rules_library/hotwire.md +56 -0
  38. data/lib/generators/claude/rules_library/security.md +54 -0
  39. data/lib/generators/claude/rules_library/testing.md +47 -0
  40. data/lib/generators/claude/skill/skill_generator.rb +196 -0
  41. data/lib/generators/claude/skill/templates/SKILL.md.tt +27 -0
  42. data/lib/generators/claude/skills_library/create-task-files/SKILL.md +311 -0
  43. data/lib/generators/claude/skills_library/create-task-files/templates/bug.md +60 -0
  44. data/lib/generators/claude/skills_library/create-task-files/templates/epic.md +47 -0
  45. data/lib/generators/claude/skills_library/create-task-files/templates/issue.md +45 -0
  46. data/lib/generators/claude/skills_library/create-task-files/templates/user-story.md +57 -0
  47. data/lib/generators/claude/skills_library/minitest-testing/SKILL.md +398 -0
  48. data/lib/generators/claude/skills_library/minitest-testing/references/examples.md +889 -0
  49. data/lib/generators/claude/skills_library/plan-feature/SKILL.md +253 -0
  50. data/lib/generators/claude/skills_library/rails-api-controllers/SKILL.md +1041 -0
  51. data/lib/generators/claude/skills_library/rails-api-controllers/references/api-documentation.md +422 -0
  52. data/lib/generators/claude/skills_library/rails-api-controllers/references/serialization.md +456 -0
  53. data/lib/generators/claude/skills_library/rails-auth-with-devise/SKILL.md +191 -0
  54. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/advanced.md +331 -0
  55. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/api-auth.md +266 -0
  56. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/omniauth.md +194 -0
  57. data/lib/generators/claude/skills_library/rails-authorization-cancancan/SKILL.md +603 -0
  58. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/api-authorization.md +543 -0
  59. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/complex-permissions.md +572 -0
  60. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/multi-tenancy.md +373 -0
  61. data/lib/generators/claude/skills_library/rails-controllers/SKILL.md +514 -0
  62. data/lib/generators/claude/skills_library/rails-debugging/SKILL.md +260 -0
  63. data/lib/generators/claude/skills_library/rails-deployment/SKILL.md +437 -0
  64. data/lib/generators/claude/skills_library/rails-deployment/references/examples.md +901 -0
  65. data/lib/generators/claude/skills_library/rails-hotwire/SKILL.md +367 -0
  66. data/lib/generators/claude/skills_library/rails-jobs/MISSION_CONTROL_SETUP.md +639 -0
  67. data/lib/generators/claude/skills_library/rails-jobs/SKILL.md +704 -0
  68. data/lib/generators/claude/skills_library/rails-mailers/SKILL.md +549 -0
  69. data/lib/generators/claude/skills_library/rails-models/SKILL.md +379 -0
  70. data/lib/generators/claude/skills_library/rails-pagination-kaminari/SKILL.md +622 -0
  71. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/api-pagination.md +523 -0
  72. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/custom-themes.md +498 -0
  73. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/performance.md +478 -0
  74. data/lib/generators/claude/skills_library/rails-views/SKILL.md +508 -0
  75. data/lib/generators/claude/skills_library/refine-requirements/SKILL.md +226 -0
  76. data/lib/generators/claude/skills_library/refine-requirements/references/examples.md +344 -0
  77. data/lib/generators/claude/skills_library/refine-requirements/references/reference.md +298 -0
  78. data/lib/generators/claude/skills_library/rspec-testing/SKILL.md +572 -0
  79. data/lib/generators/claude/skills_library/rspec-testing/references/better_specs_guide.md +273 -0
  80. data/lib/generators/claude/skills_library/rspec-testing/references/thoughtbot_patterns.md +407 -0
  81. data/lib/generators/claude/skills_library/tailwindcss/SKILL.md +371 -0
  82. data/lib/generators/claude/views/views_generator.rb +113 -0
  83. data/lib/rails_claude_skills/railtie.rb +16 -0
  84. data/lib/rails_claude_skills/version.rb +5 -0
  85. data/lib/rails_claude_skills.rb +27 -0
  86. data/sig/rails_claude_skills.rbs +4 -0
  87. metadata +199 -0
@@ -0,0 +1,572 @@
1
+ # Complex Permissions with CanCanCan
2
+
3
+ Advanced authorization patterns for sophisticated business logic and edge cases.
4
+
5
+ ## Attribute-Level Permissions
6
+
7
+ Controlling which fields users can read or modify:
8
+
9
+ ### Read-Only Fields
10
+
11
+ ```ruby
12
+ # app/models/ability.rb
13
+ class Ability
14
+ include CanCan::Ability
15
+
16
+ def initialize(user)
17
+ return unless user.present?
18
+
19
+ # Users can update their posts
20
+ can :update, Post, user_id: user.id
21
+
22
+ # But cannot change published status
23
+ cannot :update, Post, :published unless user.admin?
24
+
25
+ # Cannot change featured status
26
+ cannot :update, Post, :featured unless user.editor?
27
+ end
28
+ end
29
+ ```
30
+
31
+ ### Controller Implementation
32
+
33
+ ```ruby
34
+ # app/controllers/posts_controller.rb
35
+ class PostsController < ApplicationController
36
+ def update
37
+ @post = Post.find(params[:id])
38
+ authorize! :update, @post
39
+
40
+ # Check specific attributes
41
+ if params[:post][:published] && cannot?(:update, @post, :published)
42
+ params[:post].delete(:published)
43
+ flash[:warning] = "You cannot change the published status"
44
+ end
45
+
46
+ if @post.update(post_params)
47
+ redirect_to @post
48
+ else
49
+ render :edit
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def post_params
56
+ permitted = [:title, :body]
57
+ permitted << :published if can?(:update, @post, :published)
58
+ permitted << :featured if can?(:update, @post, :featured)
59
+
60
+ params.require(:post).permit(*permitted)
61
+ end
62
+ end
63
+ ```
64
+
65
+ ## Conditional Permissions Based on State
66
+
67
+ ### Time-Based Editing Windows
68
+
69
+ ```ruby
70
+ # app/models/ability.rb
71
+ class Ability
72
+ include CanCan::Ability
73
+
74
+ def initialize(user)
75
+ return unless user.present?
76
+
77
+ # Can edit posts within 1 hour of creation
78
+ can :update, Post do |post|
79
+ post.user_id == user.id && post.created_at > 1.hour.ago
80
+ end
81
+
82
+ # Can delete comments within 15 minutes
83
+ can :destroy, Comment do |comment|
84
+ comment.user_id == user.id && comment.created_at > 15.minutes.ago
85
+ end
86
+
87
+ # Admins bypass time restrictions
88
+ if user.admin?
89
+ can :manage, [Post, Comment]
90
+ end
91
+ end
92
+ end
93
+ ```
94
+
95
+ ### Workflow State Permissions
96
+
97
+ ```ruby
98
+ # app/models/post.rb
99
+ class Post < ApplicationRecord
100
+ include AASM
101
+
102
+ aasm column: :status do
103
+ state :draft, initial: true
104
+ state :pending_review
105
+ state :published
106
+ state :archived
107
+
108
+ event :submit do
109
+ transitions from: :draft, to: :pending_review
110
+ end
111
+
112
+ event :publish do
113
+ transitions from: :pending_review, to: :published
114
+ end
115
+
116
+ event :archive do
117
+ transitions from: :published, to: :archived
118
+ end
119
+ end
120
+ end
121
+
122
+ # app/models/ability.rb
123
+ class Ability
124
+ include CanCan::Ability
125
+
126
+ def initialize(user)
127
+ return unless user.present?
128
+
129
+ # Authors can edit their own drafts
130
+ can :update, Post, user_id: user.id, status: 'draft'
131
+
132
+ # Can submit for review
133
+ can :submit, Post, user_id: user.id, status: 'draft'
134
+
135
+ # Editors can review and publish
136
+ if user.editor? || user.admin?
137
+ can :publish, Post, status: 'pending_review'
138
+ can :update, Post, status: 'pending_review'
139
+ end
140
+
141
+ # Only admins can archive
142
+ if user.admin?
143
+ can :archive, Post, status: 'published'
144
+ can :manage, Post, status: 'archived'
145
+ end
146
+
147
+ # Nobody can edit published posts (except admins)
148
+ cannot :update, Post, status: 'published' unless user.admin?
149
+ end
150
+ end
151
+ ```
152
+
153
+ ## Hierarchical Permissions
154
+
155
+ ### Role Hierarchy
156
+
157
+ ```ruby
158
+ # app/models/user.rb
159
+ class User < ApplicationRecord
160
+ enum role: {
161
+ viewer: 0,
162
+ contributor: 1,
163
+ editor: 2,
164
+ manager: 3,
165
+ admin: 4
166
+ }
167
+
168
+ def role_level
169
+ User.roles[role]
170
+ end
171
+
172
+ def has_role?(check_role)
173
+ role_level >= User.roles[check_role.to_s]
174
+ end
175
+ end
176
+
177
+ # app/models/ability.rb
178
+ class Ability
179
+ include CanCan::Ability
180
+
181
+ def initialize(user)
182
+ return unless user.present?
183
+
184
+ # Everyone can read published content
185
+ can :read, Post, published: true
186
+
187
+ # Viewers (level 0) - read only
188
+ can :read, Post if user.has_role?(:viewer)
189
+
190
+ # Contributors (level 1) - can create and edit own
191
+ if user.has_role?(:contributor)
192
+ can :create, Post
193
+ can [:update, :destroy], Post, user_id: user.id
194
+ end
195
+
196
+ # Editors (level 2) - can manage others' content
197
+ if user.has_role?(:editor)
198
+ can :manage, Post
199
+ can :publish, Post
200
+ end
201
+
202
+ # Managers (level 3) - can manage users
203
+ if user.has_role?(:manager)
204
+ can :manage, [Post, Comment, Category]
205
+ can :read, User
206
+ can :update, User do |target_user|
207
+ target_user.role_level < user.role_level
208
+ end
209
+ end
210
+
211
+ # Admins (level 4) - full access
212
+ can :manage, :all if user.has_role?(:admin)
213
+ end
214
+ end
215
+ ```
216
+
217
+ ## Group and Team Permissions
218
+
219
+ ```ruby
220
+ # app/models/team.rb
221
+ class Team < ApplicationRecord
222
+ has_many :team_memberships
223
+ has_many :users, through: :team_memberships
224
+ has_many :projects
225
+ end
226
+
227
+ # app/models/team_membership.rb
228
+ class TeamMembership < ApplicationRecord
229
+ belongs_to :user
230
+ belongs_to :team
231
+
232
+ enum role: { member: 0, lead: 1, owner: 2 }
233
+ end
234
+
235
+ # app/models/ability.rb
236
+ class Ability
237
+ include CanCan::Ability
238
+
239
+ def initialize(user)
240
+ return unless user.present?
241
+
242
+ # Get all teams user belongs to
243
+ team_ids = user.teams.pluck(:id)
244
+
245
+ # Can read team projects
246
+ can :read, Project, team_id: team_ids
247
+
248
+ # Can contribute to team projects
249
+ can :create, Task, project: { team_id: team_ids }
250
+ can :update, Task, project: { team_id: team_ids }, user_id: user.id
251
+
252
+ # Team leads can manage project tasks
253
+ lead_team_ids = user.team_memberships.where(role: [:lead, :owner]).pluck(:team_id)
254
+ can :manage, Task, project: { team_id: lead_team_ids }
255
+
256
+ # Team owners can manage teams
257
+ owned_team_ids = user.team_memberships.where(role: :owner).pluck(:team_id)
258
+ can :manage, Team, id: owned_team_ids
259
+ can :manage, TeamMembership, team_id: owned_team_ids
260
+ end
261
+ end
262
+ ```
263
+
264
+ ## Delegated Permissions
265
+
266
+ ### Sharing and Collaboration
267
+
268
+ ```ruby
269
+ # app/models/document.rb
270
+ class Document < ApplicationRecord
271
+ belongs_to :owner, class_name: 'User'
272
+ has_many :document_shares
273
+ has_many :shared_with_users, through: :document_shares, source: :user
274
+ end
275
+
276
+ # app/models/document_share.rb
277
+ class DocumentShare < ApplicationRecord
278
+ belongs_to :document
279
+ belongs_to :user
280
+
281
+ enum permission: { read: 0, write: 1, admin: 2 }
282
+ end
283
+
284
+ # app/models/ability.rb
285
+ class Ability
286
+ include CanCan::Ability
287
+
288
+ def initialize(user)
289
+ return unless user.present?
290
+
291
+ # Owner has full control
292
+ can :manage, Document, owner_id: user.id
293
+
294
+ # Shared documents - read permission
295
+ can :read, Document, document_shares: { user_id: user.id, permission: [:read, :write, :admin] }
296
+
297
+ # Shared documents - write permission
298
+ can :update, Document, document_shares: { user_id: user.id, permission: [:write, :admin] }
299
+
300
+ # Shared documents - admin permission (can share with others)
301
+ can :share, Document, document_shares: { user_id: user.id, permission: :admin }
302
+ end
303
+ end
304
+
305
+ # app/controllers/documents_controller.rb
306
+ class DocumentsController < ApplicationController
307
+ def share
308
+ @document = Document.find(params[:id])
309
+ authorize! :share, @document
310
+
311
+ @share = @document.document_shares.create(
312
+ user_id: params[:user_id],
313
+ permission: params[:permission]
314
+ )
315
+
316
+ redirect_to @document, notice: 'Document shared successfully'
317
+ end
318
+ end
319
+ ```
320
+
321
+ ## Conditional Abilities Based on External Services
322
+
323
+ ```ruby
324
+ # app/models/ability.rb
325
+ class Ability
326
+ include CanCan::Ability
327
+
328
+ def initialize(user, context = {})
329
+ return unless user.present?
330
+
331
+ # Check subscription status from external service
332
+ if context[:subscription_service]
333
+ subscription = context[:subscription_service].get_subscription(user.id)
334
+
335
+ case subscription.plan
336
+ when 'free'
337
+ can :create, Post
338
+ cannot :create, Post if user.posts.count >= 5 # Free tier limit
339
+ when 'pro'
340
+ can :create, Post
341
+ can :upload, :attachments
342
+ when 'enterprise'
343
+ can :manage, :all
344
+ can :access, :analytics
345
+ end
346
+ end
347
+
348
+ # Feature flags
349
+ if context[:feature_flags]
350
+ can :access, :beta_features if context[:feature_flags].enabled?(:beta_features, user)
351
+ can :use, :ai_assistant if context[:feature_flags].enabled?(:ai_assistant, user)
352
+ end
353
+ end
354
+ end
355
+
356
+ # app/controllers/application_controller.rb
357
+ def current_ability
358
+ @current_ability ||= Ability.new(current_user, {
359
+ subscription_service: SubscriptionService.new,
360
+ feature_flags: FeatureFlags.new
361
+ })
362
+ end
363
+ ```
364
+
365
+ ## IP-Based Restrictions
366
+
367
+ ```ruby
368
+ # app/models/ability.rb
369
+ class Ability
370
+ include CanCan::Ability
371
+
372
+ def initialize(user, request = nil)
373
+ return unless user.present?
374
+
375
+ can :read, Post
376
+
377
+ # Admin access only from specific IPs
378
+ if user.admin?
379
+ if request && allowed_admin_ip?(request.remote_ip)
380
+ can :manage, :all
381
+ else
382
+ can :read, :all
383
+ cannot :destroy, :all
384
+ end
385
+ end
386
+ end
387
+
388
+ private
389
+
390
+ def allowed_admin_ip?(ip)
391
+ allowed_ranges = [
392
+ IPAddr.new('10.0.0.0/8'),
393
+ IPAddr.new('172.16.0.0/12'),
394
+ IPAddr.new('192.168.0.0/16')
395
+ ]
396
+
397
+ allowed_ranges.any? { |range| range.include?(ip) }
398
+ end
399
+ end
400
+
401
+ # app/controllers/application_controller.rb
402
+ def current_ability
403
+ @current_ability ||= Ability.new(current_user, request)
404
+ end
405
+ ```
406
+
407
+ ## Performance Optimization for Complex Rules
408
+
409
+ ### Caching Abilities
410
+
411
+ ```ruby
412
+ # app/models/ability.rb
413
+ class Ability
414
+ include CanCan::Ability
415
+
416
+ def initialize(user)
417
+ return unless user.present?
418
+
419
+ # Cache expensive queries
420
+ @user_team_ids = user.teams.pluck(:id)
421
+ @user_organization_id = user.organization_id
422
+
423
+ define_permissions
424
+ end
425
+
426
+ private
427
+
428
+ def define_permissions
429
+ can :read, Project, team_id: @user_team_ids
430
+ can :read, Project, organization_id: @user_organization_id
431
+ end
432
+ end
433
+ ```
434
+
435
+ ### Eager Loading for Better Performance
436
+
437
+ ```ruby
438
+ # app/controllers/posts_controller.rb
439
+ class PostsController < ApplicationController
440
+ def index
441
+ @posts = Post
442
+ .includes(:user, :category)
443
+ .accessible_by(current_ability)
444
+ .page(params[:page])
445
+ end
446
+ end
447
+ ```
448
+
449
+ ### Using Database Views for Complex Permissions
450
+
451
+ ```ruby
452
+ # db/migrate/20240101000000_create_accessible_posts_view.rb
453
+ class CreateAccessiblePostsView < ActiveRecord::Migration[7.0]
454
+ def up
455
+ execute <<-SQL
456
+ CREATE VIEW accessible_posts AS
457
+ SELECT p.*,
458
+ u.organization_id,
459
+ CASE
460
+ WHEN p.published = true THEN true
461
+ WHEN p.user_id = u.id THEN true
462
+ WHEN EXISTS (
463
+ SELECT 1 FROM team_memberships tm
464
+ JOIN teams t ON tm.team_id = t.id
465
+ WHERE tm.user_id = u.id AND t.id = p.team_id
466
+ ) THEN true
467
+ ELSE false
468
+ END as user_can_access
469
+ FROM posts p
470
+ CROSS JOIN users u
471
+ SQL
472
+ end
473
+
474
+ def down
475
+ execute "DROP VIEW accessible_posts"
476
+ end
477
+ end
478
+ ```
479
+
480
+ ## Testing Complex Permissions
481
+
482
+ ```ruby
483
+ # spec/models/ability_spec.rb
484
+ require 'rails_helper'
485
+ require 'cancan/matchers'
486
+
487
+ RSpec.describe Ability, type: :model do
488
+ describe 'complex workflow permissions' do
489
+ let(:author) { create(:user, role: :contributor) }
490
+ let(:editor) { create(:user, role: :editor) }
491
+ let(:admin) { create(:user, role: :admin) }
492
+
493
+ let(:draft_post) { create(:post, user: author, status: :draft) }
494
+ let(:pending_post) { create(:post, user: author, status: :pending_review) }
495
+ let(:published_post) { create(:post, user: author, status: :published) }
496
+
497
+ describe 'author abilities' do
498
+ subject(:ability) { Ability.new(author) }
499
+
500
+ it { is_expected.to be_able_to(:update, draft_post) }
501
+ it { is_expected.to be_able_to(:submit, draft_post) }
502
+ it { is_expected.not_to be_able_to(:update, pending_post) }
503
+ it { is_expected.not_to be_able_to(:update, published_post) }
504
+ it { is_expected.not_to be_able_to(:publish, pending_post) }
505
+ end
506
+
507
+ describe 'editor abilities' do
508
+ subject(:ability) { Ability.new(editor) }
509
+
510
+ it { is_expected.to be_able_to(:update, pending_post) }
511
+ it { is_expected.to be_able_to(:publish, pending_post) }
512
+ it { is_expected.not_to be_able_to(:update, published_post) }
513
+ end
514
+
515
+ describe 'admin abilities' do
516
+ subject(:ability) { Ability.new(admin) }
517
+
518
+ it { is_expected.to be_able_to(:update, draft_post) }
519
+ it { is_expected.to be_able_to(:update, pending_post) }
520
+ it { is_expected.to be_able_to(:update, published_post) }
521
+ it { is_expected.to be_able_to(:archive, published_post) }
522
+ end
523
+ end
524
+
525
+ describe 'time-based permissions' do
526
+ let(:user) { create(:user) }
527
+ let(:recent_post) { create(:post, user: user, created_at: 30.minutes.ago) }
528
+ let(:old_post) { create(:post, user: user, created_at: 2.hours.ago) }
529
+
530
+ subject(:ability) { Ability.new(user) }
531
+
532
+ it { is_expected.to be_able_to(:update, recent_post) }
533
+ it { is_expected.not_to be_able_to(:update, old_post) }
534
+ end
535
+
536
+ describe 'delegated permissions' do
537
+ let(:owner) { create(:user) }
538
+ let(:viewer) { create(:user) }
539
+ let(:editor) { create(:user) }
540
+ let(:document) { create(:document, owner: owner) }
541
+
542
+ before do
543
+ create(:document_share, document: document, user: viewer, permission: :read)
544
+ create(:document_share, document: document, user: editor, permission: :write)
545
+ end
546
+
547
+ it 'grants correct permissions to shared users' do
548
+ viewer_ability = Ability.new(viewer)
549
+ editor_ability = Ability.new(editor)
550
+
551
+ expect(viewer_ability).to be_able_to(:read, document)
552
+ expect(viewer_ability).not_to be_able_to(:update, document)
553
+
554
+ expect(editor_ability).to be_able_to(:read, document)
555
+ expect(editor_ability).to be_able_to(:update, document)
556
+ end
557
+ end
558
+ end
559
+ ```
560
+
561
+ ## Best Practices
562
+
563
+ 1. **Keep it readable**: Complex logic should be well-commented
564
+ 2. **Use methods**: Extract complex conditions into well-named methods
565
+ 3. **Cache expensive queries**: Store team IDs, organization IDs in variables
566
+ 4. **Test thoroughly**: Cover all edge cases and state transitions
567
+ 5. **Document business rules**: Explain why permissions exist
568
+ 6. **Avoid over-engineering**: Start simple, add complexity only when needed
569
+ 7. **Monitor performance**: Use database indexes and eager loading
570
+ 8. **Separate concerns**: Use different ability classes for different contexts if needed
571
+ 9. **Version control**: Track permission changes in version control
572
+ 10. **Audit access**: Log permission checks for sensitive operations