# Documentation

Get started with Pokko in the official documentation, and learn more about all our features

Pokko is a fully-featured headless content management system with advanced functionality that allows you to build powerful content platforms backed by solid data structured.

## Getting started

It costs you nothing to get started with Pokko, create an account and start building out your data model.

Head over to <https://id.pokko.io/> to get started now.

## Accounts and projects

Once you have logged into Pokko you will need to create an account.

Accounts are where projects belong, they can have multiple projects.  You can also belong to multiple accounts and invite other people to your account, giving them access to the projects in your account.

Click the "Create account" button and give your account a name.

With the account created, click the "Create new project" button.  Select the region you want your project data to live in and give it a name.

You are now ready to start configuring your data model.


# Data modelling

Data models are what define the structure of your content.  They define what types of content you have - such as new articles, categories, information pages - and how they interact with each other - a news article might belong to a category.

Models consist of fields.  Fields are the properties or attributes that your model possess.  A **news article** might have **title**, **date** and **content** fields.

## Creating a model

In a new project that has no models, you will be taken directly to the model creation screen.

Otherwise, you can get to the model section by using the top navigation bar: Content > Models

![](/files/-MbccBUCZpvo0DgieqAH)

Give your model a name, the alias will automatically populate.  If you want to change the alias you can.

|                 | Description                                                                                                                                                                                                                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**        | This is a friendly name for your model.  It can be changed at any time.                                                                                                                                                                                                                         |
| **Alias**       | This is how you refer to your model when querying content.  You can change this at any time, however, it will affect any integrations you have built.                                                                                                                                           |
| **Usage**       | This identifies the purpose of your model.  Entries are top-level content such as web pages and categories.  Modules are content that live inside other content - such as entries or nested within another module.  See [modular content](/advanced-features/modular-content) for more details. |
| **Inheritance** | This allows you to specify models to inherit properties from.  See [data model inheritance](/advanced-features/data-model-inheritance) for a deeper look into this feature.                                                                                                                     |

Click the "Save changes" button to create your model.

## Adding fields

With your model created, you can now start adding fields.  Click the "New field" button.

![](/files/-Mbcf7ID9b-Z7ROg6qnf)

You only need to specify the name, alias and type to create a field.  The additional configuration will be discussed in later topics.

|                            | Description                                                                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**                   | This is a friendly name for your field.  It can be changed at any time.                                                                               |
| **Alias**                  | This is how you refer to your model when querying content.  You can change this at any time, however, it will affect any integrations you have built. |
| **Type**                   | This defines what type of content your field will hold.  See below for more information on the various field types.                                   |
| **Required**               | Indicates that this is a required field.                                                                                                              |
| **Single/Multiple values** | Fields can be a single value or have multiple values.                                                                                                 |
| **Automatic source**       | Field values can be derived from other sources.  This is discussed in the [automatic fields](/advanced-features/automatic-fields) section.            |

### Field types

| Type                | GraphQL    | Description                                        |
| ------------------- | ---------- | -------------------------------------------------- |
| **Plain text**      | `String`   | Simple plain text field                            |
| **Rich text**       | `JSON`     | Structure text field that allows embedding modules |
| **Date**            | `String`   | Simple date field.  ISO-8601 formatted date        |
| **Numeric**         | `Number`   | Integer or decimal number values                   |
| **Boolean**         | `Boolean`  | Yes/no, true/false                                 |
| **Linked content**  | `PokEntry` | References another entry                           |
| **Modular content** | `PokValue` | Allows for embedding content within the entry      |
| **Media**           | `PokMedia` | Links to an item in the media library              |

### Validation

There are three sources of field validation.  Validation is performed on Publish, not Save.

1. Required
2. Validation
3. Min/max on multiple value fields

## Advanced topics

{% content-ref url="/pages/-MbF-2qDflWez\_xI\_RPh" %}
[Data model inheritance](/advanced-features/data-model-inheritance)
{% endcontent-ref %}

{% content-ref url="/pages/-MbF1A1urwrFlgV6E3mT" %}
[Automatic fields](/advanced-features/automatic-fields)
{% endcontent-ref %}

{% content-ref url="/pages/-MbF1cJBZO3VbcT8HrgL" %}
[Modular content](/advanced-features/modular-content)
{% endcontent-ref %}


# Media library

Pokko provides a smart media library backed by a global CDN ensuring your clients have immediate access to your media assets.

The media library can store any type of file from plain text to images and videos.

## Image processing

Images uploaded to the Pokko media library can be processed by the CDN, resizing and cropping as needed.

The GraphQL query for a media item provides the options to perform these transformations.

```
query BlogPostById($id: String!) {
  entries {
    blogPost(id: $id) {
      image {
        url(process: { height: ..., width: ..., fit: CONTAIN, position: CENTRE })
      }
    }
  }
}

```

