rider-kick 0.0.13 → 0.0.14

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +629 -25
  3. data/lib/generators/rider_kick/USAGE +2 -0
  4. data/lib/generators/rider_kick/base_generator.rb +190 -0
  5. data/lib/generators/rider_kick/clean_arch_generator.rb +235 -45
  6. data/lib/generators/rider_kick/clean_arch_generator_engine_spec.rb +359 -0
  7. data/lib/generators/rider_kick/clean_arch_generator_factory_bot_spec.rb +131 -0
  8. data/lib/generators/rider_kick/entity_type_mapping_spec.rb +22 -13
  9. data/lib/generators/rider_kick/errors.rb +42 -0
  10. data/lib/generators/rider_kick/factory_generator.rb +238 -0
  11. data/lib/generators/rider_kick/factory_generator_spec.rb +175 -0
  12. data/lib/generators/rider_kick/repositories_contract_spec.rb +95 -22
  13. data/lib/generators/rider_kick/scaffold_generator.rb +377 -62
  14. data/lib/generators/rider_kick/scaffold_generator_builder_uploaders_spec.rb +119 -14
  15. data/lib/generators/rider_kick/scaffold_generator_conditional_filtering_spec.rb +820 -0
  16. data/lib/generators/rider_kick/scaffold_generator_contracts_spec.rb +37 -10
  17. data/lib/generators/rider_kick/scaffold_generator_contracts_with_scope_spec.rb +40 -11
  18. data/lib/generators/rider_kick/scaffold_generator_engine_spec.rb +221 -0
  19. data/lib/generators/rider_kick/scaffold_generator_idempotent_spec.rb +38 -13
  20. data/lib/generators/rider_kick/scaffold_generator_list_spec_format_spec.rb +153 -0
  21. data/lib/generators/rider_kick/scaffold_generator_rspec_spec.rb +347 -0
  22. data/lib/generators/rider_kick/scaffold_generator_success_spec.rb +31 -12
  23. data/lib/generators/rider_kick/scaffold_generator_with_scope_spec.rb +32 -11
  24. data/lib/generators/rider_kick/structure_generator.rb +154 -43
  25. data/lib/generators/rider_kick/structure_generator_comprehensive_spec.rb +598 -0
  26. data/lib/generators/rider_kick/structure_generator_engine_spec.rb +279 -0
  27. data/lib/generators/rider_kick/structure_generator_spec.rb +3 -3
  28. data/lib/generators/rider_kick/structure_generator_success_spec.rb +33 -5
  29. data/lib/generators/rider_kick/structure_generator_unit_spec.rb +2202 -0
  30. data/lib/generators/rider_kick/templates/.rubocop.yml +5 -4
  31. data/lib/generators/rider_kick/templates/config/initializers/version.rb.tt +1 -1
  32. data/lib/generators/rider_kick/templates/db/migrate/20220613145533_init_database.rb +1 -1
  33. data/lib/generators/rider_kick/templates/db/structures/example.yaml.tt +140 -66
  34. data/lib/generators/rider_kick/templates/domains/core/builders/builder.rb.tt +36 -10
  35. data/lib/generators/rider_kick/templates/domains/core/builders/builder_spec.rb.tt +219 -0
  36. data/lib/generators/rider_kick/templates/domains/core/builders/error.rb.tt +2 -2
  37. data/lib/generators/rider_kick/templates/domains/core/builders/pagination.rb.tt +2 -2
  38. data/lib/generators/rider_kick/templates/domains/core/entities/entity.rb.tt +32 -14
  39. data/lib/generators/rider_kick/templates/domains/core/entities/error.rb.tt +1 -1
  40. data/lib/generators/rider_kick/templates/domains/core/entities/pagination.rb.tt +1 -1
  41. data/lib/generators/rider_kick/templates/domains/core/repositories/abstract_repository.rb.tt +4 -4
  42. data/lib/generators/rider_kick/templates/domains/core/repositories/create.rb.tt +2 -2
  43. data/lib/generators/rider_kick/templates/domains/core/repositories/create_spec.rb.tt +78 -0
  44. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy.rb.tt +2 -2
  45. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy_spec.rb.tt +88 -0
  46. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id.rb.tt +3 -3
  47. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id_spec.rb.tt +62 -0
  48. data/lib/generators/rider_kick/templates/domains/core/repositories/list.rb.tt +13 -8
  49. data/lib/generators/rider_kick/templates/domains/core/repositories/list_spec.rb.tt +190 -0
  50. data/lib/generators/rider_kick/templates/domains/core/repositories/update.rb.tt +4 -4
  51. data/lib/generators/rider_kick/templates/domains/core/repositories/update_spec.rb.tt +119 -0
  52. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/default.rb.tt +1 -1
  53. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/pagination.rb.tt +1 -1
  54. data/lib/generators/rider_kick/templates/domains/core/use_cases/create.rb.tt +3 -7
  55. data/lib/generators/rider_kick/templates/domains/core/use_cases/create_spec.rb.tt +71 -0
  56. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy.rb.tt +3 -7
  57. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy_spec.rb.tt +62 -0
  58. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id.rb.tt +3 -7
  59. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id_spec.rb.tt +62 -0
  60. data/lib/generators/rider_kick/templates/domains/core/use_cases/get_version.rb.tt +2 -2
  61. data/lib/generators/rider_kick/templates/domains/core/use_cases/list.rb.tt +3 -7
  62. data/lib/generators/rider_kick/templates/domains/core/use_cases/list_spec.rb.tt +64 -0
  63. data/lib/generators/rider_kick/templates/domains/core/use_cases/update.rb.tt +3 -7
  64. data/lib/generators/rider_kick/templates/domains/core/use_cases/update_spec.rb.tt +73 -0
  65. data/lib/generators/rider_kick/templates/domains/core/utils/abstract_utils.rb.tt +3 -3
  66. data/lib/generators/rider_kick/templates/domains/core/utils/request_methods.rb.tt +1 -1
  67. data/lib/generators/rider_kick/templates/env.development +1 -1
  68. data/lib/generators/rider_kick/templates/env.production +1 -1
  69. data/lib/generators/rider_kick/templates/env.test +1 -1
  70. data/lib/generators/rider_kick/templates/models/{application_record.rb → application_record.rb.tt} +3 -1
  71. data/lib/generators/rider_kick/templates/models/model_spec.rb.tt +68 -0
  72. data/lib/generators/rider_kick/templates/spec/factories/.gitkeep +19 -0
  73. data/lib/generators/rider_kick/templates/spec/factories/factory.rb.tt +8 -0
  74. data/lib/generators/rider_kick/templates/spec/rails_helper.rb +2 -0
  75. data/lib/generators/rider_kick/templates/spec/support/class_stubber.rb +148 -0
  76. data/lib/generators/rider_kick/templates/spec/support/factory_bot.rb +34 -0
  77. data/lib/generators/rider_kick/templates/spec/support/faker.rb +61 -0
  78. data/lib/rider-kick.rb +8 -6
  79. data/lib/rider_kick/builders/abstract_active_record_entity_builder_spec.rb +644 -0
  80. data/lib/rider_kick/configuration.rb +238 -0
  81. data/lib/rider_kick/configuration_engine_spec.rb +377 -0
  82. data/lib/rider_kick/entities/failure_details.rb +1 -1
  83. data/lib/rider_kick/entities/failure_details_spec.rb +1 -1
  84. data/lib/rider_kick/matchers/use_case_result.rb +1 -1
  85. data/lib/rider_kick/use_cases/abstract_use_case.rb +1 -1
  86. data/lib/rider_kick/version.rb +1 -1
  87. metadata +129 -8
  88. data/CHANGELOG.md +0 -5
