Skip to content

Applications

Valentijn Verhallen edited this page Aug 4, 2025 · 8 revisions

Creating your first application

We'll keep this example to a minimum, but you can easily expand and make it your own.

Imagine you want to keep track of the books you've read.
All books have authors, but we don't want to write this down for every entry. This can be a second app. Let's also keep track of how many books by this author we read.

We're going to make two apps: authors & books.
We start off by defining the apps in the system configuration. This is the starting point where Unchained reads the available applications. It's also where we define our basic routing.

The bare-minimum configuration looks like this:

## /user/config/applications.yaml
applications:
  authors:
    public: false  # let's keep this to ourselves    
  books: ~
# /user/config/applications/authors.yaml
application:
  fields:
    name:
      type: text
      required: true
    surname:
      type: text
      required: true
    books:
      type: number
      source: count_books

  meta:
    exposes: [ name, surname ]

  sources:
    count_books:
      application: books
      function: count
# /user/config/applications/books.yaml
application:
  fields:
    author:
      source: author
      required: true
    title:
      type: text
      required: true
    rating:
      type: rating
      options: [ 1,2,3,4,5 ]
    comment:
      type: textbox
      public: false

  meta:
    exposes: [ author, title ]

  sources:
    author:
      application: authors

Feel free to add more fields to your liking.
For more in-depth info on the definitions please read Configuration.

Sources

Sources describe other applications (cross-references). We define sources by an alias and tell the system which application to grab the information from. Fields with a source reference their value from the described source. Source values are referenced internally. Every application exposes certain fields (see meta), which are displayed by default.
Unless you want something special, you don't need to do anything other than write the link.

It may sound more complicated that it really is:

# /user/config/applications/books.yaml
sources:
  the_author:
    application: authors

fields:
  # Because this fields refers to a source, it's automatically configured as a choice and will be visible as such in the backend.
  author:
    source: the_author

Because "authors" exposes "name" and "surname", you'll be presented with these values.

Let's expand this example a bit further, by adding a photo field to authors.

# /user/config/applications/authors.yaml
application:
  fields:
    photo:
      type: image
      required: false

    name:
      type: text
      required: true

    # etc... (see first example)

In our books we can now reference the author by their photo:

# /user/config/applications/books.yaml
application:
  fields:
    author:
      source: author.photo
      required: true

    # etc... (see first example)

Unchained has a nifty feature, allowing an automatic combination of both the image and exposed fields. This way we can still edit our records with the author's name, but display the photo in the dashboard. The photo will get a small name overlay.

How it works

It's very simple really: through foreign keys. Every application exposes an ID field. This ID is used as the reference for the requesting application. The referred ID is stored within the current app.

Reverse joins

You sometimes want something more complex. Imagine having two apps, one for internal reference and one which is published, referencing each other. You likely want to show the fields of the foreign app, but the primary key belongs to the current. You want an invert join:

# /user/config/applications/riding-gear.yaml
application:
  category: riding
  fields:
    horse:
      source: horses.photo
    saddle:
      type: image
    spurs:
      type: image

  sources:
    horses:
      application: horses
# /user/config/applications/horses.yaml
application:
  category: riding
  fields:
    photo:
      type: image
      required: false
    name:
      type: text
    saddle:
      source: gear.saddle
    spurs:
      source: gear.spurs

  meta:
    # primary exposure is name. So when showing the photo, the name is included as well
    exposes: name

  sources:
    gear:
      application: riding-gear
      invert_join: true  # linking <this>.ID to gear.<horses>.ID
      fields: [ saddle, spurs ] # limit included fields, not required

For more (advanced) configuration options, please review Configuration

Clone this wiki locally