dscf-credit 0.1.4 → 0.1.5

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/dscf/core/copilot-instructions.md +683 -0
  3. data/app/controllers/concerns/dscf/core/reviewable_controller.rb +347 -0
  4. data/app/controllers/dscf/credit/categories_controller.rb +3 -3
  5. data/app/controllers/dscf/credit/credit_lines_controller.rb +21 -13
  6. data/app/controllers/dscf/credit/eligible_credit_lines_controller.rb +50 -8
  7. data/app/controllers/dscf/credit/facilitator_applications_controller.rb +35 -0
  8. data/app/controllers/dscf/credit/facilitators_controller.rb +8 -96
  9. data/app/controllers/dscf/credit/loan_applications_controller.rb +252 -0
  10. data/app/controllers/dscf/credit/loan_profiles_controller.rb +61 -68
  11. data/app/controllers/dscf/credit/payment_requests_controller.rb +3 -5
  12. data/app/controllers/dscf/credit/scoring_parameters_controller.rb +59 -13
  13. data/app/controllers/dscf/credit/system_configs_controller.rb +30 -12
  14. data/app/models/concerns/core/reviewable_model.rb +31 -0
  15. data/app/models/dscf/credit/bank.rb +3 -3
  16. data/app/models/dscf/credit/bank_branch.rb +1 -1
  17. data/app/models/dscf/credit/category.rb +1 -2
  18. data/app/models/dscf/credit/credit_line.rb +4 -10
  19. data/app/models/dscf/credit/eligible_credit_line.rb +2 -2
  20. data/app/models/dscf/credit/facilitator.rb +6 -17
  21. data/app/models/dscf/credit/facilitator_application.rb +20 -0
  22. data/app/models/dscf/credit/loan_application.rb +30 -0
  23. data/app/models/dscf/credit/loan_profile.rb +10 -30
  24. data/app/models/dscf/credit/parameter_normalizer.rb +1 -1
  25. data/app/models/dscf/credit/scoring_parameter.rb +5 -7
  26. data/app/models/dscf/credit/system_config.rb +4 -9
  27. data/app/serializers/dscf/credit/category_serializer.rb +0 -1
  28. data/app/serializers/dscf/credit/credit_line_serializer.rb +2 -2
  29. data/app/serializers/dscf/credit/facilitator_application_serializer.rb +7 -0
  30. data/app/serializers/dscf/credit/facilitator_serializer.rb +3 -6
  31. data/app/serializers/dscf/credit/loan_application_serializer.rb +12 -0
  32. data/app/serializers/dscf/credit/loan_profile_serializer.rb +3 -6
  33. data/app/serializers/dscf/credit/scoring_parameter_serializer.rb +3 -4
  34. data/app/serializers/dscf/credit/system_config_serializer.rb +2 -2
  35. data/app/services/dscf/credit/credit_scoring_engine.rb +258 -0
  36. data/app/services/dscf/credit/facility_limit_calculation_engine.rb +159 -0
  37. data/app/services/dscf/credit/loan_profile_creation_service.rb +91 -0
  38. data/app/services/dscf/credit/risk_application_service.rb +61 -11
  39. data/config/locales/en.yml +63 -48
  40. data/config/routes.rb +31 -17
  41. data/db/migrate/20250822091131_create_dscf_credit_credit_lines.rb +1 -8
  42. data/db/migrate/20250822091820_create_dscf_credit_system_configs.rb +0 -7
  43. data/db/migrate/20250822092050_create_dscf_credit_scoring_parameters.rb +2 -6
  44. data/db/migrate/20250822092225_create_dscf_credit_parameter_normalizers.rb +1 -1
  45. data/db/migrate/20250822092236_create_dscf_credit_loan_applications.rb +20 -0
  46. data/db/migrate/20250822092246_create_dscf_credit_loan_profiles.rb +7 -19
  47. data/db/migrate/20250822092426_create_dscf_credit_facilitator_applications.rb +10 -0
  48. data/db/migrate/20250822092436_create_dscf_credit_facilitators.rb +1 -16
  49. data/db/seeds.rb +316 -203
  50. data/lib/dscf/credit/version.rb +1 -1
  51. data/spec/factories/dscf/credit/banks.rb +1 -1
  52. data/spec/factories/dscf/credit/credit_lines.rb +0 -23
  53. data/spec/factories/dscf/credit/facilitator_applications.rb +37 -0
  54. data/spec/factories/dscf/credit/facilitators.rb +8 -30
  55. data/spec/factories/dscf/credit/loan_applications.rb +42 -0
  56. data/spec/factories/dscf/credit/loan_profiles.rb +20 -34
  57. data/spec/factories/dscf/credit/parameter_normalizers.rb +4 -4
  58. data/spec/factories/dscf/credit/scoring_parameters.rb +14 -11
  59. data/spec/factories/dscf/credit/system_configs.rb +21 -5
  60. metadata +20 -10
  61. data/app/controllers/concerns/dscf/credit/reviewable.rb +0 -112
  62. data/app/controllers/dscf/credit/scoring_tables_controller.rb +0 -63
  63. data/app/models/dscf/credit/scoring_table.rb +0 -24
  64. data/app/serializers/dscf/credit/scoring_table_serializer.rb +0 -9
  65. data/db/migrate/20250901172842_create_dscf_credit_scoring_tables.rb +0 -18
  66. data/spec/factories/dscf/credit/scoring_tables.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c02d9169a31706be543d781e69d56a1d0bda57524ccde6c016acfe75ac42ecf
