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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/dscf/core/copilot-instructions.md +683 -0
- data/app/controllers/concerns/dscf/core/reviewable_controller.rb +347 -0
- data/app/controllers/dscf/credit/categories_controller.rb +3 -3
- data/app/controllers/dscf/credit/credit_lines_controller.rb +21 -13
- data/app/controllers/dscf/credit/eligible_credit_lines_controller.rb +50 -8
- data/app/controllers/dscf/credit/facilitator_applications_controller.rb +35 -0
- data/app/controllers/dscf/credit/facilitators_controller.rb +8 -96
- data/app/controllers/dscf/credit/loan_applications_controller.rb +252 -0
- data/app/controllers/dscf/credit/loan_profiles_controller.rb +61 -68
- data/app/controllers/dscf/credit/payment_requests_controller.rb +3 -5
- data/app/controllers/dscf/credit/scoring_parameters_controller.rb +59 -13
- data/app/controllers/dscf/credit/system_configs_controller.rb +30 -12
- data/app/models/concerns/core/reviewable_model.rb +31 -0
- data/app/models/dscf/credit/bank.rb +3 -3
- data/app/models/dscf/credit/bank_branch.rb +1 -1
- data/app/models/dscf/credit/category.rb +1 -2
- data/app/models/dscf/credit/credit_line.rb +4 -10
- data/app/models/dscf/credit/eligible_credit_line.rb +2 -2
- data/app/models/dscf/credit/facilitator.rb +6 -17
- data/app/models/dscf/credit/facilitator_application.rb +20 -0
- data/app/models/dscf/credit/loan_application.rb +30 -0
- data/app/models/dscf/credit/loan_profile.rb +10 -30
- data/app/models/dscf/credit/parameter_normalizer.rb +1 -1
- data/app/models/dscf/credit/scoring_parameter.rb +5 -7
- data/app/models/dscf/credit/system_config.rb +4 -9
- data/app/serializers/dscf/credit/category_serializer.rb +0 -1
- data/app/serializers/dscf/credit/credit_line_serializer.rb +2 -2
- data/app/serializers/dscf/credit/facilitator_application_serializer.rb +7 -0
- data/app/serializers/dscf/credit/facilitator_serializer.rb +3 -6
- data/app/serializers/dscf/credit/loan_application_serializer.rb +12 -0
- data/app/serializers/dscf/credit/loan_profile_serializer.rb +3 -6
- data/app/serializers/dscf/credit/scoring_parameter_serializer.rb +3 -4
- data/app/serializers/dscf/credit/system_config_serializer.rb +2 -2
- data/app/services/dscf/credit/credit_scoring_engine.rb +258 -0
- data/app/services/dscf/credit/facility_limit_calculation_engine.rb +159 -0
- data/app/services/dscf/credit/loan_profile_creation_service.rb +91 -0
- data/app/services/dscf/credit/risk_application_service.rb +61 -11
- data/config/locales/en.yml +63 -48
- data/config/routes.rb +31 -17
- data/db/migrate/20250822091131_create_dscf_credit_credit_lines.rb +1 -8
- data/db/migrate/20250822091820_create_dscf_credit_system_configs.rb +0 -7
- data/db/migrate/20250822092050_create_dscf_credit_scoring_parameters.rb +2 -6
- data/db/migrate/20250822092225_create_dscf_credit_parameter_normalizers.rb +1 -1
- data/db/migrate/20250822092236_create_dscf_credit_loan_applications.rb +20 -0
- data/db/migrate/20250822092246_create_dscf_credit_loan_profiles.rb +7 -19
- data/db/migrate/20250822092426_create_dscf_credit_facilitator_applications.rb +10 -0
- data/db/migrate/20250822092436_create_dscf_credit_facilitators.rb +1 -16
- data/db/seeds.rb +316 -203
- data/lib/dscf/credit/version.rb +1 -1
- data/spec/factories/dscf/credit/banks.rb +1 -1
- data/spec/factories/dscf/credit/credit_lines.rb +0 -23
- data/spec/factories/dscf/credit/facilitator_applications.rb +37 -0
- data/spec/factories/dscf/credit/facilitators.rb +8 -30
- data/spec/factories/dscf/credit/loan_applications.rb +42 -0
- data/spec/factories/dscf/credit/loan_profiles.rb +20 -34
- data/spec/factories/dscf/credit/parameter_normalizers.rb +4 -4
- data/spec/factories/dscf/credit/scoring_parameters.rb +14 -11
- data/spec/factories/dscf/credit/system_configs.rb +21 -5
- metadata +20 -10
- data/app/controllers/concerns/dscf/credit/reviewable.rb +0 -112
- data/app/controllers/dscf/credit/scoring_tables_controller.rb +0 -63
- data/app/models/dscf/credit/scoring_table.rb +0 -24
- data/app/serializers/dscf/credit/scoring_table_serializer.rb +0 -9
- data/db/migrate/20250901172842_create_dscf_credit_scoring_tables.rb +0 -18
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6914417c9552b795ef7f98f17f2ffbd9854c52230e2a7dcc972e2f62d48e43f1
|
4
|
+
data.tar.gz: 27aa925e0fa5dbe419c9df8f54d77c0a03b94101e81c9a61ce3daeddac1bd0a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|