diff --git a/guides/conventions.md b/guides/conventions.md new file mode 100644 index 0000000000..b3e533df80 --- /dev/null +++ b/guides/conventions.md @@ -0,0 +1,5 @@ +# Conventions + +1. [Application Namespaces](conventions/namespaces.md) +2. [Rails Conventions](conventions/rails.md) +3. [File Structure](conventions/file-structure.md) diff --git a/guides/conventions/file-structure.md b/guides/conventions/file-structure.md new file mode 100644 index 0000000000..71c2ae74d4 --- /dev/null +++ b/guides/conventions/file-structure.md @@ -0,0 +1,7 @@ +[Conventions](/guides/conventions.md) / + +# File Structure + +- [assets](file-structure/assets.md) +- [components](file-structure/components.md) +- [controllers](file-structure/controllers.md) diff --git a/guides/conventions/file-structure/assets.md b/guides/conventions/file-structure/assets.md new file mode 100644 index 0000000000..c819f5d456 --- /dev/null +++ b/guides/conventions/file-structure/assets.md @@ -0,0 +1,20 @@ +[Conventions](/guides/conventions.md) / [File Structure](/guides/conventions/file-structure.md) / + +# Assets + +Images, videos, and stylesheets are stored in the `assets` directory. + +``` +. +└ app + └─ assets + ├─ images + └─ stylesheets + ├─ [namespace] + │ └─ application.scss + └─ application.scss +``` + +The top-level `application.scss` is the shared stylesheet for all namespaces. + +The `find/application.scss` stylesheet should be included into the `layouts/find/application.html.erb` layout alongside the top-level `application.scss` stylesheet. diff --git a/guides/conventions/file-structure/components.md b/guides/conventions/file-structure/components.md new file mode 100644 index 0000000000..821f4cedfd --- /dev/null +++ b/guides/conventions/file-structure/components.md @@ -0,0 +1,19 @@ +[Conventions](/guides/conventions.md) / [File Structure](/guides/conventions/file-structure.md) / + +# View Components + +We use [View Components](https://viewcomponent.org/) to create reusable components in our Rails applications. + +``` +. +└ app + └─ components + ├─ [namespace] (Namespace-specific components) + │ ├─ [component_name].rb + │ └─ [component_name].html.erb + ├─ [model_name] (Model-specific components) + │ ├─ [component_name].rb + │ └─ [component_name].html.erb + ├─ [component_name].rb + └─ [component_name].html.erb +``` diff --git a/guides/conventions/file-structure/controllers.md b/guides/conventions/file-structure/controllers.md new file mode 100644 index 0000000000..9603ab144d --- /dev/null +++ b/guides/conventions/file-structure/controllers.md @@ -0,0 +1,67 @@ +[Conventions](/guides/conventions.md) / [File Structure](/guides/conventions/file-structure.md) / + +# Controllers + +We organise our controllers within our namespaces. + +We should follow resourceful controller conventions. + +``` +. +└ app + └─ controllers + ├─ [namespace] (Namespace-specific controllers) + │ ├─ [controller_name]_controller.rb + │ └─ application_controller.rb + └─ application_controller.rb +``` + +Each namespace has its own `ApplicationController` as a base for all controllers within that namespace. + +```ruby +# Top-level application controller. +# Shared functionality across all namespaces. +class ApplicationController < ActionController::Base + include Pundit::Authorization +end + +# Find application controller. +# Base controller for all Find controllers. +class Find::ApplicationController < ApplicationController +end + +# The API application controller inherits from ActionController::API. +# Base controller for all API controllers. +class API::ApplicationController < ActionController::API +end + +# The base controller for all v1 API controllers. +class API::V1::ApplicationController < API::ApplicationController +end +``` + +This allows us to set base functionality across groups of controllers. + +The pattern described in [ADR#6 Controller Structure](/guides/adr/0006-controller-structure.md) details a scalable pattern to managing nested resourceful controllers. + +```ruby +class Find::RecruitmentCycles::CoursesController < Find::ApplicationController + # GET /recruitment_cycles/:recruitment_cycle_id/courses + def index + @courses = recruitment_cycle.courses + end + + # GET /recruitment_cycles/:recruitment_cycle_id/courses/:id + def show + @course = recruitment_cycle.courses.find(params[:id]) + end + + private + + def recruitment_cycle + @recruitment_cycle ||= RecruitmentCycle.find(params[:recruitment_cycle_id]) + end +end +``` + +The `params[:id]` should always be the ID of the resource being acted upon. Parent resources should always be prefixed, e.g. `params[:recruitment_cycle_id]`. diff --git a/guides/conventions/namespaces.md b/guides/conventions/namespaces.md new file mode 100644 index 0000000000..044b1cf8c7 --- /dev/null +++ b/guides/conventions/namespaces.md @@ -0,0 +1,26 @@ +[Conventions](/guides/conventions.md) / + +# Namespaces + +We use namespaces to organise our code into service-specific modules. This provides us with visibility of separation of concerns. + +We benefit from this separtation in the following ways: + +- Code under a namespace is intended to be used only by the service it belongs to. + + We can easily detect when code is used incorrectly outside of its namespace. + + This limits the blast radius of changes to a single service. For example, we can confidently make changes to a `Find` component and expect that it will only effect the "Find" service. + +- Explicit shared code. + + If code is shared, it is in the top-level namespace. + + We can visually determine how much code is shared between services by looking at the non-namespaced files. + +## Our namespaces + +- `Find` +- `Publish` +- `Support` +- `API` diff --git a/guides/conventions/rails.md b/guides/conventions/rails.md new file mode 100644 index 0000000000..cd69158276 --- /dev/null +++ b/guides/conventions/rails.md @@ -0,0 +1,66 @@ +[Conventions](/guides/conventions.md) / + +# Rails Architecture + +This document describes the Rails conventions of this application. + +## 1. File Structure + +Learn more about each of the directories' purposes in the [File Structure](conventions/file-structure.md) guide. + +``` +. +└ app + ├─ assets + ├─ components (View Components) + ├─ controllers + ├─ forms (Form Objects) + ├─ helpers + ├─ javascript + ├─ jobs + ├─ lib + ├─ mailers + ├─ models + ├─ policies + ├─ serializers + ├─ services (Service Objects) + ├─ validators + ├─ views + └─ wizards +``` + +The following directories are deprecated and should be removed: + +- `app/decorators` + + We should put decorator-type methods in models themselves. + +- `app/view_objects` + + We should use View Components (`app/components`) instead. + +## 2. Environments + +There are 2 kinds of environments we need to maintain: + +1. Rails environment (`RAILS_ENV`) + + There are 3 Rails environments: + + - `production` + - `test` + - `development` + +2. Application environment (`APP_ENV`) - This is commonly known as Hosting environment in other BAT applications. + + This environment is used to determine the settings of the application. + + There are 5 Application environments: + + - `review` + - `qa` + - `staging` + - `sandbox` + - `production` + + The `loadtest` and `rollover` environments are deprecated and should be removed. We can use `staging` temporarily for these use-cases.