The `process` parameter is optional, but if specified both the `height` and `width` arguments are required, the `fit` and `position` remain optional.


# Querying content

How to extract published content out of Pokko

## API Keys

To query content you will need to set up an API key.  This can be done from the project settings screen.

![Click the cog here to access the project settings](/files/-MdzUQkFKHN43T6egy4i)

Click the "New token" button under the "API Tokens" section.

![](/files/-MdzUb4GcMNF1wyxV-Px)

Click the "GraphQL Playground" button to open a website where you can start querying content.

In this UI you will need to specify the token that was generated.

Click "HTTP Headers" down the bottom and enter the following

```
{
  "X-Token": "<< API TOKEN >>"
}
```

With this in place, you can start querying your content.

## Queries

There are two ways of querying your content.

1. Querying individual pieces of content - `entry()`
2. Querying a list of content of a specific type  - `entries { }`

The GraphQL root query has two queries to access your content - `entry` and `entries`

More information about what queries are available can be found in the GraphQL Playground.

### Individual entries

With `entry` you can query individual entries by ID or by Path.

```graphql
query GetBlogPost {
  entry(id: "...") {
    ... on IBlogPost {
      id
      # additional fields here
    }
  }
}
```

### Multiple entries

With `entries` you can query multiple entries of a type.

```graphql
query ListBlogPosts {
  entries {
    allBlogPost(skip: 0, take: 10, filter: { ... }) {
      nodes {
        id
        # additional fields here
      }
      totalCount
    }
  }
}
```

## Caching

A layer of caching is in place for the content querying endpoints.  Content will be cached indefinitely until a change to your content is made.  When a Publish occurs on an entry the cache will be cleared.

The more complex a GraphQL query is, the longer the initial request will take.  Subsequent cached queries will be drastically faster.

## GraphQL endpoint

<mark style="color:green;">`POST`</mark> `https://<region>.pokko.io/:project/:environment/graphql`

This endpoint allows you to get free cakes.

#### Path Parameters

| Name        | Type   | Description |
| ----------- | ------ | ----------- |
| environment | string |             |
| project     | string |             |

#### Headers

| Name    | Type   | Description |
| ------- | ------ | ----------- |
| X-Token | string |             |

{% tabs %}
{% tab title="200 " %}

```
```

{% endtab %}
{% endtabs %}


# Webhooks

Talk about - webhooks and callbacks


# Data model inheritance

Compose complex data structured through inheritance

Data model inheritance - often simplified to just "inheritance" - is a feature in Pokko that allows you to compose complex data models by basing one model off another, inheriting the properties from that other model.

{% hint style="info" %}
**Example: Website**

You may be using Pokko to manage content for a website.  This website consists of various kinds of pages - blog posts, portfolio items, media libraries, etc.

Being part of a website they all share some common properties - i.e., page titles, URLs, meta descriptions

Instead of creating a data model in Pokko for each page and adding these properties to each model, you could make use of inheritance and create a base model including all these common properties that your page types would inherit from.

![](/files/-MfZtE3SGRbse8pvptGs)
{% endhint %}

## Model configuration

Data model inheritance is best implemented when creating your models rather than retrospectively.  You can move fields around once they have been created, but if any content has been created against the models you are reconfiguring it may be lost.

Following the above example, you would start by creating the **Page** model.

| Field            | Configuration                                                                 |
| ---------------- | ----------------------------------------------------------------------------- |
| Title            | Single line text, automatic source "Entry name"                               |
| URL slug         | Single line text, automatic source "Entry name" with "slugify" transformation |
| Meta description | Single line text                                                              |

When creating the **Blog post** and **Portfolio item** models, under the Inheritance section, click "Add" and choose "Page" from the dropdown.

![](/files/-MfZtrysz6_A5IZlny-E)

With that configured, you will see in the **Blog post** model the fields that have been inherited from **Page**.

![](/files/-MfZuDjSem5NmXPR0bFJ)


# Content hierarchy

Pokko allows you to create data models that define the shape of your content items that lets both your users and integrated systems what to expect when working with your content.

This provides you with a "flat" document store that suits a lot of purposes, but there are some instances where there needs to be another level of content organisation such as a hierarchy.

Pokko has the concept of Content Structure that allows you to define this hierarchy for your content.  This allows you to address content based on a known structure, rather than querying chunks of data hoping to find what you get or hard-coding known IDs of content.

The easy example of where this feature would be most useful is a website, where you can define the structure of the content for your website.

![The content structure configuration for the Pokko website](/files/-MhQVymS3I_mKcAJmJBp)


# Base values

Base values allow you to define a set of fallback values for content when fields are left empty.

If you use data model inheritance the base values are also inherited.

