# Introduction

Cortex [CMS](/glossary#cms) is a [multitenant](https://en.wikipedia.org/wiki/Multitenancy) identity, [custom content](/glossary#custom-content-cms) distribution/management and reporting platform built by the [Content Enablement](https://github.com/cb-talent-development) team at [CareerBuilder](https://github.com/careerbuilder). Its purpose is to provide central infrastructure for next-generation applications; exposing a single point of management while enabling quicker build-out of new software.

Cortex adheres to a headless, API-only architecture - it avoids a monolithic, all-in-one architecture associated with CMSs like WordPress or Drupal.

To jump straight into using Cortex CMS, please refer to either the [Docker Compose guide](/basics/setup/docker-compose) (recommended) or the [manual setup guide](/basics/setup/manual-setup).

[![CircleCI](https://circleci.com/gh/cortex-cms/cortex.svg?style=svg)](https://circleci.com/gh/cortex-cms/cortex) [![Maintainability](https://api.codeclimate.com/v1/badges/8c8b8b9137fa9f019aa5/maintainability)](https://codeclimate.com/github/cortex-cms/cortex/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/8c8b8b9137fa9f019aa5/test_coverage)](https://codeclimate.com/github/cortex-cms/cortex/test_coverage)

<div align="left"><img src="/files/-LBbOaGc-JQdyEH7bYRB" alt=""></div>

Copyright (c) CareerBuilder, LLC.


# Motivation

At CareerBuilder, we have a presence in almost every major country, each with immense content needs. We want to build rich, informative experiences for both job seekers and employers, recommend relevant content, and report on it so we can better serve our users and author more successful content in the future. We're also constantly adapting to changing business needs, spinning up new test vehicles for content as these use cases arise. In the past, we've typically used either WordPress or Drupal to build these experiences, but have found that the lack of a unified content strategy and platform has held us back.

## Why not the tried-and-true WordPress?

The management overhead of WordPress is minimal, but lacks distribution flexibility - we can't author content in one central location and distribute it to multiple location-specific websites. Instead, we have to have 20 different IT teams manage 20 different installations and accounts, or email 20 different people just to push out content from the top of the organization - for example, a company-wide sale, a new product initiative, and so on.

## Alright, but isn't Drupal really flexible?

Drupal has more advanced distribution tools - you can build a 'multitenant' site for many locales. Speed, relevancy, extensibility, and advanced distribution are major issues, however. Out of the box, Drupal lacks a search database like Elasticsearch or Solr, which limits both speed and relevancy, especially in more advanced use cases. Drupal's plugin and frontend/templating architecture tends to be very complicated, and PHP is no longer as commonplace among engineers - especially at CareerBuilder. Additionally, Drupal is not headless, which makes consuming content in non-traditional media, such as an ad network, a 3rd party property, a car, etc much more difficult - or impossible!

## Fine, you got me - but didn't you forget all the Custom Content CMSs?

We love the concepts of various API-centric [Custom Content CMSs](/glossary#custom-content-cms), which solve many of the aforementioned issues, but we have been hard-pressed to find one that's open source, is Ruby-based, and supports all the various features we found necessary, such as:

* Content from the top-down. We want to push down content from the lead content/marketing teams down to our field offices.
* Content from the bottom-up. If a field office creates a great piece of content, it should be shareable across tenants and up the chain to any tenant that would like to consume or localize it. This is similar to how public radio (and radio in general) [syndicates](https://en.wikipedia.org/wiki/Broadcast_syndication#Radio_syndication) and shares content.
* Responsive, bespoke content creation interfaces ([Wizards](/basics/designing-wizards)). Custom Content CMSs typically don't have great [content creator](/glossary#content-creator) experiences, as they've sacrificed good UI/UX for a better engineer/superadministrator experience.
* A search engine, which provides:
  * Advanced relevancy. CareerBuilder provides content recommendations based on Job Title/Occupancy codes, which tie in with internal data science APIs that further enrich these recommendations. Integrating all these needs with other CMSs would prove difficult. Cortex CMS allows engineers to to arbitrarily [extend the search engine](/advanced/developing-plugins/extending-search) via plugins.
  * Speed! For advanced queries, which are very common, normal databases just can't stack up to Lucene-based search engines.
* `FieldTypes` built as React components
* Drag-and-drop website/landing page builder and manager
* Lots more!

***Thus, Cortex CMS is born!***


# Core Concepts

## Content Types

In Cortex CMS, a `ContentType` allows a [superadministrator](/glossary#superadministrator) to model what kind of content gets delivered to the consuming application - your corporate or personal blog, resource center, marketplace, website and so on.

Unlike systems that hardcode your basic content types out of the box - Blogposts, Media, etc. - and require you to create tightly coupled plugins to mix in additional functionality, Cortex CMS allows you to compose your content types from the ground up, specific to each business case. To accomplish this, you combine the necessary `FieldTypes` that make up your content. Every `FieldType`available for use is provided as part of a plugin, allowing you to extend the system without directly modifying the 'core' platform.

Once a [content creator](/glossary#content-creator) has created actual content based on a `ContentType`, it is saved as a `ContentItem`.

## Field Types

When modeling `ContentTypes`, [superadministrators](/glossary#superadministrator) make use of individual `FieldTypes`, which can provide anything from input fields with types such as Text, Boolean, User, Media to static text, informative widgets, video & data previews, and much more.

Once a [content creator](/glossary#content-creator) has created content based on a `ContentType`, a `FieldItem` is created for each of the `FieldTypes` that make up the `ContentType`.

## Decorators

[Content creators](/glossary#content-creator) expect a creation experience that properly utilizes screen real estate, is informative, and can be reconfigured based on new business needs and challenges. Unlike systems such as Drupal, which simply stack each `FieldType` added to a `ContentType` one after the other in a giant, vertical view, Cortex CMS allows [superadministrators](/glossary#superadministrator) to design the create/edit/index experience by way of `Decorators`. These are simple JSON objects that, based on their `Decorator` type, adhere to a documented schema.

There are currently two primary `Decorator` types (though more can be added via plugins): `Wizard` and `Index`. By setting the type to `Wizard` and adhering to its documented schema, a [superadministrator](/glossary#superadministrator) can set up a CRUD interface that that can drop `Fields` into a flexible, responsive grid, configure individual `FieldTypes` for display to the [content creator](/glossary#content-creator), toggle a WYSIWYG editor, apply CSS classes directly to the rendered `Field`, utilize the data from one `Field` in another `Field`, and so on.

## State, Workflow & Scheduling

TBD

## Headless

TBD

## Search

TBD

## Content Library

TBD


# Prior Art

Cortex CMS is inspired by many CMSs already in the wild, including but not limited to:

* [WordPress](https://wordpress.com/) - By far the most popular CMS due to its inherent simplicity and great [content creator](/glossary#content-creator) experience. Lacks flexibility and advanced distribution.
* [Drupal](https://www.drupal.org/) - Supports slightly more advanced distribution models, but lacks a great [content creator](/glossary#content-creator) experience, is not headless (lacks an API, so it does not support more advanced distribution), and can be very difficult to maintain and scale.
* [HippoCMS](https://www.onehippo.org/) - Supports advanced distribution models, features a novel backend ([JCR](https://en.wikipedia.org/wiki/Content_repository_API_for_Java)), is headless, but is Java-based and potentially unwieldy.
* [Contentful](https://www.contentful.com/) - Supports advanced distribution models and is headless, but lacks a great [content creator](/glossary#content-creator) experience and is closed-source.
* [Prismic](https://prismic.io/) - similar to Contentful, but isn't quite as feature-rich, and is also closed source.
* [GraphCMS](https://graphcms.com/) - The closest analogue to Cortex CMS. Fully headless with a custom content model, the backend to this CMS is still closed-source.


# Examples

## Beta (Dynamic Content Models)

* Employer Resources - Article and Resource portal bringing relevant content to Employers. Frontend built with [Uberflip](https://www.uberflip.com/), which pulls from a Beta Cortex RSS Feed (which uses a custom `RSS` [Decorator](/core-concepts#decorators)) - [Live Site](https://resources.careerbuilder.com/)
* Many new clients to be documented soon

## Legacy (Hardcoded Content Models - *Deprecated*)

* [Advice and Resources](https://github.com/cbdr/consumer-main/) - Simple Jobseeker Resources platform built atop the Consumer Web site utilizing Legacy Cortex Posts and Rails. Content will eventually be dynamically dispersed across site (result pages, description pages, etc) - [Live Site](https://www.careerbuilder.com/advice)
* [Employer](https://github.com/cbdr/employer) - Redesigned Employer Marketing platform utilizing Legacy Cortex Webpages/Snippets and Rails. - [Live Site](https://hiring.careerbuilder.com/)
* [CB1 Lander Shell](https://github.com/cbdr/cb1-lander-shell) - Platform for hosting lander pages and experiments, utilizing Legacy Cortex Posts and Sinatra. - [Live Site](http://corporate.careerbuilder.com/)
* [CareerBuilder.com](https://github.com/cbdr/consumer-main) - The main Consumer Web site for CB.com uses Legacy Cortex Posts for the [Privacy](https://www.careerbuilder.com/privacy) and [Terms of Service](https://www.careerbuilder.com/terms) pages.


# Basics

Working with Cortex CMS as a [superadministrator](/glossary#superadministrator) may seem daunting at first blush, but we're here to walk you through every step and demonstrate the simplicity & power of the platform.

* [Setup](https://github.com/cortex-cms/cortex-cms/tree/ec0acc5e822e7cd071403cac968f82e8f6df4a96/basics/setup.md)
  * [Docker Compose](https://docs.cortexcms.org/basics/setup/docker-compose)
  * [Manual](/basics/setup/manual-setup)
  * [Core & Plugin Development](/basics/setup/core-and-plugin-development)
  * Engine Mounting *(coming soon)*
* [Deployment](/basics/deployment)
* [Tenancy & User Management](/basics/tenancy-and-user-management)
* [Building Content Types](/basics/building-content-types)
* [Data Validation](/basics/data-validation)
* [Designing Indexes](/basics/designing-indexes)
* [Designing Wizards](/basics/designing-wizards)
* [Consuming Content](/basics/consuming-content)
* [Scheduling Content](/basics/scheduling-content)
* [Search](https://github.com/cortex-cms/cortex-cms/tree/ec0acc5e822e7cd071403cac968f82e8f6df4a96/basics/search.md)


# Setup

If you're interested in local development with Cortex (relevant to [integration engineers](/glossary#integration-engineer), or those who wish to contribute to the project), these guides will walk you through the process across any POSIX OS.

* [Docker Compose](/basics/setup/docker-compose)
* [Manual](/basics/setup/manual-setup)
* [Core & Plugin Development](/basics/setup/core-and-plugin-development)
* Engine Mounting *(coming soon)*


# Docker Compose

## Environment Preparation

Install `docker` and `docker-compose` using the [installer](https://docs.docker.com/compose/install/#install-compose) or via your Operating System's package manager (`pacman`, for example), then launch the service.

## `cortex-starter` Preparation <a href="#cortex-starter-prep" id="cortex-starter-prep"></a>

As `cortex` itself is only a Rails Engine, it needs to be mounted within a parent Rails applicaton. [cortex-starter](https://github.com/cortex-cms/cortex-starter) serves as a starting point for new users, with `cortex` and `cortex-plugins-core` already mounted and configured with several example `ContentTypes`/`Decorators`. Start by cloning the repository:

```bash
$ git clone git@github.com:cortex-cms/cortex-starter.git && cd cortex-starter
```

## Provision & Launch Application

Provision and launch Cortex Starter, PostgreSQL, Redis, Elasticsearch, Sidekiq and live Webpack rebuild via Docker Compose:

```bash
$ docker-compose up
```

Once complete, the admin interface will be accessible locally at `http://localhost:3000`. To access Cortex CMS as superadmin, login as `admin@cortexcms.org` with password `welcome1`.


# Manual Setup

## `cortex-starter` Preparation

As `cortex` itself is only a Rails Engine, it needs to be mounted within a parent Rails applicaton. [cortex-starter](https://github.com/cortex-cms/cortex-starter) serves as a starting point for new users, with `cortex` and `cortex-plugins-core` already mounted and configured with several example `ContentTypes`/`Decorators`. Start by cloning the repository:

```bash
$ git clone git@github.com:cortex-cms/cortex-starter.git && cd cortex-starter
```

## Environment

Copy and rename the example `.env.example` file as `.env` and modify it to match your environment.

For a rudimentary setup, these variables should be configured:

* Execute `$ bin/rails secret` twice to generate both an `APP_SECRET` and `DEVISE_SECRET`
* If the superuser isn't used for the app databases, the `DATABASE_USERNAME` and `DATABASE_PASSWORD` should be set accordingly.

## Dependencies

### System

#### macOS

* Install the Xcode Command Line tools:

```bash
$ xcode-select --install
```

* Install all Cortex system-wide dependencies (and the `readline` Ruby/`byebug` build dependency) using [Homebrew](http://brew.sh/) from the `Brewfile` via `$ brew install $(cat Brewfile|grep -v "#")`
* Install Ruby via [rbenv](https://github.com/sstephenson/rbenv) or [rvm](https://rvm.io/).
* Enable system agents:

```bash
$ ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents
$ ln -sfv /usr/local/opt/elasticsearch/*.plist ~/Library/LaunchAgents
$ ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents
```

and start them with `brew services`:

```bash
$ brew services start postgresql
$ brew services start elasticsearch
$ brew services start redis
```

or `launchctl`:

```bash
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.elasticsearch.plist
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
```

#### Linux

* Install all Cortex system-wide dependencies (and the `readline` Ruby/`byebug` build dependency) using your distribution's package manager (`pacman`, `apt-get`, `yum`, etc). For example, with Ubuntu's `apt-get`:

```bash
$ apt-get install libreadline6-dev postgresql postgresql-contrib redis-server openjdk-8-jre imagemagick jpegoptim ghostscript
```

{% hint style="info" %}
Ubuntu and Redhat/Fedora do not have an official `elasticsearch` package - you must use Elasticsearch's repositories for [APT](https://www.elastic.co/guide/en/elasticsearch/reference/current/deb.html) or [RPM](https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html) or follow these [manual instructions](https://www.elastic.co/guide/en/elasticsearch/reference/current/_installation.html). The same goes for `phantomjs`. Build from [source](http://phantomjs.org/download.html) or use a [PPA](https://launchpad.net/ubuntu/+ppas?name_filter=phantomjs). Additionally, `yarn` will need its repository added for these distributions. Follow these [instructions](https://yarnpkg.com/lang/en/docs/install). Other Linux distributions likely have these as prebuilt packages in their official or user repositories.
{% endhint %}

* Install Ruby via [rbenv](https://github.com/sstephenson/rbenv) or [rvm](https://rvm.io/).
* Enable & start system agents using your distribution's service manager frontend, which is likely `systemd`'s frontend, `systemctl`:

```bash
$ systemctl enable --now postgresql elasticsearch redis
```

### Application

* Install Bundler and its dependencies:

```bash
$ gem install bundler && bin/bundle install
```

* Install `node` dependencies using `yarn`:

```bash
$ bin/yarn install
```

## Data Provisioning

### Quick

`cortex-starter` ships with an automated setup script. Execute this in lieu of the Manual Setup steps below, if you're comfortable doing so:

```bash
$ bin/setup
```

### Manual

* Create databases:

```bash
$ bin/rails db:create
```

* Initialize the schema:

```bash
$ bin/rails db:schema:load
```

* Seed database with a top-level tenant, the superuser and Custom Content data, then rebuild the Elasticsearch index:

```bash
$ bin/rails db:seed
$ bin/rails cortex_starter:content_types:seed
$ bin/rails cortex:rebuild_indexes
```

## Server

Start Cortex, Sidekiq and live Webpack rebuild via Foreman with the `dev-server` script:

```bash
$ bin/dev-server
```

The admin interface should now be accessible locally at `http://localhost:3000`. To access Cortex as superadmin, login as `admin@cortexcms.org` with password `welcome1`.


# Core & Plugin Development

## Local Development Setup

First, clone the necessary repositories:

```bash
$ git clone git@github.com:cortex-cms/cortex-starter.git
$ git clone git@github.com:cortex-cms/cortex.git
$ git clone git@github.com:cortex-cms/cortex-plugins-core.git
$ git clone your-plugin-repo-here.git
```

Use `pwd` to retrieve the fully qualified path for each engine, then modify each of the following files to point to the relevant local dependencies:

* `cortex/Gemfile`
* `cortex/spec/dummy/package.json`
* `cortex-starter/Gemfile`
* `cortex-starter/package.json`

For example:

{% code title="cortex-starter/Gemfile" %}

```ruby
# Cortex
gem 'cortex', path: '/home/testuser/repos/cortex'
gem 'cortex-plugins-core', path: '/home/testuser/repos/cortex-plugins-core'
```

{% endcode %}

{% code title="cortex-starter/package.json" %}

```javascript
"cortex": "/home/testuser/repos/cortex",
"cortex-plugins-core": "/home/testuser/repos/cortex-plugins-core"
```

{% endcode %}

Lastly, re-install dependencies in the relevant projects.

## Running Test Suite

Initialize the dummy application:

```bash
$ cd cortex
$ RAILS_ENV=test spec/dummy/bin/setup
```

To run Ruby and JavaScript specs, utilize:

```bash
$ RAILS_ENV=test bin/rails app:spec
$ RAILS_ENV=test bin/rails app:spec:javascript
```


# Deployment

> Note: Docker Compose instructions coming soon

If you want to self-host Cortex CMS, this guide is for you. Currently, only [Manual Setup](/basics/setup/manual-setup) is officially supported.

## Configuration

Deploying the `development` environment as a non-local server will require an additional environmental variable be set:

```
DEPLOYED=true
```

This will configure various things such as [dotenv](https://github.com/bkeepers/dotenv) to behave normally in a deployed scenario.


# Tenancy & User Management

> TBD - Tenancy and User Management are currently in heavy flux


# Building Content Types

> **Note**: We've temporarily removed these very old instructions, as they need to be updated with clearer language, recent changes, and more detail.


# Data Validation

> Note: These are very old instructions, and need to be updated with clearer language, recent changes, and more detail

Each FieldType defines the validations that can be run on a FieldItem's data. It should have a hash where the keys are the different types of validations that can be run, and the values are method names that will be called to determine if the requested Field validation is legitimate:

```
VALIDATION_TYPES = {
  length: :valid_length_validation?,
  presence: :valid_presence_validation?
}.freeze
```

In order to define the validations that can be run, we use the [validators defined by Rails](https://github.com/rails/rails/tree/master/activemodel/lib/active_model/validations). You can also write [custom validators](http://guides.rubyonrails.org/active_record_validations.html#custom-validators) that would be used in the same way. This makes it easy to adhere to the same syntax used with ActiveRecord validations. When creating a Field, first it checks to ensure that the requested validations are consistent with the validations its FieldType provides, e.g. if a TextFieldType supports presence and length validations, you will not be able to add a numericality validation. Then the FieldType tests to see that any requested Field validations are allowed by instantiating the associated Validator and catching any ArgumentError or NoMethodError that gets thrown. If an error is thrown, then the syntax or content of the Field validation is incorrect somehow. If there is no error, then the Field validation is allowed.

The Field validations themselves are run when creating a ContentItem and its associated FieldItems. A ContentItem is only considered valid if all of its FieldItems are valid. To determine validity, the FieldItem instantiates the FieldType, passes in its data, and tells the FieldType to run the validations hash specified by the Field.

```
class TextFieldType
  def text_length
    validator = LengthValidator.new(validations[:length].merge(attributes: [:text]))
    validator.validate_each(self, :text, text)
  end
end
```


# Designing Indexes

> TBD - this system is currently in flux as we switch from server-side Cells to React


# Designing Wizards

> TBD - this system is currently in flux as we switch from server-side Cells to React


# Consuming Content

> TBD - a rudimentary RESTful API and RSS feed system already exist, but these will be replaced (or augmented) with a GraphQL API in 3-6 months.

## API Client Libraries

* [cortex-client-ruby](https://github.com/cortex-cms/cortex-client-ruby)


# Scheduling Content

> TBD - this system is built but is being refactored for greater reliability before we harden its interface


# Advanced

This guide typically goes beyond the role of a [superadministrator](/glossary#superadministrator) and is more engineering-focused. Whether you want to author plugins, extend search functionality, build reports, or contribute to the project, these guides will step you through the process.

* [Developing Plugins](https://github.com/cortex-cms/cortex-cms/tree/ec0acc5e822e7cd071403cac968f82e8f6df4a96/advanced/developing-plugins.md)
  * [Basic Architecture](/advanced/developing-plugins/basic-architecture)
  * [Service Layer](/advanced/developing-plugins/service-layer)
  * [Examples](/advanced/developing-plugins/examples)
  * [Extending Search](/advanced/developing-plugins/extending-search)
  * [WYSIWYG Widgets](/advanced/developing-plugins/wysiwyg-widgets)
* [Contributing](/advanced/contributing)


# Developing Plugins

This guide lays out how to build new plugins for Cortex CMS, which will allow you to extend the system with more `FieldTypes`, queries, WYSIWYG widgets, jobs, etc.

* [Basic Architecture](/advanced/developing-plugins/basic-architecture)
* [Service Layer](/advanced/developing-plugins/service-layer)
* [Extending Search](/advanced/developing-plugins/extending-search)
* [WYSIWYG Widgets](/advanced/developing-plugins/wysiwyg-widgets)
* [Examples](/advanced/developing-plugins/examples)


# Basic Architecture


# Service Layer


# Extending Search


# WYSIWYG Widgets


# Examples

Currently, there is only one reference Plugin implementation.

* [cortex-plugins-core](https://github.com/cortex-cms/cortex-plugins-core) - This provides the basic `FieldTypes` we'd expect most applications to need, such as `TextFieldType`, `BooleanFieldType`, `UserFieldType`, etc.


# Contributing

Anyone and everyone is encouraged to fork Cortex and submit pull requests, propose new features and create issues.

* Ideally, we'd first like to hear your concerns or suggestions in the form of an [issue](https://github.com/cortex-cms/cortex/issues). We can all avoid unnecessary re-work if a problem and its potential solution are first discussed before code is written.
* Fork on Github, then clone your repo:

```bash
$ git clone git@github.com:your-username/cortex.git
```

* Follow the [setup instructions](https://docs.cortexcms.org/basics/setup/manual-setup)
* Follow the [test suite instructions](https://docs.cortexcms.org/basics/setup/core-and-plugin-development#running-test-suite), and ensure all tests pass
* Make your changes. Make frequent commits, but keep commits and commit messages focused on individual, atomic feature changes or fixes. If you end up making many small commits during debug or development that belong to the same chunk of functionality, squash those commits before creating a pull request.
* Add tests for your change. Once again, ensure all tests pass.
* Push to a branch on your fork and [submit a pull request](https://github.com/cortex-cms/cortex/compare). Your PR must adhere to the following conventions:
  * For CareerBuilder team members, if the PR relates to a JIRA card, use the following naming convention:
    * `JIRA card #`: `PR Title`
    * Example: `COR-365: Unhandled Error on Media Upload`
  * For open source contributors, or if the PR does not relate to a JIRA card, use:
    * `PR Title`
    * Example: `Unhandled Error on Media Upload`
  * Names should use titleized capitalization. i.e.: `Login Form Redesign and Refactor`
  * Names should be dense, yet informative. For example, `Testing` is not an appropriate PR name, nor is `For update_url task, must use the body method to actually retrieve the stream from the S3 GetObjectOutput`. PR names are more high-level than commit messages.
  * PRs should be tagged appropriately (i.e. `enhancement`, `bug`, etc). Tags should be preferred over including things like 'bug' in the PR name.
  * PR Descriptions should be a clearly-separated, bulleted list summarizing what's contained in the commits, as well as any relevant notes or considerations for developers or ops. It should also detail any potential follow-up issues.
  * If working with a versioned library, open source users should not include version bumps or changelog updates in their PRs.

From here, it's up to the Cortex maintenance team (<employersitecontentproducts@cb.com>) to review your pull request. We operate in 2-week sprint lifecycles, but we'll try to get to your request or contribution sooner. We may suggest further improvements or alternatives, or the community at large may have input.

Some things that will increase the chances that your pull request will be accepted:

* Write [good tests](http://betterspecs.org)
* Write [good](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), [semantic](https://seesparkbox.com/foundry/semantic_commit_messages) commit messages
* Be consistent
* If applicable, suggest additional options or alternatives, follow-up issues or potential future improvements


# Troubleshooting

* For OS X / homebrew users: Run `which node` to ensure node is properly linked. The path shown should match homebrew's default installation path (run `which brew` to reveal this). If its not, then run `brew link node` and follow the instructions.


# Roadmap

To see where Cortex CMS is headed, please refer to <https://github.com/cbdr/cortex/projects/4>


# Branding Guide

Brand assets and style guide coming soon.

![](/files/-LJba9nxtjI-GTjnBgm6)


# Glossary

## CMS

At its core, a Content Management System allows for the creation & distribution of content across media devices. With more advanced tools, such as Cortex CMS, a CMS can also provide dynamic content recommendations to end-users, an API for [integration engineers](/glossary#integration-engineer) to work with when consuming content, reporting, localizations, advanced distribution rules and much more.

## Custom Content CMS

'Custom Content' implies a more flexible CMS architecture. Rather than hardcoding available 'content types' (such as a Blogpost, Webpage, Landing Page, Media, etc), Cortex CMS and others of its ilk allow [superadministrators](/glossary#superadministrator) to easily spin up new content types (and modify them) on a whim, as new business cases arise or change. This allows companies to meet the evolving needs of their users, while still providing rich, relevant & tracked experiences.

## Content Creator

The primary customer a CMS serves is the content creator, who authors the rich content experiences necessary for end-users to be delighted by the product, whether it be a blog, a website, or something more - a smartphone app, an advertising platform, or even a car's dashboard.

## Superadministrator

The glue putting together all the pieces across the CMS - this user creates or manages the various `ContentTypes`, plugins, tenants and users available to every other role.

## Integration Engineer

This developer creates and configures the connection between Cortex CMS and the desired frontend application. They can do this via the Cortex CMS API (recommended) or RSS feed by following the consuming [content instructions](/basics/consuming-content) & utilizing the [Cortex Client](/basics/consuming-content#api-client-libraries). A frontend application may be a simple blog, resource center, phone app, embeded device, appliance, and so much more!

## ContentType

A collection of `Fields` which represents a category of content that you want on your site

## Field

The association between a `ContentType` and a `FieldType`. When saving as a `FieldItem`, it informs the `ContentType` which `FieldType` to use, the validations to run on the content, and provides any relevant metadata to plugins, widgets, decorators, etc.

## FieldType

Describes the characteristics of some piece of data that can be used to compose a `ContentType`. For example, if a `ContentType` needs a string of text, you might utilize a `TextFieldType`, while a PDF might require a `FileFieldType`, and so on.

## ContentItem

An instance of a `ContentType`, a `ConteItem` is a grouping of `FieldItems` with [content creator](/glossary#content-creator)-provided data that is then persisted to the database and search engine.

## FieldItem

Each `FieldItem` represents a component of the `ContentItem` to which it belongs. So if the `ContentItem` is a blog post, there would be a `FieldItem` for the title, another for the body, another for an associated image, etc. Each of these `FieldItems` has a single corresponding `FieldType` that describes what kind of content it represents, such as a `TextFieldType`, `BooleanFieldType`, etc

## Decorator

## Multitenancy

## Content Library

## Role

## Permission

## WYSIWYG

## WYSIWYG Widget

## Service Layer

## Elasticsearch

## Drafts

## Docker

## Automated Testing


