diff --git a/public/diagram.png b/public/diagram.png
new file mode 100644
index 00000000..872ae906
Binary files /dev/null and b/public/diagram.png differ
diff --git a/src/content/docs/products/ontrack/documentation/Documentation_Backlog_for_rails/Documentation-Backlog-Rails-Backend.md b/src/content/docs/products/ontrack/documentation/Documentation_Backlog_for_rails/Documentation-Backlog-Rails-Backend.md
new file mode 100644
index 00000000..5c82b883
--- /dev/null
+++ b/src/content/docs/products/ontrack/documentation/Documentation_Backlog_for_rails/Documentation-Backlog-Rails-Backend.md
@@ -0,0 +1,1563 @@
+---
+title: Documentation Backlog - Rails Backend
+---
+
+# Doubtfire API
+
+## Student Name: Zhongyu Zhang
+
+## Student ID: 222076406
+
+## User Authentication and Management (Devise)
+
+### Sign In
+
+- **Request Method**: GET
+- **URL**: `/users/sign_in`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+
+ ```html
+
+ ```
+
+- **Request Method**: POST
+- **URL**: `/users/sign_in`
+- **Parameters**:
+ ```json
+ {
+ "user": {
+ "email": "user@example.com",
+ "password": "password"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Signed in successfully."
+ }
+ ```
+
+- **Request Method**: DELETE
+- **URL**: `/users/sign_out`
+- **Parameters**: None
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "message": "Signed out successfully."
+ }
+ ```
+
+### Password Management
+
+- **Request Method**: GET
+- **URL**: `/users/password/new`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+
+ ```html
+
+ ```
+
+- **Request Method**: GET
+- **URL**: `/users/password/edit`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+
+ ```html
+
+ ```
+
+- **Request Method**: PATCH/PUT/POST
+- **URL**: `/users/password`
+- **Parameters**:
+ ```json
+ {
+ "user": {
+ "email": "user@example.com",
+ "password": "new_password",
+ "password_confirmation": "new_password"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "message": "Password updated successfully."
+ }
+ ```
+
+### User Registration
+
+- **Request Method**: GET
+- **URL**: `/users/sign_up`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+
+ ```html
+
+ ```
+
+- **Request Method**: GET
+- **URL**: `/users/edit`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+
+ ```html
+
+ ```
+
+- **Request Method**: PATCH/PUT/DELETE/POST
+- **URL**: `/users`
+- **Parameters**:
+ ```json
+ {
+ "user": {
+ "email": "user@example.com",
+ "password": "password",
+ "password_confirmation": "password"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "message": "User registered/updated successfully."
+ }
+ ```
+
+## File Downloads
+
+### Download Course Resources
+
+- **Request Method**: GET
+- **URL**: `/api/submission/unit/:id/portfolio`
+- **Parameters**:
+ ```json
+ {
+ "id": "unit_id"
+ }
+ ```
+- **Response Format**: File
+- **Example**:
+
+ ```json
+ {
+ "file": "portfolio.pdf"
+ }
+ ```
+
+- **Request Method**: GET
+- **URL**: `/api/submission/unit/:id/task_definitions/:task_def_id/download_submissions`
+- **Parameters**:
+ ```json
+ {
+ "id": "unit_id",
+ "task_def_id": "task_definition_id"
+ }
+ ```
+- **Response Format**: File
+- **Example**:
+
+ ```json
+ {
+ "file": "submissions.zip"
+ }
+ ```
+
+- **Request Method**: GET
+- **URL**: `/api/submission/unit/:id/task_definitions/:task_def_id/student_pdfs`
+- **Parameters**:
+ ```json
+ {
+ "id": "unit_id",
+ "task_def_id": "task_definition_id"
+ }
+ ```
+- **Response Format**: File
+- **Example**:
+
+ ```json
+ {
+ "file": "student_pdfs.zip"
+ }
+ ```
+
+- **Request Method**: GET
+- **URL**: `/api/units/:id/all_resources`
+- **Parameters**:
+ ```json
+ {
+ "id": "unit_id"
+ }
+ ```
+- **Response Format**: File
+- **Example**:
+ ```json
+ {
+ "file": "resources.zip"
+ }
+ ```
+
+## API Root and Documentation
+
+### API Root
+
+- **URL**: `/`
+- **Parameters**: None
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "message": "API Root"
+ }
+ ```
+
+### Swagger API Documentation
+
+- **URL**: `/api/docs`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+ ```html
+
+
+ Swagger API Documentation
+
+
+ ```
+
+## Sidekiq
+
+### Sidekiq Management Interface
+
+- **URL**: `/sidekiq`
+- **Parameters**: None
+- **Response Format**: HTML
+- **Example**:
+ ```html
+
+
+ Sidekiq Management
+
+
+ ```
+
+## Action Mailbox
+
+### Email Handling
+
+- **Request Method**: POST
+- **URL**: `/rails/action_mailbox/postmark/inbound_emails`
+- **Parameters**:
+ ```json
+ {
+ "email": {
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Email received via Postmark"
+ }
+ ```
+
+- **Request Method**: POST
+- **URL**: `/rails/action_mailbox/relay/inbound_emails`
+- **Parameters**:
+ ```json
+ {
+ "email": {
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Email received via Relay"
+ }
+ ```
+
+- **Request Method**: POST
+- **URL**: `/rails/action_mailbox/sendgrid/inbound_emails`
+- **Parameters**:
+ ```json
+ {
+ "email": {
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Email received via Sendgrid"
+ }
+ ```
+
+- **Request Method**: GET
+- **URL**: `/rails/action_mailbox/mandrill/inbound_emails`
+- **Parameters**: None
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Mandrill health check passed"
+ }
+ ```
+
+- **Request Method**: POST
+- **URL**: `/rails/action_mailbox/mandrill/inbound_emails`
+- **Parameters**:
+ ```json
+ {
+ "email": {
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+
+ ```json
+ {
+ "message": "Email received via Mandrill"
+ }
+ ```
+
+- **Request Method**: POST
+- **URL**: `/rails/action_mailbox/mailgun/inbound_emails/mime`
+- **Parameters**:
+ ```json
+ {
+ "email": {
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ }
+ ```
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "message": "Email received via Mailgun"
+ }
+ ```
+
+## Action Mailbox Conductor
+
+### Conductor Management Interface
+
+- **Request Method**: GET
+- **URL**: `/rails/conductor/action_mailbox/inbound_emails`
+- **Parameters**: None
+- **Response Format**: JSON
+- **Example**:
+ ```json
+ {
+ "inbound_emails": [
+ {
+ "id": "1",
+ "to": "example@domain.com",
+ "from": "sender@domain.com",
+ "subject": "Hello",
+ "body": "Email body"
+ }
+ ]
+ }
+ ```
+
+# Environment Configurations
+
+This section documents the configurations found in the `config/environments` directory of the Rails
+backend for Ontrack. Each file configures the application behavior for different environments such
+as development, production, staging, and testing.
+
+## 1. Development Environment (`development.rb`)
+
+### Purpose
+
+The `development.rb` file contains settings specific to the development environment. It prioritizes
+ease of development and debugging.
+
+### Key Configurations
+
+- **Code Reloading:**
+ - `config.cache_classes = false`: Disables class caching, allowing code changes to be reflected
+ without restarting the server.
+- **Eager Loading:**
+ - `config.eager_load = false`: Disables eager loading of code on boot.
+- **Error Reporting:**
+ - `config.consider_all_requests_local = true`: Shows full error reports.
+- **Caching:**
+ - Conditional caching based on environment variables or presence of a file.
+ - `config.action_controller.perform_caching = true/false`: Enables or disables caching.
+ - `config.cache_store = :memory_store / :redis_cache_store / :null_store`: Configures the cache
+ store based on environment variables.
+- **File Storage:**
+ - `config.active_storage.service = :local`: Stores uploaded files on the local file system.
+- **Action Mailer:**
+ - `config.action_mailer.raise_delivery_errors = false`: Ignores delivery errors.
+ - `config.action_mailer.perform_caching = false`: Disables mailer caching.
+ - `config.action_mailer.delivery_method = :file`: Writes emails to file instead of sending them.
+- **Deprecation Notices:**
+ - `config.active_support.deprecation = :log`: Logs deprecation warnings.
+ - `config.active_support.disallowed_deprecation = :raise`: Raises exceptions for disallowed
+ deprecations.
+ - `config.active_support.disallowed_deprecation_warnings = []`: Specifies which deprecation
+ warnings are disallowed.
+- **Database:**
+ - `config.active_record.migration_error = :page_load`: Raises an error on page load if there are
+ pending migrations.
+ - `config.active_record.verbose_query_logs = true`: Highlights code that triggered database
+ queries in logs.
+- **File Watcher:**
+ - `config.file_watcher = ActiveSupport::EventedFileUpdateChecker`: Uses an evented file watcher to
+ asynchronously detect changes.
+- **Logging:**
+ - `config.log_level = :debug`: Sets the logging level to debug.
+- **Miscellaneous:**
+ - `config.action_dispatch.best_standards_support = :builtin`: Uses best-standards-support built
+ into browsers.
+ - `Faker::Config.random = Random.new(77)`: Sets deterministic randomness for Faker.
+ - `config.pdfgen_quiet = false`: Sets the verbosity of pdfgen logs.
+ - `config.active_record.encryption.key_derivation_salt = ENV['DF_ENCRYPTION_KEY_DERIVATION_SALT'] || 'default_salt'`:
+ Configures ActiveRecord encryption keys.
+
+## 2. Production Environment (`production.rb`)
+
+### Purpose
+
+The `production.rb` file contains settings specific to the production environment, optimized for
+performance and security.
+
+### Key Configurations
+
+- **Code Caching:**
+ - `config.cache_classes = true`: Enables class caching for better performance.
+- **Caching:**
+ - `config.cache_store = :redis_cache_store`: Uses Redis for caching.
+ - Configures Redis connection and error handling.
+- **Error Reporting:**
+ - `config.consider_all_requests_local = false`: Disables full error reports.
+- **Static Files:**
+ - `config.serve_static_files = true`: Enables serving of static files.
+- **Eager Loading:**
+ - `config.eager_load = true`: Enables eager loading of code on boot.
+- **I18n:**
+ - `config.i18n.fallbacks = true`: Enables locale fallbacks for I18n.
+- **Deprecation Notices:**
+ - `config.active_support.deprecation = :notify`: Sends deprecation notices to registered
+ listeners.
+- **Middleware:**
+ - `config.middleware.delete Rack::Runtime`: Removes runtime middleware to harden against timing
+ attacks.
+- **Logging:**
+ - `config.log_level = :info`: Sets the logging level to info.
+- **Action Mailer:**
+ - `config.action_mailer.perform_deliveries = (ENV['DF_MAIL_PERFORM_DELIVERIES'] || 'yes') == 'yes'`:
+ Configures whether to perform email deliveries.
+ - `config.action_mailer.delivery_method = :smtp`: Uses SMTP for email delivery.
+ - Configures SMTP settings based on environment variables.
+- **ActiveRecord Encryption:**
+ - Configures ActiveRecord encryption keys using environment variables.
+
+## 3. Staging Environment (`staging.rb`)
+
+### Purpose
+
+The `staging.rb` file configures settings for the staging environment, which mirrors the production
+environment with minor changes.
+
+### Key Configurations
+
+- **SSL:**
+ - `config.force_ssl = false`: Disables forcing SSL.
+- **Logging:**
+ - `config.log_level = :info`: Sets the logging level to info.
+- **Deterministic Randomness:**
+ - `Faker::Config.random = Random.new(77)`: Sets deterministic randomness for Faker.
+
+## 4. Test Environment (`test.rb`)
+
+### Purpose
+
+The `test.rb` file contains settings specific to the test environment, optimized for running the
+application's test suite.
+
+### Key Configurations
+
+- **Code Caching:**
+ - `config.cache_classes = true`: Enables class caching for tests.
+- **Static Files:**
+ - `config.serve_static_files = true`: Configures static asset server for tests.
+ - `config.static_cache_control = 'public, max-age=3600'`: Sets Cache-Control headers.
+- **Eager Loading:**
+ - `config.eager_load = false`: Disables eager loading.
+- **Error Reporting:**
+ - `config.consider_all_requests_local = true`: Shows full error reports.
+- **Caching:**
+ - `config.action_controller.perform_caching = false`: Disables caching.
+- **Exception Handling:**
+ - `config.action_dispatch.show_exceptions = false`: Raises exceptions instead of rendering
+ templates.
+- **Request Forgery Protection:**
+ - `config.action_controller.allow_forgery_protection = false`: Disables request forgery
+ protection.
+- **Action Mailer:**
+ - `config.action_mailer.delivery_method = :test`: Uses the test delivery method for emails.
+- **Deprecation Notices:**
+ - `config.active_support.deprecation = :stderr`: Prints deprecation notices to stderr.
+- **Logging:**
+ - `config.log_level = :warn`: Sets the logging level to warn.
+- **ActiveRecord Encryption:**
+ - Configures ActiveRecord encryption keys.
+- **Environment Variables:**
+ - Sets specific environment variables for the test environment.
+
+# Initializer Configurations
+
+This section documents the configurations found in the `config/initializers` directory of the Rails
+backend for Ontrack. Each file configures the application behavior during the initialization phase.
+
+## 1. Backtrace Silencer (`backtrace_silencers.rb`)
+
+### Purpose
+
+This file allows you to add or remove backtrace silencers for libraries you don't wish to see in
+your backtraces.
+
+### Key Configurations
+
+- **Add Silencer**:
+ ```ruby
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+ ```
+- **Remove All Silencers**:
+ ```ruby
+ # Rails.backtrace_cleaner.remove_silencers!
+ ```
+
+## 2. Devise Configuration (`devise.rb`)
+
+### Purpose
+
+This file is used to configure Devise, a flexible authentication solution for Rails.
+
+### Key Configurations
+
+- **Mailer Configuration**:
+
+ ```ruby
+ config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
+ ```
+
+- **ORM Configuration**:
+
+ ```ruby
+ require 'devise/orm/active_record'
+ ```
+
+- **Authentication Keys**:
+
+ ```ruby
+ config.authentication_keys = [:username]
+ ```
+
+- **Case-Insensitive Keys**:
+
+ ```ruby
+ config.case_insensitive_keys = [:email, :username]
+ ```
+
+- **Whitespace Stripped Keys**:
+
+ ```ruby
+ config.strip_whitespace_keys = [:email, :username]
+ ```
+
+- **Session Storage**:
+
+ ```ruby
+ config.skip_session_storage = [:http_auth]
+ ```
+
+- **Password Length**:
+
+ ```ruby
+ config.password_length = 8..128
+ ```
+
+- **Token Expiry**:
+
+ ```ruby
+ config.reset_password_within = 6.hours
+ ```
+
+- **Sign Out Method**:
+
+ ```ruby
+ config.sign_out_via = :delete
+ ```
+
+- **Navigational Formats**:
+
+ ```ruby
+ config.navigational_formats = ['*/*', :json]
+ ```
+
+- **Secret Key**:
+
+ ```ruby
+ config.secret_key = Doubtfire::Application.secrets.secret_key_devise if Rails.env.production?
+ ```
+
+- **LDAP Configuration**:
+
+ ```ruby
+ config.ldap_use_admin_to_bind = ENV.fetch('DF_LDAP_USE_ADMIN_TO_BIND', 'false').to_s.downcase != 'false'
+ ```
+
+- **Responder Configuration**:
+ ```ruby
+ config.responder.error_status = :unprocessable_entity
+ config.responder.redirect_status = :see_other
+ ```
+
+## 3. Inflections (`inflections.rb`)
+
+### Purpose
+
+This file is used to add new inflection rules for pluralization and singularization of words.
+
+### Key Configurations
+
+- **Irregular Inflections**:
+ ```ruby
+ ActiveSupport::Inflector.inflections do |inflect|
+ inflect.irregular 'campus', 'campuses'
+ end
+ ```
+
+## 4. Log Initializer (`log_initializer.rb`)
+
+### Purpose
+
+This file configures the logging output and format.
+
+### Key Configurations
+
+- **Log Output to STDOUT**:
+
+ ```ruby
+ unless Rails.env.test?
+ Rails.logger.broadcast_to(ActiveSupport::Logger.new($stdout))
+ end
+ ```
+
+- **Custom Log Formatter**:
+
+ ```ruby
+ class FormatifFormatter < Logger::Formatter
+ include ActiveSupport::TaggedLogging::Formatter
+
+ def call(severity, timestamp, _progname, msg)
+ remote_ip = Thread.current.thread_variable_get(:ip) || 'unknown'
+ "#{timestamp},#{remote_ip},#{severity}: #{msg.to_s.gsub(/\n/, '\n')}\n"
+ end
+ end
+
+ Rails.logger.formatter = FormatifFormatter.new
+ ```
+
+## 5. MIME Types (`mime_types.rb`)
+
+### Purpose
+
+This file allows you to add new MIME types for use in respond_to blocks.
+
+### Key Configurations
+
+- **Add New MIME Types**:
+ ```ruby
+ # Mime::Type.register "text/richtext", :rtf
+ # Mime::Type.register_alias "text/html", :iphone
+ ```
+
+## 6. Session Store (`session_store.rb`)
+
+### Purpose
+
+This file configures how session data is stored.
+
+### Key Configurations
+
+- **Cookie Store**:
+
+ ```ruby
+ Doubtfire::Application.config.session_store :cookie_store, key: '_doubtfire_session'
+ ```
+
+- **ActiveRecord Store**:
+ ```ruby
+ # Doubtfire::Application.config.session_store :active_record_store
+ ```
+
+## 7. Sidekiq Configuration (`sidekiq.rb`)
+
+### Purpose
+
+This file configures Sidekiq, a background job processing library.
+
+### Key Configurations
+
+- **Server Configuration**:
+
+ ```ruby
+ Sidekiq.configure_server do |config|
+ config.redis = { url: ENV.fetch('DF_REDIS_SIDEKIQ_URL', 'redis://localhost:6379/1') }
+ config.logger = Rails.logger
+ end
+ ```
+
+- **Client Configuration**:
+ ```ruby
+ Sidekiq.configure_client do |config|
+ config.redis = { url: ENV.fetch('DF_REDIS_SIDEKIQ_URL', 'redis://localhost:6379/1') }
+ config.logger = Rails.logger
+ end
+ ```
+
+## 8. Swagger Configuration (`swagger.rb`)
+
+### Purpose
+
+This file configures Swagger, a tool for documenting APIs.
+
+### Key Configurations
+
+- **Swagger URL and App URL**:
+
+ ```ruby
+ GrapeSwaggerRails.options.url = '/api/swagger_doc'
+ GrapeSwaggerRails.options.before_action do
+ GrapeSwaggerRails.options.app_url = request.protocol + request.host_with_port
+ end
+
+ GrapeSwaggerRails.options.before_filter_proc = proc {
+ GrapeSwaggerRails.options.app_url = request.protocol + request.host_with_port
+ }
+ ```
+
+## 9. TurnItIn Initializer (`turn_it_in_initializer.rb`)
+
+### Purpose
+
+This file initializes the TurnItIn API configuration.
+
+### Key Configurations
+
+- **Load Configuration**:
+
+ ```ruby
+ require_relative '../../app/helpers/turn_it_in'
+ config = Doubtfire::Application.config
+
+ TurnItIn.load_config(config)
+ ```
+
+- **Background Jobs**:
+
+ ```ruby
+ if config.tii_enabled
+ require 'tca_client'
+ config.logger = Rails.logger
+
+ unless Rails.env.test?
+ config.after_initialize do
+ TurnItIn.launch_tii(with_webhooks: Rails.env.production?)
+ end
+ end
+
+ if Rails.env.development?
+ TCAClient.configure do |tii_config|
+ tii_config.debugging = true
+ end
+ end
+ end
+ ```
+
+## 10. Wrap Parameters (`wrap_parameters.rb`)
+
+### Purpose
+
+This file configures parameter wrapping for JSON requests.
+
+### Key Configurations
+
+- **Enable Parameter Wrapping for JSON**:
+
+ ```ruby
+ ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json]
+ end
+ ```
+
+- **Disable Root Element in JSON**:
+ ```ruby
+ ActiveSupport.on_load(:active_record) do
+ self.include_root_in_json = false
+ end
+ ```
+
+# Locale Configurations
+
+This section documents the configurations found in the `config/locales` directory of the Rails
+backend for Ontrack. Each file contains translations and localization settings for the application.
+
+## 1. Devise Locale (`devise.en.yml`)
+
+### Purpose
+
+This file contains the English translations for error messages and notifications used by the Devise
+authentication library.
+
+### Key Configurations
+
+- **Error Messages**:
+
+ ```yaml
+ en:
+ errors:
+ messages:
+ expired: "has expired, please request a new one"
+ not_found: "not found"
+ already_confirmed: "was already confirmed, please try signing in"
+ not_locked: "was not locked"
+ not_saved:
+ one: "1 error prohibited this %{resource} from being saved:"
+ other: "%{count} errors prohibited this %{resource} from being saved:"
+ ```
+
+- **Devise Notifications**:
+ ```yaml
+ en:
+ devise:
+ failure:
+ already_authenticated: "You are already signed in."
+ unauthenticated: "You need to sign in before continuing."
+ unconfirmed: "You have to confirm your account before continuing."
+ locked: "Your account is locked."
+ invalid: "Invalid username or password."
+ invalid_token: "Invalid authentication token."
+ timeout: "Your session expired, please sign in again to continue."
+ inactive: "Your account was not activated yet."
+ sessions:
+ signed_in: "Signed in successfully."
+ signed_out: "Signed out successfully."
+ passwords:
+ send_instructions:
+ "You will receive an email with instructions about how to reset your password in a few
+ minutes."
+ updated: "Your password was changed successfully. You are now signed in."
+ updated_not_active: "Your password was changed successfully."
+ send_paranoid_instructions:
+ "If your e-mail exists on our database, you will receive a password recovery link on your
+ e-mail"
+ confirmations:
+ send_instructions:
+ "You will receive an email with instructions about how to confirm your account in a few
+ minutes."
+ send_paranoid_instructions:
+ "If your e-mail exists on our database, you will receive an email with instructions about
+ how to confirm your account in a few minutes."
+ confirmed: "Your account was successfully confirmed. You are now signed in."
+ registrations:
+ signed_up: "Welcome! You have signed up successfully."
+ inactive_signed_up:
+ "You have signed up successfully. However, we could not sign you in because your account
+ is %{reason}."
+ updated: "You updated your account successfully."
+ destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon."
+ reasons:
+ inactive: "inactive"
+ unconfirmed: "unconfirmed"
+ locked: "locked"
+ unlocks:
+ send_instructions:
+ "You will receive an email with instructions about how to unlock your account in a few
+ minutes."
+ unlocked: "Your account was successfully unlocked. You are now signed in."
+ send_paranoid_instructions:
+ "If your account exists, you will receive an email with instructions about how to unlock
+ it in a few minutes."
+ omniauth_callbacks:
+ success: "Successfully authorized from %{kind} account."
+ failure: 'Could not authorize you from %{kind} because "%{reason}".'
+ mailer:
+ confirmation_instructions:
+ subject: "Confirmation instructions"
+ reset_password_instructions:
+ subject: "Reset password instructions"
+ unlock_instructions:
+ subject: "Unlock Instructions"
+ ```
+
+## 2. Bootstrap Locale (`en.bootstrap.yml`)
+
+### Purpose
+
+This file contains English translations for common actions and labels used in the Bootstrap
+framework.
+
+### Key Configurations
+
+- **Helper Actions and Links**:
+ ```yaml
+ en:
+ helpers:
+ actions: "Actions"
+ links:
+ back: "Back"
+ cancel: "Cancel"
+ confirm: "Are you sure?"
+ destroy: "Delete"
+ new: "New"
+ edit: "Edit"
+ titles:
+ edit: "Edit"
+ save: "Save"
+ new: "New"
+ delete: "Delete"
+ ```
+
+## 3. General Locale (`en.yml`)
+
+### Purpose
+
+This file contains general English translations used in the application.
+
+### Key Configurations
+
+- **General Translations**:
+ ```yaml
+ en:
+ hello: "Hello world"
+ ```
+
+## 4. Simple Form Locale (`simple_form.en.yml`)
+
+### Purpose
+
+This file contains English translations for the Simple Form gem, which is used to create forms in
+Rails applications.
+
+### Key Configurations
+
+- **Form Labels and Hints**:
+ ```yaml
+ en:
+ simple_form:
+ "yes": "Yes"
+ "no": "No"
+ required:
+ text: "required"
+ mark: "*"
+ error_notification:
+ default_message: "Please review the problems below:"
+ # Labels and hints examples
+ # labels:
+ # defaults:
+ # password: 'Password'
+ # user:
+ # new:
+ # email: 'E-mail to sign in.'
+ # edit:
+ # email: 'E-mail.'
+ # hints:
+ # defaults:
+ # username: 'User name to sign in.'
+ # password: 'No special characters, please.'
+ ```
+
+# Additional Configurations
+
+This section documents various configuration files found in the `config` directory of the Rails
+backend for Ontrack. These files include core application settings, database configurations,
+institution-specific settings, and more.
+
+## 1. Application Configuration (`application.rb`)
+
+### Purpose
+
+This file contains the core configuration settings for the Rails application.
+
+### Key Configurations
+
+- **Load Defaults**:
+
+ ```ruby
+ config.load_defaults 7.0
+ ```
+
+- **Environment Variables**:
+
+ ```ruby
+ Dotenv::Railtie.load
+ ```
+
+- **Authentication Method**:
+
+ ```ruby
+ config.auth_method = (ENV['DF_AUTH_METHOD'] || :database).to_sym
+ ```
+
+- **Student Work Directory**:
+
+ ```ruby
+ config.student_work_dir = ENV['DF_STUDENT_WORK_DIR'] || "#{Rails.root}/student_work"
+ ```
+
+- **Credentials**:
+
+ ```ruby
+ credentials.secret_key_base = ENV.fetch('DF_SECRET_KEY_BASE', Rails.env.production? ? nil : 'default_secret_key_base')
+ credentials.secret_key_attr = ENV.fetch('DF_SECRET_KEY_ATTR', Rails.env.production? ? nil : 'default_secret_key_attr')
+ credentials.secret_key_devise = ENV.fetch('DF_SECRET_KEY_DEVISE', Rails.env.production? ? nil : 'default_secret_key_devise')
+ credentials.secret_key_aaf = ENV.fetch('DF_SECRET_KEY_AAF', Rails.env.production? ? nil : 'secret_key_aaf')
+ credentials.secret_key_moss = ENV.fetch('DF_SECRET_KEY_MOSS', nil)
+ ```
+
+- **Institution Settings**:
+
+ ```ruby
+ config.institution = YAML.load_file("#{Rails.root}/config/institution.yml").with_indifferent_access
+ ```
+
+- **SAML Authentication**:
+
+ ```ruby
+ if config.auth_method == :saml
+ config.saml = HashWithIndifferentAccess.new
+ config.saml[:SAML_metadata_url] = ENV.fetch('DF_SAML_METADATA_URL', nil)
+ config.saml[:assertion_consumer_service_url] = ENV.fetch('DF_SAML_CONSUMER_SERVICE_URL', nil)
+ config.saml[:entity_id] = ENV.fetch('DF_SAML_SP_ENTITY_ID', nil)
+ config.saml[:idp_sso_target_url] = ENV.fetch('DF_SAML_IDP_TARGET_URL', nil)
+ config.saml[:idp_sso_signout_url] = ENV.fetch('DF_SAML_IDP_SIGNOUT_URL', nil)
+ config.saml[:idp_sso_cert] = ENV.fetch('DF_SAML_IDP_CERT', nil) if config.saml[:SAML_metadata_url].nil?
+ config.saml[:idp_name_identifier_format] = ENV['DF_SAML_IDP_SAML_NAME_IDENTIFIER_FORMAT'] || "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
+ end
+ ```
+
+- **AAF Authentication**:
+
+ ```ruby
+ if config.auth_method == :aaf
+ config.aaf = HashWithIndifferentAccess.new
+ config.aaf[:issuer_url] = ENV['DF_AAF_ISSUER_URL'] || 'https://rapid.test.aaf.edu.au'
+ config.aaf[:audience_url] = ENV.fetch('DF_AAF_AUDIENCE_URL', nil)
+ config.aaf[:callback_url] = ENV.fetch('DF_AAF_CALLBACK_URL', nil)
+ config.aaf[:redirect_url] = ENV.fetch('DF_AAF_UNIQUE_URL', nil)
+ config.aaf[:identity_provider_url] = ENV.fetch('DF_AAF_IDENTITY_PROVIDER_URL', nil)
+ config.aaf[:auth_signout_url] = ENV.fetch('DF_AAF_AUTH_SIGNOUT_URL', nil)
+ end
+ ```
+
+- **Localization**:
+
+ ```ruby
+ config.i18n.enforce_available_locales = true
+ ```
+
+- **Parameter Filtering**:
+
+ ```ruby
+ config.filter_parameters += %i(auth_token password password_confirmation)
+ ```
+
+- **Autoload Paths**:
+
+ ```ruby
+ config.autoload_paths += Dir[Rails.root.join('app')]
+ config.eager_load_paths += Dir[Rails.root.join('app')]
+ ```
+
+- **CORS Configuration**:
+ ```ruby
+ config.middleware.insert_before Warden::Manager, Rack::Cors do
+ allow do
+ origins '*'
+ resource '*', headers: :any, methods: %i(get post put delete options)
+ end
+ end
+ ```
+
+## 2. Boot Configuration (`boot.rb`)
+
+### Purpose
+
+This file sets up the gems listed in the Gemfile and speeds up boot time by caching expensive
+operations.
+
+### Key Configurations
+
+- **Bundler Setup**:
+
+ ```ruby
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
+ ```
+
+- **Bootsnap Setup**:
+ ```ruby
+ require 'bootsnap/setup'
+ ```
+
+## 3. Database Configuration (`database.yml`)
+
+### Purpose
+
+This file contains the database connection settings for different environments.
+
+### Key Configurations
+
+- **Development Environment**:
+
+ ```yaml
+ development:
+ adapter: <%= ENV['DF_DEV_DB_ADAPTER'] %>
+ database: <%= ENV['DF_DEV_DB_DATABASE'] %>
+ username: <%= ENV['DF_DEV_DB_USERNAME'] %>
+ password: <%= ENV['DF_DEV_DB_PASSWORD'] %>
+ host: <%= ENV['DF_DEV_DB_HOST'] %>
+ min_messages: warning
+ ```
+
+- **Test Environment**:
+
+ ```yaml
+ test:
+ adapter: <%= ENV['DF_TEST_DB_ADAPTER'] %>
+ database: <%= ENV['DF_TEST_DB_DATABASE'] %>
+ username: <%= ENV['DF_TEST_DB_USERNAME'] %>
+ password: <%= ENV['DF_TEST_DB_PASSWORD'] %>
+ host: <%= ENV['DF_TEST_DB_HOST'] %>
+ min_messages: warning
+ ```
+
+- **Staging Environment**:
+
+ ```yaml
+ staging:
+ adapter: <%= ENV['DF_STAGING_DB_ADAPTER'] %>
+ host: <%= ENV['DF_STAGING_DB_HOST'] %>
+ database: <%= ENV['DF_STAGING_DB_DATABASE'] %>
+ username: <%= ENV['DF_STAGING_DB_USERNAME'] %>
+ password: <%= ENV['DF_STAGING_DB_PASSWORD'] %>
+ ```
+
+- **Production Environment**:
+ ```yaml
+ production:
+ adapter: <%= ENV['DF_PRODUCTION_DB_ADAPTER'] %>
+ host: <%= ENV['DF_PRODUCTION_DB_HOST'] %>
+ database: <%= ENV['DF_PRODUCTION_DB_DATABASE'] %>
+ username: <%= ENV['DF_PRODUCTION_DB_USERNAME'] %>
+ password: <%= ENV['DF_PRODUCTION_DB_PASSWORD'] %>
+ ```
+
+## 4. Deakin Institution Settings (`deakin.rb`)
+
+### Purpose
+
+This file contains custom settings and methods for importing users into units for Deakin University.
+
+### Key Configurations
+
+- **Initialization**:
+
+ ```ruby
+ def initialize()
+ @base_url = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_BASE_URL', nil)
+ @client_id = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_CLIENT_ID', nil)
+ @client_secret = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_CLIENT_SECRET', nil)
+ @star_url = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_STAR_URL', nil)
+ @star_user = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_STAR_USER', nil)
+ @star_secret = ENV.fetch('DF_INSTITUTION_SETTINGS_SYNC_STAR_SECRET', nil)
+ end
+ ```
+
+- **Methods for User Import**:
+
+ ```ruby
+ def user_import_settings_for(headers)
+ if are_callista_headers?(headers)
+ {
+ missing_headers_lambda: ->(row) { missing_headers(row, ["person id", "surname", "given names", "unit code", "student attempt status", "email", "preferred given name", "campus"]) },
+ fetch_row_data_lambda: ->(row, unit) { fetch_callista_row(row, unit) },
+ replace_existing_tutorial: false
+ }
+ else
+ {
+ missing_headers_lambda: ->(row) { missing_headers(row, ["student_code", "first_name", "last_name", "email_address", "preferred_name", "subject_code", "activity_code", "campus", "day_of_week", "start_time", "location", "campus"]) },
+ fetch_row_data_lambda: ->(row, unit) { fetch_star_row(row, unit) },
+ replace_existing_tutorial: true
+ }
+ end
+ end
+ ```
+
+- **Synchronization Methods**:
+
+ ```ruby
+ def sync_enrolments(unit)
+ # Implementation for synchronizing enrolments
+ end
+
+ def fetch_timetable_data(unit)
+ # Implementation for fetching timetable data
+ end
+ ```
+
+## 5. Environment Initialization (`environment.rb`)
+
+### Purpose
+
+This file loads and initializes the Rails application.
+
+### Key Configurations
+
+- **Application Initialization**:
+ ```ruby
+ require_relative "application"
+ Doubtfire::Application.initialize!
+ ```
+
+## 6. Institution Configuration (`institution.yml`)
+
+### Purpose
+
+This file contains institution-specific settings and information.
+
+### Key Configurations
+
+- \*\*
+
+Institution Details\*\*:
+
+```yaml
+name: Doubtfire University
+email_domain: doubtfire.com
+host: localhost:3000
+product_name: Doubtfire
+settings: no_institution_setting.rb
+privacy: Privacy statement text...
+plagiarism: Plagiarism policy text...
+```
+
+## 7. LDAP Configuration (`ldap.yml`)
+
+### Purpose
+
+This file contains LDAP server settings for different environments.
+
+### Key Configurations
+
+- **Development Environment**:
+
+ ```yaml
+ development:
+ host: <%= ENV['DF_LDAP_HOST'] %>
+ port: <%= ENV['DF_LDAP_PORT'] %>
+ attribute: <%= ENV['DF_LDAP_ATTRIBUTE'] %>
+ base: <%= ENV['DF_LDAP_BASE'] %>
+ admin_user: <%= ENV['DF_LDAP_ADMIN_USER'] %>
+ admin_password: <%= ENV['DF_LDAP_ADMIN_PWD'] %>
+ ssl: <%= ENV['DF_LDAP_SSL'].to_s.downcase != "false" %>
+ ```
+
+- **Test Environment**:
+
+ ```yaml
+ test:
+ host: <%= ENV['DF_LDAP_HOST'] %>
+ port: <%= ENV['DF_LDAP_PORT'] %>
+ attribute: <%= ENV['DF_LDAP_ATTRIBUTE'] %>
+ base: <%= ENV['DF_LDAP_BASE'] %>
+ admin_user: <%= ENV['DF_LDAP_ADMIN_USER'] %>
+ admin_password: <%= ENV['DF_LDAP_ADMIN_PWD'] %>
+ ssl: <%= ENV['DF_LDAP_SSL'].to_s.downcase != "false" %>
+ ```
+
+- **Production Environment**:
+ ```yaml
+ production:
+ host: <%= ENV['DF_LDAP_HOST'] %>
+ port: <%= ENV['DF_LDAP_PORT'] %>
+ attribute: <%= ENV['DF_LDAP_ATTRIBUTE'] %>
+ base: <%= ENV['DF_LDAP_BASE'] %>
+ admin_user: <%= ENV['DF_LDAP_ADMIN_USER'] %>
+ admin_password: <%= ENV['DF_LDAP_ADMIN_PWD'] %>
+ ssl: <%= ENV['DF_LDAP_SSL'].to_s.downcase != "false" %>
+ ```
+
+## 8. No Institution Setting (`no_institution_setting.rb`)
+
+### Purpose
+
+This file contains default institution settings when no specific institution settings are provided.
+
+### Key Configurations
+
+- **Default Methods**:
+
+ ```ruby
+ def are_headers_institution_users?(headers)
+ false
+ end
+
+ def extract_user_from_row(row)
+ { unit_code: nil, username: nil, student_id: nil, first_name: nil, last_name: nil, email: nil, tutorials: nil }
+ end
+
+ def sync_enrolments(unit)
+ puts 'Unit sync not enabled'
+ end
+
+ def details_for_next_tutorial_stream(unit, activity_type)
+ counter = 1
+ begin
+ name = "#{activity_type.name} #{counter}"
+ abbreviation = "#{activity_type.abbreviation} #{counter}"
+ counter += 1
+ end while unit.tutorial_streams.where("abbreviation = :abbr OR name = :name", abbr: abbreviation, name: name).present?
+ [name, abbreviation]
+ end
+ ```
+
+## 9. Puma Configuration (`puma.rb`)
+
+### Purpose
+
+This file contains configuration settings for the Puma web server.
+
+### Key Configurations
+
+- **Thread Configuration**:
+
+ ```ruby
+ max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
+ min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
+ threads min_threads_count, max_threads_count
+ ```
+
+- **Port Configuration**:
+
+ ```ruby
+ port ENV.fetch("PORT") { 3000 }
+ ```
+
+- **Environment Configuration**:
+
+ ```ruby
+ environment ENV.fetch("RAILS_ENV") { "development" }
+ ```
+
+- **PID File**:
+
+ ```ruby
+ pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
+ ```
+
+- **Plugin**:
+ ```ruby
+ plugin :tmp_restart
+ ```
+
+## 10. Routes Configuration (`routes.rb`)
+
+### Purpose
+
+This file defines the routes for the Rails application.
+
+### Key Configurations
+
+- **Devise Routes**:
+
+ ```ruby
+ devise_for :users
+ ```
+
+- **API Routes**:
+
+ ```ruby
+ get 'api/submission/unit/:id/portfolio', to: 'portfolio_downloads#index'
+ get 'api/submission/unit/:id/task_definitions/:task_def_id/download_submissions', to: 'task_downloads#index'
+ get 'api/submission/unit/:id/task_definitions/:task_def_id/student_pdfs', to: 'task_submission_pdfs#index'
+ get 'api/units/:id/all_resources', to: 'lecture_resource_downloads#index'
+ ```
+
+- **Mounting Engines**:
+ ```ruby
+ mount ApiRoot => '/'
+ mount GrapeSwaggerRails::Engine => '/api/docs'
+ mount Sidekiq::Web => "/sidekiq"
+ ```
+
+## 11. Schedule Configuration (`schedule.rb`)
+
+### Purpose
+
+This file contains cron job schedules for the application.
+
+### Key Configurations
+
+- **Daily Update Task**:
+ ```ruby
+ set :output, "#{path}/log/cron.log"
+ every 1.day, at: '3:00 am' do
+ rake 'db:update_temporal'
+ end
+ ```
+
+## 12. Schedule Configuration (`schedule.yml`)
+
+### Purpose
+
+This file contains job schedules for background tasks.
+
+### Key Configurations
+
+- **Register Webhooks**:
+
+ ```yaml
+ register_webhooks:
+ cron: "every day at 5"
+ class: "TiiRegisterWebHookJob"
+ ```
+
+- **Progress TurnItIn Jobs**:
+ ```yaml
+ progress_turn_it_in_jobs:
+ cron: "every 30 minutes"
+ class: "TiiCheckProgressJob"
+ ```
+
+## 13. Storage Configuration (`storage.yml`)
+
+### Purpose
+
+This file contains configurations for storage services. Note that ActiveStorage is not used in this
+application.
+
+### Key Configurations
+
+- **Sample Storage Configuration**:
+
+ ```yaml
+ # local:
+ # service: Disk
+ # root: <%= Rails.root.join("storage") %>
+ ```
+
+- **Amazon S3 Configuration**:
+
+ ```yaml
+ # amazon:
+ # service: S3
+ # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+ # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+ # region: us-east-1
+ # bucket: your_own_bucket
+ ```
+
+- **Google Cloud Storage Configuration**:
+ ```yaml
+ # google:
+ # service: GCS
+ # project: your_project
+ # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
+ # bucket: your_own_bucket
+ ```
+
+# Architecture Diagram of the Doubtfire API
+
+The architecture diagram of the Doubtfire API illustrates the following components and their
+interactions:
+
+## Components
+
+1. **Client:**
+
+ - Represents the user interface, typically a web browser or a mobile app.
+ - Sends HTTP requests to the Web Server.
+
+2. **Web Server:**
+
+ - Handles incoming HTTP requests from the client.
+ - Serves static content (HTML, CSS, JavaScript).
+ - Forwards API requests to the Application Server via REST API.
+
+3. **Application Server:**
+
+ - Processes all business logic and data operations.
+ - Contains all API endpoints such as user authentication, file downloads, and email handling.
+ - Interacts with the Database using SQL.
+ - Communicates with Third-party Services via API.
+
+4. **Database:**
+
+ - Stores application data, including user information, files, and emails.
+ - The Application Server interacts with the Database through SQL queries.
+
+5. **Third-party Services:**
+ - Includes external services used by the application, such as payment gateways and email services
+ (Postmark, SendGrid, Mandrill, Mailgun).
+ - The Application Server communicates with these services through APIs.
+
+