i.e., if you have a `Blog Post` model that inherits from `Base Page` then any base values on the `Base Page` will propagate through to your `Blog Post` entries.


# Automatic fields

Talk about - automatic fields and the options available


# Content workflow

Talk about - publish targets


# Modular content

Talk about - how to configure modular content fields and where they may be useful


# Isolated environments

Talk about - what environments are and why you would want to use them


# NextJS

Getting started guide for using Pokko with NextJS websites

Pokko provides a GraphQL endpoint for querying content that integrates with any platform that can consume data coming from such an endpoint.

Using the [content hierarchy](/advanced-features/content-hierarchy) feature of Pokko you can easily map content in Pokko to web pages on your website.

The website for Pokko - [pokko.io](https://www.pokko.io/) - is a NextJS website with Typescript connected to Pokko.  You can view the source code for [the site here](https://github.com/pokkocms/website).

It's worth noting that the guide below isn't necessarily tied to NextJS, but could apply to any Javascript-based application.

## Getting started

The simplest way to connect NextJS to Pokko is to add a thin API layer using the Apollo GraphQL client.

Start by adding the required dependencies.

```
yarn add @apollo/client graphql

# or, if you are using npm

npm install --save @apollo/client graphql
```

Then create a file somewhere in your project; we tend to use `lib/pokko.ts` in our projects.

```
import {
  ApolloClient,
  ApolloClientOptions,
  InMemoryCache,
  NormalizedCacheObject,
} from "@apollo/client";

const config = {
  environment: process.env.POK_ENVIRONMENT!,
  project: process.env.POK_PROJECT!,
  token: process.env.POK_TOKEN!,
};

const options = (
  token: string
): ApolloClientOptions<NormalizedCacheObject> => ({
  cache: new InMemoryCache(),

  headers: {
    "X-Token": token,
  },

  uri: `https://au-syd1.pokko.io/${config.project}/${config.environment}/graphql`,
});

export const client = new ApolloClient(options(config.token));
```

This expects the environment variables for `POK_ENVIRONMENT` , `POK_PROJECT` and `POK_TOKEN`.  These can go into your `.env` file.

aWith that, you can query content using the `client` export from this file, it will provide you with a raw GraphQL interface to query content.

## Code generation

We like to use a library called [GraphQL Codegen](https://www.graphql-code-generator.com/) that allows us to write GraphQL queries and store them in `.graphql` files that are then validated against the Pokko API and then output into Typescript files for easier consumption.

It only takes a few moments to configure but will save you tonnes of time in the long run.

Start by installing the dependencies.

```
yarn add --dev @graphql-codegen/cli @graphql-codegen/fragment-matcher @graphql-codegen/typescript @graphql-codegen/typescript-apollo-client-helpers @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo

# or, with npm

npm install --save-dev @graphql-codegen/cli @graphql-codegen/fragment-matcher @graphql-codegen/typescript @graphql-codegen/typescript-apollo-client-helpers @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo
```

Then create a `codegen.yml` file alongside your `package.json` with the contents below.  You can put these files wherever you like, this is just how we set things up.

```
schema:
  - https://au-syd1.pokko.io/<< PROJECT ID >>/<< ENVIRONMENT ID >>/graphql:
      headers:
        X-Token: ${POK_TOKEN}
documents:
  - pokko/queries/*.graphql
generates:
  ./pokko/queries.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-react-apollo
      - fragment-matcher
```

The URL on line 2 can be found by following [the steps here](/basic-features/getting-started#api-keys), the URL for the "GraphQL Playground" is what will go here.

This will look for `.graphql` files in the `pokko/queries` folder and output the generated Typescript to `pokko/queries.ts`

This also looks for your API key in your environment variables, you can create a `.env` file with `POK_TOKEN=<< API TOKEN >>` alongside the `codegen.yml` file.

With this in place, you can run `yarn run graphql-codegen` to generate the Typescript file.

There is one extra piece needed if you use data model inheritance, that is to update your `lib/pokko.ts` file to the following.

```
import {
  ApolloClient,
  ApolloClientOptions,
  InMemoryCache,
  NormalizedCacheObject,
} from "@apollo/client";
import intro from "../pokko/queries"; // <-- add this

const config = {
  environment: process.env.POK_ENVIRONMENT!,
  project: process.env.POK_PROJECT!,
  token: process.env.POK_TOKEN!,
};

const options = (
  token: string
): ApolloClientOptions<NormalizedCacheObject> => ({
  cache: new InMemoryCache({
    possibleTypes: intro.possibleTypes,  // <-- and this
  }),

  headers: {
    "X-Token": token,
  },

  uri: `https://au-syd1.pokko.io/${config.project}/${config.environment}/graphql`,
});

export const client = new ApolloClient(options(config.token));
```


