├── .gitignore ├── README.md └── docs ├── 00_INSTALLATION.md ├── 01_REST_API_DOC.md ├── 02_WEB_APP_SCREENSHOTS.md ├── screenshots ├── 010_sign_in.jpg ├── 011_sign_in_error.jpg ├── 020_forgot_password.jpg ├── 030_sign_up.jpg ├── 031_sign_up_errors.jpg ├── 032_sign_up_success.jpg ├── 040_new_task.jpg ├── 041_task_created.jpg ├── 042_task_completed.jpg ├── 043_tasks_completed.jpg ├── 044_tasks_incomplete.jpg ├── 045_edit_task.jpg ├── 050_task_lists.jpg ├── 051_new_task_list.jpg ├── 052_select_task_list.jpg ├── 060_settings_profile.jpg ├── 061_settings_account_deletion.jpg ├── 062_settings_api_token.jpg └── 070_sign_out.jpg └── versions ├── controller ├── api │ ├── README.md │ ├── solid-process-0.rb │ ├── solid-process-1.rb │ ├── solid-process-2.00--2.80.rb │ ├── solid-process-2.95.rb │ ├── solid-process-2.99--4.rb │ └── vanilla-rails.rb └── web │ ├── README.md │ ├── solid-process-0.rb │ ├── solid-process-1--2.95.rb │ ├── solid-process-2.99--4.rb │ └── vanilla-rails.rb └── model ├── README.md ├── solid-process-0.rb ├── solid-process-1.rb ├── solid-process-2.00.rb ├── solid-process-2.20--2.40.rb ├── solid-process-2.60.rb ├── solid-process-2.80.rb ├── solid-process-2.95--2.99.rb ├── solid-process-3.rb └── solid-process-4.rb /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all environment files (except templates). 11 | /.env* 12 | !/.env*.erb 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore storage (uploaded files in development and any SQLite databases). 26 | /storage/* 27 | !/storage/.keep 28 | /tmp/storage/* 29 | !/tmp/storage/ 30 | !/tmp/storage/.keep 31 | 32 | /public/assets 33 | 34 | # Ignore master key for decrypting credentials and more. 35 | /config/master.key 36 | 37 | /coverage/ 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | > `MENU` **README** | [How to run locally](./docs/00_INSTALLATION.md) | [REST API doc](./docs/01_REST_API_DOC.md) | [Web app screenshots](./docs/02_WEB_APP_SCREENSHOTS.md) 4 | 5 | 6 | 7 | # ✨ Solid Rails App 8 | 9 | Web and REST API application made with [Ruby on Rails](https://guides.rubyonrails.org/) + [solid-process](https://github.com/solid-process/solid-process). 10 | 11 | ## 📚 Table of contents 12 | 13 | - [📢 Disclaimer](#-disclaimer) 14 | - [🙌 Repository branches](#-repository-branches) 15 | - [🌟 Highlights of what solid-process can bring to you/your team](#-highlights-of-what-solid-process-can-bring-to-youyour-team) 16 | - [🤔 How can we be aware of critical system processes?](#-how-can-we-be-aware-of-critical-system-processes) 17 | - [👋 About](#-about) 18 | 19 | ## 📢 Disclaimer 20 | 21 | The goal of this project is to demonstrate how the `solid-process` can be gradually integrated into a Rails application. 22 | 23 | It's important to note that the **Rails Way** and the **Solid Process** are not mutually exclusive. You can implement the `solid-process` where it best fits your needs, allowing both approaches to coexist harmoniously and beneficially. 24 | 25 | That said, this is not an invitation, guide, or recommendation to implement all applications in the more complex manner demonstrated in this project. 26 | 27 | I (Rodrigo Serradura) believe in a pragmatic approach using the best tool for the job. The _**vanilla-rails**_ version is excellent and capable of handling all the complexity within this system's scope. 28 | 29 | Therefore, view this project as a showcase of what the `solid-process` gem can achieve. You may discover valuable tools to add to your toolbox. Enjoy! ✌️😊 30 | 31 | ## 🙌 Repository branches 32 | 33 | This repository has twelve branches that represent the application's evolution. 34 | 35 | The `2.##` branches are percentages that indicate gradual progress toward the next version. 36 | 37 | Architectural patterns are applied according to the following criteria: 38 | - `0` to `2.99` , stays on the **Layered Architecture**. 39 | - `3` onwards, applies the **Ports and Adapters (_Hexagonal_) Architecture**. 40 | 41 | __*Click in the arrows*__ to see the summary of each branch: 42 | 43 |
Branch | 47 |LOC / GRADE | 48 |
---|---|
54 |
55 |
75 | vanilla-rails56 | 57 | --- 58 | It is the base version that implements a web application and REST API using the Rails Way approach. The business rules are mainly implemented around the ActiveRecord lifecycle/features (normalization, validation, callbacks, and macros), which the application controllers orchestrate. 59 | 60 | However, with each new version, these models and controllers will have fewer responsibilities as we implement processes to wrap and orchestrate the core business logic. 61 | 62 | Note: Three concepts differ from a traditional CRUD. Are they: 63 | 64 | 1. [Account Member](https://github.com/solid-process/solid-rails-app/blob/vanilla-rails/app/models/account/member.rb): This PORO performs access/scope control in the accounts. 65 | 66 | 2. [User Registration](https://github.com/solid-process/solid-rails-app/blob/vanilla-rails/app/models/user.rb#L18-L49): This operation consists of creating the user and its account, defining the user as the account's owner, creating the user API token, and sending an email to confirm the user email. 67 | 68 | 3. [User API token](https://github.com/solid-process/solid-rails-app/blob/vanilla-rails/app/models/user_token.rb): This implementation is based on the [prefixed API token concept](https://github.com/seamapi/prefixed-api-key), which consists of a short (public) and a long (encrypted) token. 69 | 70 | **Version samples:** 71 | - [API Controller](./docs/versions/controller/api/vanilla-rails.rb) 72 | - [Web Controller](./docs/versions/controller/web/vanilla-rails.rb) 73 | 74 | |
76 | 1434 / 94.06 | 77 |
82 |
83 |
96 | solid-process-084 | 85 | --- 86 | Introduces the solid-process gem and implements the application's first process ([User::Registration](https://github.com/solid-process/solid-rails-app/blob/solid-process-0/app/models/user/registration.rb)). 87 | 88 | It shows the low learning curve required to use gem features. Although basic, this implementation removes callbacks from the [User](https://github.com/solid-process/solid-rails-app/blob/solid-process-0/app/models/user.rb) model, as the process will orchestrate all account creation within a transaction and send a confirmation email after its commit. 89 | 90 | **Version samples:** 91 | - [API Controller](./docs/versions/controller/api/solid-process-0.rb) ([Diff](./docs/versions/controller/api/README.md#vanilla-railssolid-process-0)) 92 | - [Web Controller](./docs/versions/controller/web/solid-process-0.rb) ([Diff](./docs/versions/controller/web/README.md#vanilla-railsrbsolid-process-0)) 93 | - [Process](./docs/versions/model/solid-process-0.rb) 94 | 95 | |
97 | 1459 / 94.08 | 98 |
103 |
104 |
117 | solid-process-1105 | 106 | --- 107 | Defines types for input attributes and uses steps to perform all operations within a transaction block that will perform a rollback if any step returns a failure. After the commit, the confirmation email is sent, and the created user is exposed in the [User::Registration](https://github.com/solid-process/solid-rails-app/blob/solid-process-1/app/models/user/registration.rb) result. 108 | 109 | Note: In this version, the process input ([User::Registration::Input](https://github.com/solid-process/solid-rails-app/blob/solid-process-1/app/controllers/web/guest/registrations_controller.rb#L6)) is used in the view forms, causing the view to be coupled to it and no longer to the User model (ActiveRecord). 110 | 111 | **Version samples:** 112 | - [API Controller](./docs/versions/controller/api/solid-process-1.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-0solid-process-1)) 113 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 114 | - [Process](./docs/versions/model/solid-process-1.rb) ([Diff](./docs/versions/model/README.md#solid-process-0solid-process-1)) 115 | 116 | |
118 | 1481 / 93.98 | 119 |
124 |
125 |
142 | solid-process-2.00126 | 127 | --- 128 | From version 2 onwards, all contexts (Account and User) implement their operations through processes. Because of this, it becomes possible to create a composition of processes where they are defined as dependencies that will be orchestrated through their steps. 129 | 130 | Notes: 131 | 132 | 1. [UserToken](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.00/app/models/user_token.rb) becomes hugely lean because the model's behavior has been diluted into different components within the [User::Token namespace](https://github.com/solid-process/solid-rails-app/tree/solid-process-2.00/app/models/user/token). I am highlighting [User::Token::Entity](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.00/app/models/user/token/entity.rb), a PORO capable of representing a token without the need to interact with the database (ActiveRecord model). 133 | 134 | 2. New features are added to input blocks, such as data normalization and validation. 135 | 136 | **Version samples:** 137 | - [API Controller](./docs/versions/controller/api/solid-process-2.00--2.80.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-1solid-process-200--280)) 138 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 139 | - [Process](./docs/versions/model/solid-process-2.00.rb) ([Diff](./docs/versions/model/README.md#solid-process-1solid-process-200)) 140 | 141 | |
143 | 1866 / 93.78 | 144 |
149 |
150 |
163 | solid-process-2.20151 | 152 | --- 153 | If we analyze the previous version, we will see that the ActiveRecord models are not defined within the context of the user or account. 154 | 155 | What this version does is rename the ActiveRecord models as [Record](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.20/app/models/user/record.rb) (for this, it is necessary to define the table_name and class_name in the classes) within the [Account](https://github.com/solid-process/solid-rails-app/tree/solid-process-2.20/app/models/account) and [User](https://github.com/solid-process/solid-rails-app/tree/solid-process-2.20/app/models/user) namespaces (they become mere modules since before both were also an ActiveRecord model) 156 | 157 | **Version samples:** 158 | - [API Controller](./docs/versions/controller/api/solid-process-2.00--2.80.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-1solid-process-200--280)) 159 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 160 | - [Process](./docs/versions/model/solid-process-2.20--2.40.rb) ([Diff](./docs/versions/model/README.md#solid-process-200solid-process-220--240)) 161 | 162 | |
164 | 1894 / 93.74 | 165 |
170 |
171 |
186 | solid-process-2.40172 | 173 | --- 174 | The **vanilla-rails summary** presents the Account::Member as one of the application's most important components. It is responsible for controlling access to the accounts. 175 | 176 | It turns out that although it is a PORO (Solid::Model), its implementation also contains queries (ActiveRecord stuff). 177 | 178 | This version introduces [Account::Member::Repository](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.40/app/models/account/member/repository.rb) to enhance the separation of concerns. This new component/pattern will serve as an abstraction layer for the data source, allowing queries to be moved to it and making the [Account::Member implementation more straightforward and concise](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.40/app/models/account/member.rb). 179 | 180 | **Version samples:** 181 | - [API Controller](./docs/versions/controller/api/solid-process-2.00--2.80.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-1solid-process-200--280)) 182 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 183 | - [Process](./docs/versions/model/solid-process-2.20--2.40.rb) ([Diff](./docs/versions/model/README.md#solid-process-200solid-process-220--240)) 184 | 185 | |
187 | 1904 / 93.80 | 188 |
193 |
194 |
207 | solid-process-2.60195 | 196 | --- 197 | Since version 2.40 introduces the Repository pattern, what would happen if all processes/contexts started using this pattern? 198 | 199 | This version answers this question in practice by introducing a repository for each context and forcing the application to start using them instead of directly using the ActiveRecord models. 200 | 201 | **Version samples:** 202 | - [API Controller](./docs/versions/controller/api/solid-process-2.00--2.80.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-1solid-process-200--280)) 203 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 204 | - [Process](./docs/versions/model/solid-process-2.60.rb) ([Diff](./docs/versions/model/README.md#solid-process-220--240solid-process-260)) 205 | 206 | |
208 | 2144 / 91.14 | 209 |
214 |
215 |
230 | solid-process-2.80216 | 217 | --- 218 | Due to the addition of repositories in the previous version, it is evident that User::Registration and User::AccountDeletion have methods in their repositories that use an Account::Record. In other words, it is clear that User::Record is tightly coupled to Account::Record and should not be. 219 | 220 | To solve this, a new [account_members table](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.80/db/schema.rb#L14-L19) (and model Account::Member::Record) is created with just one column (uuid), and a column [uuid is also added to the user's table](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.80/db/schema.rb#L73). 221 | 222 | While we won't be using a foreign key, the plan is to start referencing the users' UUID in the account members table. This approach will allow us to transfer several associations from the [User::Record](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.80/app/models/user/record.rb) model to [Account::Member::Record](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.80/app/models/account/member/record.rb), effectively decoupling the User and Account contexts. This will significantly enhance the system's orthogonality, minimizing the risk of changes in one context affecting the other. 223 | 224 | **Version samples:** 225 | - [API Controller](./docs/versions/controller/api/solid-process-2.00--2.80.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-1solid-process-200--280)) 226 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 227 | - [Process](./docs/versions/model/solid-process-2.80.rb) ([Diff](./docs/versions/model/README.md#solid-process-260solid-process-280)) 228 | 229 | |
231 | 2234 / 91.34 | 232 |
237 |
238 |
251 | solid-process-2.95239 | 240 | --- 241 | Once the contexts are more decoupled, the next step is to make the processes start to expose and receive only [entities (POROS)](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.95/app/models/user/entity.rb) and no longer ActiveRecord objects. 242 | 243 | With this approach, each context gains enhanced control over side effects, be it writing or reading. All interactions with the database/ActiveRecord are now wrapped within the repositories, ensuring a more controlled and predictable system behavior. 244 | 245 | **Version samples:** 246 | - [API Controller](./docs/versions/controller/api/solid-process-2.95.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-200--280solid-process-295)) 247 | - [Web Controller](./docs/versions/controller/web/solid-process-1--2.95.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-0solid-process-1--295)) 248 | - [Process](./docs/versions/model/solid-process-2.95--2.99.rb) ([Diff](./docs/versions/model/README.md#solid-process-280solid-process-295--299)) 249 | 250 | |
252 | 2365 / 91.50 | 253 |
258 |
259 |
270 | solid-process-2.99260 | 261 | --- 262 | This version transforms the User and Account modules into facades. Processes and repositories are now exposed through simple methods. Another benefit is that shared and repeated behavior (such as instantiating entities) can be done through the facade, eliminating duplication and abstracting this complexity from the entry points. 263 | 264 | **Version samples:** 265 | - [API Controller](./docs/versions/controller/api/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-295solid-process-299--4)) 266 | - [Web Controller](./docs/versions/controller/web/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-1--295solid-process-299--4)) 267 | - [Process](./docs/versions/model/solid-process-2.95--2.99.rb) ([Diff](./docs/versions/model/README.md#solid-process-280solid-process-295--299)) 268 | 269 | |
271 | 2474 / 92.40 | 272 |
277 |
278 |
291 | solid-process-3279 | 280 | --- 281 | This version implements the Ports and Adapters architectural pattern (Hexagonal Architecture). 282 | 283 | In version [2.99](https://github.com/solid-process/solid-rails-app/blob/solid-process-2.99), the account and user namespaces encapsulated the core business logic. They began to receive and expose objects that belonged to them, in other words, objects that did not directly relate to the framework (Rails). Because of this, it becomes feasible to isolate this core outside the app folder; for this reason, these components were moved to [lib/core](https://github.com/solid-process/solid-rails-app/tree/solid-process-3/lib/core). So, through a new lib, [Solid::Adapters](https://github.com/solid-process/solid-adapters) was added, it is possible to use [initializers](https://github.com/solid-process/solid-rails-app/tree/solid-process-3/config/initializers/solid_adapters) to plug the adapters defined in the app folder (framework side) into the core. This way, it becomes protected as the app uses/implements its ports (interfaces). 284 | 285 | **Version samples:** 286 | - [API Controller](./docs/versions/controller/api/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-295solid-process-299--4)) 287 | - [Web Controller](./docs/versions/controller/web/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-1--295solid-process-299--4)) 288 | - [Process](./docs/versions/model/solid-process-3.rb) ([Diff](./docs/versions/model/README.md#solid-process-295--299solid-process-3)) 289 | 290 | |
292 | 2527 / 93.42 | 293 |
298 |
299 |
312 | solid-process-4300 | 301 | --- 302 | This version makes usage of another `Solid::Adapters` feature, the [interface mechanism](https://github.com/solid-process/solid-adapters?tab=readme-ov-file#solidadaptersinterface) to strengthen the contracts between the core and the application. Because of this, the core can [establish](https://github.com/solid-process/solid-rails-app/blob/solid-process-4/lib/core/user/adapters/repository_interface.rb) and [demand](https://github.com/solid-process/solid-rails-app/blob/solid-process-4/lib/core/user/registration.rb#L13) its contracts (ports). 303 | 304 | Note: In case of a breach of contract, the system will raise an exception indicating what was compromised and needs to be fixed. 305 | 306 | **Version samples:** 307 | - [API Controller](./docs/versions/controller/api/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/api/README.md#solid-process-295solid-process-299--4)) 308 | - [Web Controller](./docs/versions/controller/web/solid-process-2.99--4.rb) ([Diff](./docs/versions/controller/web/README.md#solid-process-1--295solid-process-299--4)) 309 | - [Process](./docs/versions/model/solid-process-4.rb) ([Diff](./docs/versions/model/README.md#solid-process-3solid-process-4)) 310 | 311 | |
313 | 2947 / 93.42 | 314 |
app/models
file structure (output from solid-process-2.00 branch)bin/rails solid:processes
(output from solid-process-2.00 branch)