4
- data.tar.gz: 55258ca56dd7e93305b82002bfc591946d0f48f5b06469ac5fa5507e100c3e37
3
+ metadata.gz: 6914417c9552b795ef7f98f17f2ffbd9854c52230e2a7dcc972e2f62d48e43f1
4
+ data.tar.gz: 27aa925e0fa5dbe419c9df8f54d77c0a03b94101e81c9a61ce3daeddac1bd0a6
5
5
  SHA512:
6
- metadata.gz: 57e3868b428a74c8b9b0cbf10d2b4126f28e0ebf0fdef328a82b4827fc9d06627a1e89709b54a6a361ab888e679f42d903a826ad98da6863cea871ce69c415b6
7
- data.tar.gz: 7c77eaf42cfe6e0c28e3465834a52a7c410460f35fb3cd443e9b211bac50a671ecab24ad4dac1d1efa5e49987d3e3a7e43a4ddd557d8bd6f545953ac33d89b3b
6
+ metadata.gz: c7f0f12531ba3b30ec55c527f0091bd49bbb4606218a6ddbe03d45793c16a10d22e02258f6a3ea821fde1812c386fafe3f98b64590c9c074960c4cc22c0d4883
7
+ data.tar.gz: ac5a855d4322ba647a1c9439b32600eaf736253dc6397ed5eb333339e9bd901550f73fe326c4a24e87a1fd77b70cdde9558fd41bb146c7bdd779602703c18e41
@@ -0,0 +1,683 @@
1
+ # AI Coding Assistant Guidelines for DSCF Credit Engine
2
+
3
+ ## Project Overview
4
+
5
+ This is `dscf-credit`, a Rails Engine for credit scoring and loan management. It's part of the Digital Supply Chain Finance (DSCF) platform, built as a modular engine that depends on `dscf-core` for shared functionality.
6
+
7
+ ## Architecture Patterns
8
+
9
+ ### Rails Engine Structure
10
+
11
+ - **Isolated namespace**: All models/controllers under `Dscf::Credit::*`
12
+ - **Engine configuration**: Located in `lib/dscf/credit/engine.rb` with API-only config
13
+ - **Dependency**: Inherits authentication, JSON responses, and common patterns from `dscf-core`
14
+
15
+ ### Model Patterns
16
+
17
+ - **Base class**: All models inherit from `Dscf::Credit::ApplicationRecord`
18
+ - **Table naming**: Prefixed with `dscf_credit_` (e.g., `dscf_credit_loans`)
19
+ - **Polymorphic relationships**: Use `*_type` and `*_id` for flexible associations (e.g., `backer`, `reviewed_by`)
20
+ - **Ransack integration**: Always implement `ransackable_attributes` and `ransackable_associations`
21
+ - **Status enums**: Use string enums for status fields (e.g., `pending`, `approved`, `rejected`)
22
+
23
+ ### Controller Patterns
24
+
25
+ - **Base**: Inherit from `Dscf::Credit::ApplicationController`
26
+ - **Includes**: Use `Dscf::Core::Common` for standard CRUD patterns
27
+ - **Required methods**: Implement `model_params`, `eager_loaded_associations`, `allowed_order_columns`, `default_serializer_includes`
28
+ - **Reviewable workflows**: Include `Dscf::Core::ReviewableController` for approval workflows
29
+
30
+ ### External Dependencies from dscf-core
31
+
32
+ - **Authentication**: `Dscf::Core::Authenticatable` provides Bearer token auth with `current_user` access
33
+ - **JSON Response**: `Dscf::Core::JsonResponse` already included in `ApplicationController` - provides `render_success`/`render_error`
34
+ - **CRUD Operations**: `Dscf::Core::Common` provides standard index/show/create/update with pagination
35
+ - **Filtering**: `Dscf::Core::Filterable` enables Ransack-based filtering (requires `ransackable_*` methods)
36
+ - **Pagination**: Built-in pagination with `page`, `per_page`, `order_by`, `order_direction` params
37
+ - **I18n Integration**: Automatic message resolution using `{model}.{success|errors}.{action}` pattern
38
+
39
+ ### Service Patterns
40
+
41
+ - **Location**: Place in `app/services/dscf/credit/`
42
+ - **Naming**: Use `*Service` suffix (e.g., `FacilitatorCreationService`)
43
+ - **Structure**: Accept dependencies in constructor, provide public methods for operations
44
+ - **Transactions**: Wrap complex operations in `ActiveRecord::Base.transaction`
45
+
46
+ ## Development Workflows
47
+
48
+ ### Reviewable System (Core Feature)
49
+
50
+ The engine's primary feature is the `Dscf::Core::ReviewableController` system for approval workflows:
51
+
52
+ #### DSCF Review Workflow Setup
53
+
54
+ **Step 1: Include the Concerns**
55
+
56
+ ```ruby
57
+ # app/controllers/your_controller.rb
58
+ module YourEngine
59
+ class YourController < ApplicationController
60
+ include Dscf::Core::Common # ✅ For CRUD operations
61
+ include Dscf::Core::ReviewableController # ✅ For review workflow
62
+
63
+ # Your existing controller code...
64
+ end
65
+ end
66
+
67
+ # app/models/your_model.rb
68
+ module YourEngine
69
+ class YourModel < ApplicationRecord
70
+ include Dscf::Core::ReviewableModel # ✅ For review associations
71
+
72
+ # Your existing model code...
73
+ end
74
+ end
75
+ ```
76
+
77
+ **Step 2: Add Required Controller Methods**
78
+
79
+ ```ruby
80
+ # app/controllers/your_controller.rb
81
+ class YourController < ApplicationController
82
+ include Dscf::Core::Common
83
+ include Dscf::Core::ReviewableController
84
+
85
+ private
86
+
87
+ # ✅ REQUIRED: Add reviews with user_profile to eager loading
88
+ def eager_loaded_associations
89
+ [
90
+ :your_associations,
91
+ reviews: { reviewed_by: :user_profile } # ← ADD THIS
92
+ ]
93
+ end
94
+
95
+ # ✅ REQUIRED: Add reviews to serializer includes
96
+ def default_serializer_includes
97
+ {
98
+ index: [
99
+ :your_associations,
100
+ reviews: { reviewed_by: :user_profile } # ← ADD THIS
101
+ ],
102
+ show: [
103
+ :your_associations,
104
+ reviews: { reviewed_by: :user_profile } # ← ADD THIS
105
+ ],
106
+ create: [],
107
+ update: [:your_associations]
108
+ }
109
+ end
110
+
111
+ # ✅ REQUIRED: Your model params
112
+ def model_params
113
+ params.require(:your_model).permit(:field1, :field2, :field3)
114
+ end
115
+
116
+ # ✅ REQUIRED: Allowed order columns
117
+ def allowed_order_columns
118
+ %w[id name created_at updated_at]
119
+ end
120
+ end
121
+ ```
122
+
123
+ dont forget to add the serializer
124
+
125
+ ```ruby
126
+ # app/serializers/your_model_serializer.rb
127
+ class YourModelSerializer < ActiveModel::Serializer
128
+ attributes :id, :field1, :field2, :field3
129
+
130
+ # ✅ REQUIRED: Add reviews to serializer
131
+ has_many :reviews, serializer: ReviewSerializer
132
+ end
133
+ ```
134
+
135
+ **Step 3: Update Model Ransackable Associations**
136
+
137
+ ```ruby
138
+ # app/models/your_model.rb
139
+ class YourModel < ApplicationRecord
140
+ include Dscf::Core::ReviewableModel
141
+
142
+ # ✅ REQUIRED: Add reviews to ransackable associations
143
+ def self.ransackable_associations(auth_object = nil)
144
+ %w[your_associations reviews] # ← ADD 'reviews'
145
+ end
146
+ end
147
+ ```
148
+
149
+ **Step 4: Add Routes for Review Actions**
150
+
151
+ For Zero-Config (Default Actions Only):
152
+
153
+ ```ruby
154
+ # config/routes.rb
155
+ resources :your_resources do
156
+ member do
157
+ patch :approve
158
+ patch :reject
159
+ patch :request_modification
160
+ patch :resubmit
161
+ end
162
+ end
163
+ ```
164
+
165
+ For Custom Actions:
166
+
167
+ ```ruby
168
+ # config/routes.rb
169
+ resources :your_resources do
170
+ member do
171
+ # Zero-config default actions (always available)
172
+ patch :approve
173
+ patch :reject
174
+ patch :request_modification
175
+ patch :resubmit
176
+
177
+ # Your custom actions (if you define custom reviewable_context)
178
+ patch :start_review # ← ADD CUSTOM ACTIONS
179
+ patch :escalate # ← ADD CUSTOM ACTIONS
180
+ patch :your_custom_action
181
+ end
182
+ end
183
+ ```
184
+
185
+ **Step 5: Add I18n Messages**
186
+
187
+ For Default Actions (Zero-Config):
188
+
189
+ ```yaml
190
+ # config/locales/en.yml
191
+ en:
192
+ your_model: # ← Replace with your model name (lowercase, underscore)
193
+ success:
194
+ # Default actions (always needed)
195
+ approve: "Your model approved successfully"
196
+ reject: "Your model rejected successfully"
197
+ request_modification: "Modification requested for your model successfully"
198
+ resubmit: "Your model resubmitted successfully"
199
+ errors:
200
+ # Default actions (always needed)
201
+ approve: "Failed to approve your model"
202
+ reject: "Failed to reject your model"
203
+ request_modification: "Failed to request modification for your model"
204
+ resubmit: "Failed to resubmit your model"
205
+ ```
206
+
207
+ For Custom Actions and Contexts:
208
+
209
+ ```yaml
210
+ # config/locales/en.yml
211
+ en:
212
+ your_model:
213
+ success:
214
+ # Default actions
215
+ approve: "Your model approved successfully"
216
+ reject: "Your model rejected successfully"
217
+ request_modification: "Modification requested successfully"
218
+ resubmit: "Your model resubmitted successfully"
219
+
220
+ # ✅ ADD: Custom actions based on your reviewable_context
221
+ start_review: "Review started for your model successfully"
222
+ escalate: "Your model escalated successfully"
223
+ your_custom_action: "Custom action completed successfully"
224
+
225
+ errors:
226
+ # Default actions
227
+ approve: "Failed to approve your model"
228
+ reject: "Failed to reject your model"
229
+ request_modification: "Failed to request modification"
230
+ resubmit: "Failed to resubmit your model"
231
+
232
+ # ✅ ADD: Custom actions based on your reviewable_context
233
+ start_review: "Failed to start review for your model"
234
+ escalate: "Failed to escalate your model"
235
+ your_custom_action: "Failed to complete custom action"
236
+ ```
237
+
238
+ #### Zero-Config Default Context
239
+
240
+ Including `Dscf::Core::ReviewableController` automatically provides default actions:
241
+
242
+ - `approve` (pending → approved)
243
+ - `reject` (pending → rejected, requires feedback)
244
+ - `request_modification` (pending → modify, requires feedback)
245
+ - `resubmit` (modify → pending, can update model)
246
+
247
+ #### Custom Contexts
248
+
249
+ Define custom review workflows with `reviewable_context`:
250
+
251
+ ```ruby
252
+ # Multiple contexts supported
253
+ reviewable_context :compliance,
254
+ statuses: %w[pending_review verified non_compliant needs_documents],
255
+ initial_status: "pending_review",
256
+ transitions: {
257
+ "pending_review" => %w[verified non_compliant needs_documents],
258
+ "needs_documents" => %w[pending_review]
259
+ },
260
+ actions: {
261
+ verify: { status: "verified" },
262
+ mark_non_compliant: { status: "non_compliant", require_feedback: true },
263
+ request_documents: { status: "needs_documents", require_feedback: true },
264
+ resubmit: { status: "pending_review", update_model: true }
265
+ }
266
+ ```
267
+
268
+ #### API Endpoints and Context Switching
269
+
270
+ - Default context: `/banks/123/approve`
271
+ - Custom context: `/banks/123/verify?context=compliance`
272
+ - Feedback structure: `{ "review_feedback": { "message": "...", "field": "..." } }`
273
+
274
+ #### Required I18n Messages
275
+
276
+ Auto-resolves using pattern: `{model}.{success|errors}.{action}`
277
+
278
+ ```yaml
279
+ bank:
280
+ success:
281
+ verify: "Bank verified successfully"
282
+ errors:
283
+ verify: "Failed to verify bank"
284
+ ```
285
+
286
+ ### Testing with reviewable_request_spec
287
+
288
+ Use the specialized shared example for testing reviewable controllers:
289
+
290
+ ```ruby
291
+ # Test built-in default actions only
292
+ it_behaves_like "reviewable_request_spec", "categories", {
293
+ review_contexts: {
294
+ default: true
295
+ }
296
+ }
297
+
298
+ # Test customized default context
299
+ it_behaves_like "reviewable_request_spec", "banks", {
300
+ review_contexts: {
301
+ default: {
302
+ statuses: %w[pending approved rejected modify revise],
303
+ actions: { /* custom actions */ }
304
+ }
305
+ }
306
+ }
307
+
308
+ # Test multiple custom contexts
309
+ it_behaves_like "reviewable_request_spec", "banks", {
310
+ review_contexts: {
311
+ compliance: { /* config */ },
312
+ audit: { /* config */ }
313
+ }
314
+ }
315
+ ```
316
+
317
+ **Required setup:**
318
+
319
+ - Include `with authenticated_user` context
320
+ - Define `new_attributes` for `update_model` actions
321
+ - Add I18n messages for all custom actions
322
+
323
+ ### Testing
324
+
325
+ - **Framework**: RSpec with FactoryBot for fixtures
326
+ - **Shared examples**: Use `request_shared_spec` for standard CRUD testing and `reviewable_request_spec` for reviewable workflows
327
+ - **Authentication**: Include `with authenticated_user` context for request specs
328
+ - **Factories**: Located in `spec/factories/dscf/credit/` with traits for different states
329
+
330
+ ### Development Workflow Tips
331
+
332
+ - **Common Generator**: Use `rails generate common ModelName` to scaffold complete API resources
333
+ - **Yield Blocks**: Override Common module actions using `super` pattern for custom logic
334
+ - **Message Resolution**: System automatically resolves I18n keys - no manual message keys needed
335
+ - **Security**: Always implement `ransackable_attributes` and `ransackable_associations` for filtering
336
+ - **Reviewable Testing**: Use `reviewable_request_spec` with `default: true` for built-in workflows or full config for custom contexts
337
+
338
+ ### Database Conventions
339
+
340
+ - **Migrations**: Prefix with `dscf_credit_` and include comprehensive indexing
341
+ - **Precision**: Use `precision: 15, scale: 2` for monetary amounts
342
+ - **Foreign keys**: Explicitly name foreign key tables (e.g., `foreign_key: { to_table: :dscf_credit_banks }`)
343
+ - **JSONB**: Use for flexible data storage (e.g., `metadata`, `review_feedback`)
344
+
345
+ ### Key Commands
346
+
347
+ ```bash
348
+ # Run tests
349
+ bundle exec rspec
350
+
351
+ # Generate migration
352
+ rails generate migration CreateDscfCreditModelName
353
+
354
+ # Generate complete API resource with Common module
355
+ rails generate common Dscf::Credit::ModelName
356
+
357
+ # Generate only specific components
358
+ rails generate common ModelName --only controller serializer
359
+ rails generate common ModelName --skip routes locales
360
+
361
+ # Run engine in dummy app context
362
+ cd spec/dummy && rails console
363
+
364
+ # Install gem locally
365
+ gem build dscf-credit.gemspec && gem install dscf-credit-*.gem
366
+ ```
367
+
368
+ ## Core Dependencies Deep Dive
369
+
370
+ ### Dscf::Core::Common Module
371
+
372
+ Provides standardized CRUD with automatic model resolution and I18n integration:
373
+
374
+ ```ruby
375
+ # Automatic model resolution
376
+ # Controller: Dscf::Credit::LoansController → Model: Dscf::Credit::Loan
377
+ # Fallback: Dscf::Core::Loan if credit model doesn't exist
378
+
379
+ def index
380
+ # Built-in features:
381
+ # - Pagination with metadata when ?page= param present
382
+ # - Ransack filtering with whitelisted attributes
383
+ # - Eager loading via eager_loaded_associations
384
+ # - Automatic I18n message resolution
385
+ # - Serializer includes based on action
386
+
387
+ # Custom logic with yield blocks
388
+ super do
389
+ loans = Loan.active.includes(:bank)
390
+ options = { include: [:bank, :user] }
391
+ [loans, options] # Return [data, serializer_options]
392
+ end
393
+ end
394
+
395
+ def create
396
+ # Automatic validation and error handling
397
+ # Uses model_params for strong parameters
398
+ # Automatically reloads with eager_loaded_associations
399
+ # Resolves I18n messages: "loan.success.create" or "loan.errors.create"
400
+ end
401
+ ```
402
+
403
+ ### Yield Block Customization Patterns
404
+
405
+ ```ruby
406
+ # Pattern 1: Custom data only
407
+ def index
408
+ super do
409
+ User.active.verified # Return custom ActiveRecord::Relation
410
+ end
411
+ end
412
+
413
+ # Pattern 2: Custom data with options
414
+ def show
415
+ super do
416
+ options = {
417
+ include: [:profile, :roles],
418
+ meta: { last_login: @obj.last_login_at }
419
+ }
420
+ [@obj, options] # Return [data, serializer_options]
421
+ end
422
+ end
423
+
424
+ # Pattern 3: Hash options only (uses default data)
425
+ def index
426
+ super do
427
+ { include: [:profile], meta: { total: User.count } }
428
+ end
429
+ end
430
+ ```
431
+
432
+ ### Required Controller Methods
433
+
434
+ All controllers using `Dscf::Core::Common` must implement:
435
+
436
+ ```ruby
437
+ private
438
+
439
+ def model_params
440
+ # Strong parameters for the model
441
+ params.require(:loan).permit(:amount, :status, :due_date)
442
+ end
443
+
444
+ def eager_loaded_associations
445
+ # Associations to preload for N+1 query prevention
446
+ [:loan_profile, :credit_line, :payment_request]
447
+ end
448
+
449
+ def allowed_order_columns
450
+ # Whitelisted columns for sorting (security)
451
+ %w[id amount status due_date created_at updated_at]
452
+ end
453
+
454
+ def default_serializer_includes
455
+ # Action-specific includes for serialization
456
+ {
457
+ index: [:loan_profile, :credit_line],
458
+ show: [:loan_profile, :credit_line, :loan_transactions],
459
+ create: [:loan_profile, :credit_line],
460
+ update: [:loan_profile, :credit_line]
461
+ }
462
+ end
463
+ ```
464
+
465
+ ### Dscf::Core::JsonResponse Patterns
466
+
467
+ Standardized API responses with automatic I18n message resolution:
468
+
469
+ ```ruby
470
+ # Automatic message resolution using locale keys
471
+ # Pattern: {model}.{success|errors}.{action}
472
+ # Example: bank.success.create, facilitator.errors.approve
473
+
474
+ # Success with automatic message
475
+ render_success(data: @loan)
476
+ # Looks for: "loan.success.{action_name}" in config/locales/en.yml
477
+
478
+ # Success with explicit message key
479
+ render_success(
480
+ "operations.success.completed",
481
+ data: @loan,
482
+ serializer_options: { include: [:loan_profile, :credit_line] }
483
+ )
484
+
485
+ # Error with automatic message
486
+ render_error(
487
+ errors: @loan.errors.full_messages[0],
488
+ status: :unprocessable_entity
489
+ )
490
+ # Looks for: "loan.errors.{action_name}" in config/locales/en.yml
491
+
492
+ # Error with explicit message key
493
+ render_error(
494
+ "errors.validation_failed",
495
+ errors: @loan.errors.full_messages,
496
+ status: :unprocessable_entity
497
+ )
498
+
499
+ # Response format with pagination metadata
500
+ {
501
+ "success": true,
502
+ "message": "Loans retrieved successfully",
503
+ "data": [...],
504
+ "pagination": {
505
+ "current_page": 1,
506
+ "per_page": 10,
507
+ "total_count": 150,
508
+ "total_pages": 15,
509
+ "links": {
510
+ "first": "/loans?page=1",
511
+ "prev": null,
512
+ "next": "/loans?page=2",
513
+ "last": "/loans?page=15"
514
+ }
515
+ }
516
+ }
517
+ ```
518
+
519
+ ### I18n Message Configuration
520
+
521
+ Define messages in `config/locales/en.yml` following the pattern:
522
+
523
+ ```yaml
524
+ en:
525
+ model_name:
526
+ success:
527
+ index: "Model retrieved successfully"
528
+ show: "Model details retrieved successfully"
529
+ create: "Model created successfully"
530
+ update: "Model updated successfully"
531
+ # Reviewable actions
532
+ approve: "Model approved successfully"
533
+ reject: "Model rejected successfully"
534
+ request_modification: "Modification requested for model successfully"
535
+ resubmit: "Model resubmitted successfully"
536
+ errors:
537
+ create: "Failed to create model"
538
+ update: "Failed to update model"
539
+ # Reviewable actions
540
+ approve: "Failed to approve model"
541
+ reject: "Failed to reject model"
542
+ request_modification: "Failed to request modification for model"
543
+ resubmit: "Failed to resubmit model"
544
+ ```
545
+
546
+ ### Dscf::Core::Filterable Security
547
+
548
+ Ransack integration with mandatory attribute whitelisting:
549
+
550
+ ```ruby
551
+ # REQUIRED in all models for security
552
+ def self.ransackable_attributes(auth_object = nil)
553
+ %w[id status amount created_at updated_at] # Explicit whitelist
554
+ end
555
+
556
+ def self.ransackable_associations(auth_object = nil)
557
+ %w[bank user loan_profile] # Explicit whitelist
558
+ end
559
+
560
+ # Common Ransack predicates
561
+ # _eq (equals), _cont (contains), _start (starts with), _end (ends with)
562
+ # _gt/_gteq (greater than/equal), _lt/_lteq (less than/equal)
563
+ # _in (in array), _null/_not_null (is/isn't null)
564
+
565
+ # API usage examples
566
+ GET /loans?q[status_eq]=active&q[amount_gteq]=1000
567
+ GET /loans?q[user_email_cont]=john&q[created_at_gteq]=2023-01-01
568
+ GET /loans?q[status_in][]=active&q[status_in][]=pending
569
+ ```
570
+
571
+ ### Authentication Integration
572
+
573
+ Bearer token authentication from dscf-core:
574
+
575
+ ```ruby
576
+ # Automatic in ApplicationController
577
+ include Dscf::Core::Authenticatable
578
+
579
+ # Provides:
580
+ # - current_user method
581
+ # - Authentication verification
582
+ # - Token parsing from Authorization header
583
+
584
+ # Test context
585
+ include_context "with authenticated_user" # Provides auth_user and headers
586
+ ```
587
+
588
+ ### API Response Standards
589
+
590
+ All API responses follow this format:
591
+
592
+ ```ruby
593
+ # Success Response
594
+ {
595
+ "success": true,
596
+ "message": "Resource created successfully", # From I18n or explicit
597
+ "data": { ... }, # Serialized data
598
+ "pagination": { ... } # If paginated
599
+ }
600
+
601
+ # Error Response
602
+ {
603
+ "success": false,
604
+ "error": "Failed to create resource", # From I18n or explicit
605
+ "errors": ["Validation error messages"] # Array of specific errors
606
+ }
607
+ ```
608
+
609
+ ### Controller Implementation Template
610
+
611
+ ```ruby
612
+ module Dscf::Credit
613
+ class ExampleController < ApplicationController
614
+ include Dscf::Core::Common
615
+ include Dscf::Credit::Reviewable # If approval workflow needed
616
+
617
+ private
618
+
619
+ def model_params
620
+ params.require(:example).permit(:attr1, :attr2)
621
+ end
622
+
623
+ def eager_loaded_associations
624
+ [:association1, :association2]
625
+ end
626
+
627
+ def allowed_order_columns
628
+ %w[id name status created_at updated_at]
629
+ end
630
+
631
+ def default_serializer_includes
632
+ {
633
+ index: [:association1],
634
+ show: [:association1, :association2],
635
+ create: [:association1],
636
+ update: [:association1, :association2]
637
+ }
638
+ end
639
+ end
640
+ end
641
+ ```
642
+
643
+ ### Model Implementation Template
644
+
645
+ ```ruby
646
+ module Dscf::Credit
647
+ class Example < ApplicationRecord
648
+ self.table_name = "dscf_credit_examples"
649
+
650
+ # Associations with explicit class names
651
+ belongs_to :bank, class_name: "Dscf::Credit::Bank"
652
+ has_many :items, class_name: "Dscf::Credit::Item", dependent: :destroy
653
+
654
+ # Validations
655
+ validates :status, inclusion: { in: %w[pending approved rejected] }
656
+ validates :amount, numericality: { greater_than: 0 }
657
+
658
+ # Scopes
659
+ scope :active, -> { where(status: "approved") }
660
+
661
+ # Ransack configuration
662
+ def self.ransackable_attributes(auth_object = nil)
663
+ %w[id status amount created_at updated_at]
664
+ end
665
+
666
+ def self.ransackable_associations(auth_object = nil)
667
+ %w[bank items]
668
+ end
669
+ end
670
+ end
671
+ ```
672
+
673
+ ### Critical Files to Reference
674
+
675
+ - `app/controllers/dscf/credit/application_controller.rb` - Base controller pattern
676
+ - `app/models/dscf/credit/loan.rb` - Complex model with multiple associations
677
+ - `app/controllers/concerns/dscf/core/reviewable_controller.rb` - Review workflow implementation
678
+ - `spec/support/requests/shared_examples.rb` - Test patterns with `request_shared_spec`
679
+ - `spec/support/requests/reviewable_controller_spec.rb` - Reviewable testing with `reviewable_request_spec`
680
+ - `spec/support/shared_context/authenticated_user.rb` - Authentication setup
681
+ - `config/routes.rb` - Engine routing patterns with member actions for approvals
682
+ - `docs/REVIEWABLE_REQUEST_SPEC_DOCUMENTATION.md` - Comprehensive testing guide for reviewable controllers
683
+ - `docs/docs/CORE_CONCERNS_DOCUMENTATION.md` - Detailed dscf-core dependency patterns