data/README.md CHANGED
@@ -1,18 +1,32 @@
1
1
  # RiderKick
2
2
  Rails generators for **Clean Architecture** on the backend: use cases, entities, repositories, builders, and utilities — organized for clarity and designed for speed.
3
3
 
4
+ > **🎉 NEW!** Domain scoping dengan `--domain` option! Organize domain files ke dalam scope yang berbeda (core/, admin/, api/v1/, dll.)
5
+ >
6
+ > **🎉 NEW!** Sekarang dengan automatic RSpec generation! Setiap file yang di-generate otomatis mendapat spec file-nya. [Lihat dokumentasi lengkap](SPEC_GENERATION.md)
7
+ >
8
+ > **🎉 NEW!** FactoryBot factory generator dengan smart Faker generation! [Lihat dokumentasi lengkap](FACTORY_GENERATOR.md)
9
+
4
10
  This gem provides helper interfaces and classes to assist in the construction of application with
5
11
  Clean Architecture, as described in [Robert Martin's seminal book](https://www.amazon.com/gp/product/0134494164).
6
12
  ---
7
13
  ## Features
8
14
 
9
- - **Clean Architecture scaffolding**
10
- Creates `app/domains` with `entities/`, `use_cases/`, `repositories/`, `builders/`, and `utils/`.
11
- - **Use-case-first “screaming architecture”**
15
+ - **Clean Architecture scaffolding**
16
+ Creates `app/domains/<domain>/` with `entities/`, `use_cases/`, `repositories/`, `builders/`, and `utils/`.
17
+ - **Domain scoping dengan --domain option** 🆕
18
+ Organize domain files ke dalam scope yang berbeda: `--domain core/`, `--domain admin/`, `--domain api/v1/`, dll.
19
+ - **Engine support dengan --engine option**
20
+ Generate domain files dalam Rails engines: `--engine MyEngine --domain admin/`
21
+ - **Use-case-first "screaming architecture"**
12
22
  Encourages file names like `[role]_[action]_[subject].rb` for immediate intent (e.g., `admin_update_stock.rb`).
13
- - **Rails-native generators**
23
+ - **Rails-native generators**
14
24
  Pragmatic commands for bootstrapping domain structure and scaffolding.
15
- - **Idempotent, minimal friction**
25
+ - **Automatic RSpec generation** 🆕
26
+ Generates comprehensive RSpec files for all generated code (use cases, repositories, builders, entities).
27
+ - **FactoryBot factory generator** 🆕
28
+ Generates smart FactoryBot factories with automatic Faker values and foreign key skipping.
29
+ - **Idempotent, minimal friction**
16
30
  Safe to run more than once; prefers appending or no-ops over destructive changes.
17
31
  ---
18
32
  ## ✅ Compatibility
@@ -30,9 +44,25 @@ And then execute:
30
44
  $ bundle add rider-kick
31
45
  $ rails generate rider_kick:clean_arch --setup
32
46
  $ rails db:drop db:create db:migrate db:seed
33
- $ rails g model models/products name price:decimal is_published:boolean
47
+ $ rails g model models/products name price:decimal is_published:boolean
34
48
  $ rails generate rider_kick:structure Models::Product actor:owner
35
- $ rails generate rider_kick:scaffold products scope:dashboard
49
+ $ rails generate rider_kick:scaffold products scope:dashboard
50
+ ```
51
+
52
+ ### Quick Examples with Domain Scoping
53
+
54
+ ```bash
55
+ # Setup dengan domain default (core/)
56
+ $ rails generate rider_kick:clean_arch --setup
57
+
58
+ # Setup untuk admin domain
59
+ $ rails generate rider_kick:clean_arch --setup --domain admin/
60
+
61
+ # Setup untuk API v1 domain
62
+ $ rails generate rider_kick:clean_arch --setup --domain api/v1/
63
+
64
+ # Setup dalam Rails engine
65
+ $ rails generate rider_kick:clean_arch --setup --engine MyEngine --domain mobile/
36
66
  ```
37
67
  ### OPTIONAL
38
68
  ```bash
@@ -40,30 +70,558 @@ And then execute:
40
70
  ```
41
71
  ---
42
72
  ## Usage
73
+
74
+ ### Initial Setup (Required Once)
75
+
76
+ #### Basic Setup (Default Domain)
77
+ ```bash
78
+ # 1. Create new Rails app
79
+ rails new kotaro_minami -d=postgresql -T --skip-javascript --skip-asset-pipeline
80
+
81
+ # 2. Add rider-kick gem
82
+ bundle add rider-kick
83
+
84
+ # 3. Setup Clean Architecture structure (includes RSpec setup & helpers)
85
+ bin/rails generate rider_kick:clean_arch --setup
86
+ ```
87
+
88
+ #### Advanced Setup with Domain Scoping
89
+
43
90
  ```bash
44
- Description:
45
- Clean Architecture generator
46
- rails new kotaro_minami -d=postgresql -T --skip-javascript --skip-asset-pipeline
47
-
48
- Example:
49
- To Generate scaffold:
50
- bin/rails generate rider_kick:clean_arch --setup
51
- bin/rails generate rider_kick:structure Models::User actor:owner
52
- bin/rails generate rider_kick:scaffold users scope:dashboard
91
+ # Setup untuk domain tertentu
92
+ bin/rails generate rider_kick:clean_arch --setup --domain admin/
93
+
94
+ # Setup untuk API domain
95
+ bin/rails generate rider_kick:clean_arch --setup --domain api/v1/
96
+
97
+ # Setup dalam Rails engine
98
+ bin/rails generate rider_kick:clean_arch --setup --engine MyEngine --domain core/
99
+
100
+ # Setup engine dengan domain khusus
101
+ bin/rails generate rider_kick:clean_arch --setup --engine AdminEngine --domain admin/
102
+ ```
103
+
104
+ ### Domain Scoping Explanation
105
+
106
+ **--domain option** memungkinkan Anda mengorganisir domain files ke dalam scope yang berbeda:
107
+
108
+ - **Default**: `--domain core/` → `app/domains/core/`
109
+ - **Admin domain**: `--domain admin/` → `app/domains/admin/`
110
+ - **API domain**: `--domain api/v1/` → `app/domains/api/v1/`
111
+ - **Engine**: `--engine MyEngine --domain mobile/` → `engines/my_engine/app/domains/mobile/`
112
+
113
+ ### Setup Output
53
114
 
115
+ This setup will create:
116
+ - Domain structure (`app/domains/<domain>/` or `engines/<engine>/app/domains/<domain>/`)
117
+ - RSpec configuration with helpers (`spec/support/class_stubber.rb`, etc.)
118
+ - Database configuration
119
+ - Initializers
120
+
121
+ #### Generated Structure Examples
122
+
123
+ **Main App dengan domain default:**
124
+ ```
125
+ app/
126
+ domains/
127
+ core/ # --domain core/ (default)
128
+ entities/
129
+ builders/
130
+ repositories/
131
+ use_cases/
132
+ utils/
133
+ ```
134
+
135
+ **Main App dengan multiple domains:**
136
+ ```
137
+ app/
138
+ domains/
139
+ core/ # --domain core/
140
+ admin/ # --domain admin/
141
+ api/
142
+ v1/ # --domain api/v1/
143
+ ```
144
+
145
+ **Rails Engine:**
146
+ ```
147
+ engines/
148
+ my_engine/
149
+ app/
150
+ domains/
151
+ core/ # --engine MyEngine --domain core/
152
+ mobile/ # --engine MyEngine --domain mobile/
153
+ ```
154
+
155
+ ### Generate Structure
156
+
157
+ Generator untuk membuat file struktur YAML dari model yang sudah ada. File YAML ini berisi konfigurasi yang akan digunakan oleh generator `scaffold`.
158
+
159
+ ```bash
160
+ rails generate rider_kick:structure MODEL_NAME [SETTINGS] [OPTIONS]
54
161
  ```
162
+
163
+ **Required Arguments:**
164
+ - `MODEL_NAME` - Nama model class (e.g., `Models::User`, `Models::Article`)
165
+ - `actor` - Actor/role yang akan menggunakan use case (e.g., `actor:user`, `actor:admin`)
166
+ - `resource_owner` - Nama resource owner untuk authorization (e.g., `resource_owner:account`)
167
+ - `resource_owner_id` - Nama kolom resource owner ID (e.g., `resource_owner_id:account_id`)
168
+
169
+ **Optional Settings:**
170
+ - `uploaders` - Daftar kolom uploader dipisah koma (e.g., `uploaders:avatar,images`)
171
+ - `search_able` - Daftar kolom yang bisa di-search dipisah koma (e.g., `search_able:name,email`)
172
+
173
+ **Options:**
174
+ - `--engine ENGINE_NAME` - Specify engine name (e.g., `Core`, `Admin`)
175
+ - `--domain DOMAIN` - Specify domain scope (e.g., `core/`, `admin/`, `api/v1/`)
176
+
177
+ **Examples:**
178
+ ```bash
179
+ # Basic structure dengan domain default
180
+ rails generate rider_kick:structure Models::User actor:owner resource_owner:account resource_owner_id:account_id
181
+
182
+ # Dengan uploaders dan searchable fields
183
+ rails generate rider_kick:structure Models::Product \
184
+ actor:admin \
185
+ resource_owner:account \
186
+ resource_owner_id:account_id \
187
+ uploaders:image,documents \
188
+ search_able:name,sku \
189
+ --domain admin/
190
+
191
+ # Dalam Rails engine
192
+ rails generate rider_kick:structure Models::Order \
193
+ actor:user \
194
+ resource_owner:account \
195
+ resource_owner_id:account_id \
196
+ --engine OrderEngine \
197
+ --domain fulfillment/
198
+ ```
199
+
200
+ **Output:** File YAML di `db/structures/<model_name>_structure.yaml` yang berisi konfigurasi lengkap untuk scaffold generator.
201
+
202
+ ### Generate Scaffold
203
+
204
+ Generator utama untuk generate use cases, repositories, entities, builders, dan spec files berdasarkan structure YAML yang sudah dibuat.
205
+
206
+ ```bash
207
+ rails generate rider_kick:scaffold STRUCTURE_NAME [SCOPE] [OPTIONS]
208
+ ```
209
+
210
+ **Required Arguments:**
211
+ - `STRUCTURE_NAME` - Nama structure (plural, tanpa `_structure.yaml`). Contoh: `users`, `products`, `orders`
212
+
213
+ **Optional Arguments:**
214
+ - `scope:SCOPE_NAME` - Route scope (e.g., `scope:dashboard`, `scope:admin`)
215
+
216
+ **Options:**
217
+ - `--engine ENGINE_NAME` - Specify engine name (e.g., `Core`, `Admin`)
218
+ - `--domain DOMAIN` - Specify domain scope (e.g., `core/`, `admin/`, `api/v1/`)
219
+
220
+ **Examples:**
221
+ ```bash
222
+ # Basic scaffold dengan domain default
223
+ rails generate rider_kick:scaffold users scope:dashboard
224
+
225
+ # Dengan domain khusus
226
+ rails generate rider_kick:scaffold users scope:admin --domain admin/
227
+
228
+ # Dalam Rails engine
229
+ rails generate rider_kick:scaffold orders --engine OrderEngine --domain fulfillment/
230
+
231
+ # API domain
232
+ rails generate rider_kick:scaffold products --domain api/v1/
233
+ ```
234
+
235
+ **Output:**
236
+ - Use cases: `app/domains/<domain>/use_cases/<scope>/<resource>/`
237
+ - Repositories: `app/domains/<domain>/repositories/<resource>/`
238
+ - Entities: `app/domains/<domain>/entities/`
239
+ - Builders: `app/domains/<domain>/builders/`
240
+ - Spec files untuk semua generated code
241
+
242
+ ### Generate Factory
243
+
244
+ Generator untuk membuat FactoryBot factory files dengan smart Faker generation. Otomatis skip foreign key columns dan generate Faker values berdasarkan tipe kolom.
245
+
246
+ ```bash
247
+ rails generate rider_kick:factory MODEL_NAME [SCOPE] [OPTIONS]
248
+ ```
249
+
250
+ **Required Arguments:**
251
+ - `MODEL_NAME` - Nama model class (e.g., `Models::Article`, `Models::User`)
252
+
253
+ **Optional Arguments:**
254
+ - `scope:SCOPE_NAME` - Scope untuk factory (e.g., `scope:core`)
255
+
256
+ **Options:**
257
+ - `--engine ENGINE_NAME` - Specify engine name (e.g., `Core`, `Admin`)
258
+ - `--static` - Generate static values instead of Faker calls (time fields tetap menggunakan `Time.zone.now`)
259
+
260
+ **Examples:**
261
+ ```bash
262
+ # Factory dengan Faker (default)
263
+ rails generate rider_kick:factory Models::Article scope:core
264
+
265
+ # Factory dengan static values
266
+ rails generate rider_kick:factory Models::Article scope:core --static
267
+
268
+ # Dalam Rails engine
269
+ rails generate rider_kick:factory Models::Order scope:fulfillment --engine OrderEngine
270
+ ```
271
+
272
+ **Smart Faker Mapping:**
273
+ Generator menggunakan smart mapping berdasarkan nama kolom dan tipe:
274
+ - `string` dengan `email` → `Faker::Internet.email`
275
+ - `string` dengan `name` → `Faker::Name.name`
276
+ - `text` dengan `description`/`content` → `Faker::Lorem.paragraph`
277
+ - `integer` dengan `price`/`amount` → `Faker::Number.between(from: 1000, to: 1000000)`
278
+ - `decimal` dengan `price` → `Faker::Commerce.price`
279
+ - `boolean` → `[true, false].sample`
280
+ - `datetime`/`timestamp`/`time` → `Time.zone.now` (selalu)
281
+ - Dan banyak lagi...
282
+
283
+ **Kolom yang Di-skip:**
284
+ - `id`, `created_at`, `updated_at`, `type`
285
+ - Semua foreign key columns (`*_id`)
286
+
287
+ 📖 **[Complete Factory Generator Documentation →](FACTORY_GENERATOR.md)**
288
+ 📖 **[Domain Scoping Guide →](DOMAIN_SCOPING.md)**
55
289
  ---
56
290
  ## Generated Structure
57
291
 
292
+ ### Default Structure (Main App)
293
+ ```text
294
+ app/
295
+ domains/
296
+ core/ # Default domain (--domain core/)
297
+ entities/
298
+ builders/
299
+ repositories/
300
+ use_cases/
301
+ utils/
302
+ ```
303
+
304
+ ### Multiple Domains Structure
58
305
  ```text
59
306
  app/
60
307
  domains/
61
- core/
308
+ core/ # Main domain (--domain core/)
309
+ entities/
310
+ builders/
311
+ repositories/
312
+ use_cases/
313
+ utils/
314
+ admin/ # Admin domain (--domain admin/)
62
315
  entities/
63
316
  builders/
64
317
  repositories/
65
318
  use_cases/
66
319
  utils/
320
+ api/
321
+ v1/ # API domain (--domain api/v1/)
322
+ entities/
323
+ builders/
324
+ repositories/
325
+ use_cases/
326
+ utils/
327
+ ```
328
+
329
+ ### Rails Engine Structure
330
+ ```text
331
+ engines/
332
+ my_engine/
333
+ app/
334
+ domains/
335
+ core/ # Engine domain (--engine MyEngine --domain core/)
336
+ entities/
337
+ builders/
338
+ repositories/
339
+ use_cases/
340
+ utils/
341
+ mobile/ # Mobile domain (--engine MyEngine --domain mobile/)
342
+ entities/
343
+ builders/
344
+ repositories/
345
+ use_cases/
346
+ utils/
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Complete Generator Documentation
352
+
353
+ ### Generator Overview
354
+
355
+ Gem ini menyediakan **4 generator utama**:
356
+
357
+ 1. **`rider_kick:clean_arch`** - Setup Clean Architecture structure
358
+ 2. **`rider_kick:structure`** - Generate structure YAML file dari model
359
+ 3. **`rider_kick:scaffold`** - Generate use cases, repositories, entities, builders
360
+ 4. **`rider_kick:factory`** - Generate FactoryBot factory files
361
+
362
+ ### 1. Generator: `rider_kick:clean_arch`
363
+
364
+ **Deskripsi:**
365
+ Generator untuk setup awal struktur Clean Architecture. Generator ini harus dijalankan pertama kali sebelum menggunakan generator lainnya.
366
+
367
+ **Command:**
368
+ ```bash
369
+ rails generate rider_kick:clean_arch [OPTIONS]
370
+ ```
371
+
372
+ **Options:**
373
+
374
+ | Option | Type | Default | Deskripsi |
375
+ |--------|------|---------|-----------|
376
+ | `--setup` | boolean | `false` | **WAJIB** - Setup domain structure. Harus dispecify untuk membuat struktur domain. |
377
+ | `--engine` | string | `nil` | Specify engine name (e.g., `Core`, `Admin`). Jika dispecify, `--setup` otomatis dianggap true. |
378
+ | `--domain` | string | `''` | Specify domain scope (e.g., `core/`, `admin/`, `api/v1/`). Default: `core/` |
379
+
380
+ **Yang Dihasilkan:**
381
+
382
+ 1. **Domain Structure:**
383
+ - `app/domains/<domain>/use_cases/` (dengan subfolder `contract/`)
384
+ - `app/domains/<domain>/repositories/`
385
+ - `app/domains/<domain>/builders/`
386
+ - `app/domains/<domain>/entities/`
387
+ - `app/domains/<domain>/utils/`
388
+
389
+ 2. **Base Files:**
390
+ - Contract files: `pagination.rb`, `default.rb`
391
+ - Use case: `get_version.rb`
392
+ - Builders: `error.rb`, `pagination.rb`
393
+ - Entities: `error.rb`, `pagination.rb`
394
+ - Repository: `abstract_repository.rb`
395
+ - Utils: `abstract_utils.rb`, `request_methods.rb`
396
+
397
+ 3. **Configuration Files (Main App Only):**
398
+ - Initializers: `clean_archithecture.rb`, `generators.rb`, `hashie.rb`, `version.rb`, `zeitwerk.rb`, `pagy.rb`, `route_extensions.rb`
399
+ - Database config: `config/database.yml`
400
+ - Environment files: `.env.development`, `.env.production`, `.env.test`, `env.example`
401
+ - Git ignore: `.gitignore`
402
+ - Rubocop: `.rubocop.yml`
403
+ - README: `README.md`
404
+
405
+ 4. **RSpec Setup (Main App Only):**
406
+ - RSpec configuration
407
+ - Support files: `class_stubber.rb`, `file_stuber.rb`, `repository_stubber.rb`
408
+ - FactoryBot & Faker setup
409
+ - `spec/rails_helper.rb`
410
+
411
+ 5. **Database:**
412
+ - Migration: `db/migrate/20220613145533_init_database.rb`
413
+ - Structures directory: `db/structures/`
414
+
415
+ 6. **Models:**
416
+ - `app/models/application_record.rb` (main app)
417
+ - `app/models/models/models.rb`
418
+
419
+ 7. **Gem Dependencies (ditambahkan ke Gemfile):**
420
+ - `rspec-rails`, `factory_bot_rails`, `faker`, `shoulda-matchers`
421
+ - `dotenv-rails`
422
+ - `hashie`
423
+ - `image_processing`, `ruby-vips`
424
+ - `pagy`
425
+
426
+ **Catatan Penting:**
427
+ - Option `--setup` **WAJIB** dispecify untuk membuat struktur domain
428
+ - Jika `--engine` dispecify, `--setup` otomatis dianggap true
429
+ - Untuk engine, beberapa setup (seperti initializers) tidak dilakukan karena dilakukan di main app
430
+
431
+ ### 2. Generator: `rider_kick:structure`
432
+
433
+ **Deskripsi:**
434
+ Generator untuk membuat file struktur YAML dari model yang sudah ada. File YAML ini berisi konfigurasi yang akan digunakan oleh generator `scaffold` untuk generate use cases, repositories, entities, dan builders.
435
+
436
+ **Command:**
437
+ ```bash
438
+ rails generate rider_kick:structure MODEL_NAME [SETTINGS] [OPTIONS]
439
+ ```
440
+
441
+ **Required Settings:**
442
+
443
+ | Setting | Deskripsi | Contoh |
444
+ |---------|-----------|--------|
445
+ | `actor` | Actor/role yang akan menggunakan use case | `actor:user`, `actor:admin`, `actor:owner` |
446
+ | `resource_owner` | Nama resource owner (untuk authorization) | `resource_owner:account` |
447
+ | `resource_owner_id` | Nama kolom resource owner ID | `resource_owner_id:account_id` |
448
+
449
+ **Optional Settings:**
450
+
451
+ | Setting | Deskripsi | Contoh |
452
+ |---------|-----------|--------|
453
+ | `uploaders` | Daftar kolom uploader (dipisah koma). Otomatis detect single/multiple berdasarkan singular/plural | `uploaders:avatar,images,picture` |
454
+ | `search_able` | Daftar kolom yang bisa di-search (dipisah koma) | `search_able:name,email,title` |
455
+
456
+ **Options:**
457
+
458
+ | Option | Type | Default | Deskripsi |
459
+ |--------|------|---------|-----------|
460
+ | `--engine` | string | `nil` | Specify engine name (e.g., `Core`, `Admin`) |
461
+ | `--domain` | string | `''` | Specify domain scope (e.g., `core/`, `admin/`, `api/v1/`) |
462
+
463
+ **Format YAML yang Dihasilkan:**
464
+
465
+ ```yaml
466
+ model: Models::User
467
+ resource_name: users
468
+ actor: owner
469
+ resource_owner: account
470
+ resource_owner_id: account_id
471
+ uploaders:
472
+ - name: avatar
473
+ type: single
474
+ - name: images
475
+ type: multiple
476
+ search_able: []
477
+ domains:
478
+ action_list:
479
+ use_case:
480
+ contract: [...]
481
+ action_create:
482
+ use_case:
483
+ contract: [...]
484
+ action_update:
485
+ use_case:
486
+ contract: [...]
487
+ action_fetch_by_id:
488
+ use_case:
489
+ contract: [...]
490
+ action_destroy:
491
+ use_case:
492
+ contract: [...]
493
+ entity:
494
+ db_attributes: [...]
495
+ ```
496
+
497
+ **Catatan Penting:**
498
+ - Model harus sudah ada sebelum menjalankan generator ini
499
+ - Generator ini membaca kolom dari model untuk generate contract dan entity attributes
500
+ - Kolom `id`, `created_at`, `updated_at`, `type` otomatis di-exclude dari contract fields
501
+ - Uploader type (single/multiple) otomatis di-detect berdasarkan singular/plural name
502
+
503
+ ### 3. Generator: `rider_kick:scaffold`
504
+
505
+ **Deskripsi:**
506
+ Generator utama untuk generate use cases, repositories, entities, builders, dan spec files berdasarkan structure YAML yang sudah dibuat oleh generator `structure`.
507
+
508
+ **Command:**
509
+ ```bash
510
+ rails generate rider_kick:scaffold STRUCTURE_NAME [SCOPE] [OPTIONS]
511
+ ```
512
+
513
+ **Yang Dihasilkan:**
514
+
515
+ 1. **Use Cases** (di `app/domains/<domain>/use_cases/<scope>/<resource>/`):
516
+ - `{actor}_create_{resource}.rb` - Create use case
517
+ - `{actor}_update_{resource}.rb` - Update use case
518
+ - `{actor}_list_{resource}.rb` - List use case
519
+ - `{actor}_fetch_by_id_{resource}.rb` - Fetch by ID use case
520
+ - `{actor}_destroy_{resource}.rb` - Destroy use case
521
+ - Spec files untuk setiap use case
522
+
523
+ 2. **Repositories** (di `app/domains/<domain>/repositories/<resource>/`):
524
+ - `create_{resource}.rb` - Create repository
525
+ - `update_{resource}.rb` - Update repository
526
+ - `list_{resource}.rb` - List repository
527
+ - `fetch_by_id_{resource}.rb` - Fetch by ID repository
528
+ - `destroy_{resource}.rb` - Destroy repository
529
+ - Spec files untuk setiap repository
530
+
531
+ 3. **Entities** (di `app/domains/<domain>/entities/`):
532
+ - `{resource}.rb` - Entity class dengan attributes dari model
533
+
534
+ 4. **Builders** (di `app/domains/<domain>/builders/`):
535
+ - `{resource}.rb` - Builder class untuk convert ActiveRecord ke Entity
536
+ - Spec file untuk builder
537
+
538
+ 5. **Model Spec** (di `app/models/models/` atau `app/models/<engine>/`):
539
+ - `{resource}_spec.rb` - Model spec file
540
+
541
+ 6. **Model Attachment** (auto-inject ke model file):
542
+ - `has_one_attached` atau `has_many_attached` untuk uploaders
543
+ - Hanya jika model file sudah ada
544
+
545
+ **Catatan Penting:**
546
+ - Structure YAML file harus sudah ada (dibuat dengan generator `structure`)
547
+ - Generator ini membaca konfigurasi dari structure YAML file
548
+ - Validasi dilakukan untuk memastikan filter fields dan entity fields ada di model
549
+ - Uploader attachments otomatis di-inject ke model file jika file sudah ada
550
+ - Semua file yang di-generate otomatis mendapat spec file
551
+
552
+ ### 4. Generator: `rider_kick:factory`
553
+
554
+ **Deskripsi:**
555
+ Generator untuk membuat FactoryBot factory files dengan smart Faker generation. Otomatis skip foreign key columns dan generate Faker values berdasarkan tipe kolom.
556
+
557
+ **Command:**
558
+ ```bash
559
+ rails generate rider_kick:factory MODEL_NAME [SCOPE] [OPTIONS]
560
+ ```
561
+
562
+ **Smart Faker Mapping:**
563
+
564
+ Generator ini menggunakan smart mapping berdasarkan nama kolom dan tipe:
565
+
566
+ | Tipe Kolom | Nama Kolom Contains | Faker Expression |
567
+ |------------|---------------------|-------------------|
568
+ | `string` | `email` | `Faker::Internet.email` |
569
+ | `string` | `name` | `Faker::Name.name` |
570
+ | `string` | `phone` | `Faker::PhoneNumber.phone_number` |
571
+ | `string` | `address` | `Faker::Address.full_address` |
572
+ | `string` | `title` | `Faker::Lorem.sentence(word_count: 3)` |
573
+ | `string` | `code` | `Faker::Alphanumeric.alphanumeric(number: 10)` |
574
+ | `string` | (default) | `Faker::Lorem.word` |
575
+ | `text` | `description`, `content`, `body` | `Faker::Lorem.paragraph(sentence_count: 3)` |
576
+ | `text` | (default) | `Faker::Lorem.sentence` |
577
+ | `integer` | `count`, `quantity` | `Faker::Number.between(from: 1, to: 100)` |
578
+ | `integer` | `age` | `Faker::Number.between(from: 18, to: 80)` |
579
+ | `integer` | `price`, `amount` | `Faker::Number.between(from: 1000, to: 1000000)` |
580
+ | `integer` | (default) | `Faker::Number.number(digits: 5)` |
581
+ | `decimal` | `price`, `amount` | `Faker::Commerce.price` |
582
+ | `decimal` | (default) | `Faker::Number.decimal(l_digits: 4, r_digits: 2)` |
583
+ | `boolean` | - | `[true, false].sample` |
584
+ | `date` | - | `Faker::Date.between(from: 1.year.ago, to: Date.today)` |
585
+ | `datetime`, `timestamp`, `time` | - | `Time.zone.now` (selalu, bahkan dengan `--static`) |
586
+ | `uuid` | - | `SecureRandom.uuid` |
587
+ | `json`, `jsonb` | - | `{ key: Faker::Lorem.word, value: Faker::Lorem.sentence }` |
588
+
589
+ **Kolom yang Di-skip:**
590
+ - `id` - Primary key
591
+ - `created_at` - Timestamp
592
+ - `updated_at` - Timestamp
593
+ - `type` - STI type
594
+ - `*_id` - Semua foreign key columns (ending with `_id`)
595
+
596
+ **Catatan Penting:**
597
+ - Model harus sudah ada sebelum menjalankan generator ini
598
+ - Foreign key columns otomatis di-skip
599
+ - Time-based columns selalu menggunakan `Time.zone.now`, bahkan dengan `--static`
600
+ - Dengan `--static`, Faker expressions akan di-evaluate dan hasilnya dijadikan static values
601
+
602
+ ### Complete Workflow Example
603
+
604
+ ```bash
605
+ # 1. Setup Clean Architecture (sekali di awal)
606
+ rails generate rider_kick:clean_arch --setup --domain core/
607
+
608
+ # 2. Buat model
609
+ rails g model models/products name:string price:decimal is_published:boolean
610
+
611
+ # 3. Generate structure YAML
612
+ rails generate rider_kick:structure Models::Product \
613
+ actor:admin \
614
+ resource_owner:account \
615
+ resource_owner_id:account_id \
616
+ uploaders:image \
617
+ search_able:name,description \
618
+ --domain core/
619
+
620
+ # 4. Generate scaffold (use cases, repositories, entities, builders)
621
+ rails generate rider_kick:scaffold products scope:dashboard --domain core/
622
+
623
+ # 5. Generate factory untuk testing
624
+ rails generate rider_kick:factory Models::Product scope:core
67
625
  ```
68
626
 
69
627
  ---
@@ -80,15 +638,37 @@ This structure provides helper interfaces and classes to assist in the construct
80
638
  - models
81
639
  - models
82
640
  - ...
83
- - domains
84
- - core
85
- ...
86
- - entities (Contract Response)
87
- - builder
88
- - repositories (Business logic)
89
- - use_cases (Just Usecase)
90
- - utils (Class Reusable)
641
+ - domains
642
+ - core # Default domain (--domain core/)
643
+ - entities (Contract Response)
644
+ - builders
645
+ - repositories (Business logic)
646
+ - use_cases (Just Usecase)
647
+ - utils (Class Reusable)
648
+ - admin # Admin domain (--domain admin/)
649
+ - entities
650
+ - builders
651
+ - repositories
652
+ - use_cases
653
+ - utils
654
+ - api/v1 # API domain (--domain api/v1/)
655
+ - entities
656
+ - builders
657
+ - repositories
658
+ - use_cases
659
+ - utils
91
660
  ```
661
+
662
+ ### Domain Scoping untuk Large Applications
663
+ Untuk aplikasi yang besar, Anda dapat menggunakan `--domain` option untuk mengorganisir domain files berdasarkan konteks bisnis:
664
+
665
+ - **`core/`**: Domain utama aplikasi (default)
666
+ - **`admin/`**: Domain untuk fitur admin/pengelolaan
667
+ - **`api/v1/`**: Domain untuk API versioning
668
+ - **`mobile/`**: Domain untuk mobile-specific logic
669
+ - **`reporting/`**: Domain untuk laporan dan analytics
670
+
671
+ Ini membantu menjaga kode tetap terorganisir dan memudahkan maintenance seiring pertumbuhan aplikasi.
92
672
  ### Screaming architecture - use cases as an organisational principle
93
673
  Uncle Bob suggests that your source code organisation should allow developers to easily find a listing of all use cases your application provides. Here's an example of how this might look in a this application.
94
674
  ```
@@ -117,6 +697,30 @@ Note that the use case name contains:
117
697
  # fetch_info.rb [generic usecase] every role can access it
118
698
  ```
119
699
  ---
700
+ ---
701
+
702
+ ## Dependencies
703
+
704
+ ### Runtime Dependencies:
705
+ - `activesupport` >= 7.0, < 9.0
706
+ - `dry-matcher` >= 1.0, < 2.0
707
+ - `dry-monads` >= 1.6, < 2.0
708
+ - `dry-struct` >= 1.6, < 2.0
709
+ - `dry-types` >= 1.7, < 2.0
710
+ - `dry-validation` >= 1.9, < 2.0
711
+ - `hashie` >= 5.0, < 6.0
712
+ - `thor` >= 1.2, < 2.0
713
+
714
+ ### Development Dependencies:
715
+ - `bundler` >= 2.4, < 3.0
716
+ - `generator_spec` >= 0.9, < 1.0
717
+ - `rake` >= 13.0, < 14.0
718
+ - `rspec` >= 3.12, < 4.0
719
+ - `rubocop` >= 1.63, < 2.0
720
+ - `rubocop-rspec` >= 3.0, < 4.0
721
+
722
+ ---
723
+
120
724
  ## 🤝 Contributing
121
725
 
122
726
  - Fork the repo & bundle install