---
title: "Tutorial: build a blog admin"
description: "Build a complete blog back office with resources, policies, relations, and reactivity."
image: "https://adonia.pages.dev/og.png"
version: "next"
---

> Documentation Index
> Fetch the complete documentation index at: https://adonia.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Tutorial: build a blog admin

A single path from `pnpm create adonisjs` to a blog back office that an editor
could actually use: a posts table with search, filters and sorting; a form with
an author picker, tags, a cover image and a slug that writes itself; and a
Bouncer policy that lets authors manage their own posts and nobody else's.

Every snippet on these pages is copied out of
[`examples/blog-admin`](https://github.com/rikoriswandha/adonia/tree/main/examples/blog-admin),
the app this repository runs its own end-to-end tests against, and each one
names the file it came from. When a page says "the panel does X", there is a
test in `examples/blog-admin/tests/functional/adonia_tutorial.spec.ts` asserting
X against a running server — the last chapter shows you how to run it.

## The chapters

| # | Page | What you end up with |
|---|---|---|
| 1 | [Install](/guide/tutorial/install) | `node ace add @adonia/core`, and a panel at `/admin` |
| 2 | [The Post resource](/guide/tutorial/resource) | A generated resource, reshaped into a real form |
| 3 | [Validation](/guide/tutorial/validation) | Server-compiled rules and the `inputErrorsBag` flow |
| 4 | [The index table](/guide/tutorial/table) | Columns, sorting, search and filters |
| 5 | [Authorization](/guide/tutorial/authorization) | A Bouncer policy enforced at every gate |
| 6 | [Relations and media](/guide/tutorial/relations) | `belongsTo` author, `belongsToMany` tags, a cover image |
| 7 | [Reactivity](/guide/tutorial/reactivity) | `live()`, slugify, and fields that appear when they should |
| 8 | [Theming and tests](/guide/tutorial/theming) | Panel chrome in your brand, and a green test suite |

Follow them in order — each chapter edits the file the previous one left
behind. Total time is about an hour, less if you skim.

## Before you start

You need an **AdonisJS v7 application with Lucid and Inertia + React**. If you
do not have one:

```sh
npm init adonisjs@latest blog-admin -- --kit=inertia --adapter=react --db=sqlite --auth-guard=session
cd blog-admin
```

Adonia needs all four of those:

| Requirement | Why |
|---|---|
| AdonisJS **v7** | The provider registers panel routes in `boot()`, which only v7 allows |
| `@adonisjs/lucid` | A resource is a Lucid model plus a schema |
| `@adonisjs/inertia` + React 19 | Panel pages are Inertia pages rendered by `@adonia/ui` |
| A session **guard** | Panels sit behind a guard; the packaged login page signs users in through it |

Optional peers you will meet later: `@adonisjs/bouncer` (chapter 5) and
`@adonisjs/drive` (chapter 6). Both degrade gracefully — without Bouncer no
policy is ever consulted, and a file field only needs Drive when somebody
uploads something.

The tutorial assumes a `Post` model with `title`, `subtitle`, `slug`, `body`,
`status`, `published_at`, `cover_image`, `author_id` and `category_id`, plus
`Category`, `Tag` and `User` models and a `post_tag` pivot. The blog-admin
example ships those migrations; if you are following along in your own app,
create them first with `node ace make:model -m`.

## What this tutorial is not

It is a path, not a reference. Where a chapter shows one way to do something,
the reference page for that subsystem shows the rest — [resources](/guide/resources),
[schema components](/schema-components), the
[fields reference](/reference/fields), [table columns](/table-columns),
[filters and search](/guide/filters-and-search), [validation](/guide/validation),
[authorization](/authorization), [theming](/theming) and
[testing](/guide/testing). The action, widget, lens, relation-manager,
domain, and locking APIs are covered by those reference guides. Continue with
[tenancy](/guide/tenancy) and [nested resources](/guide/nested-resources) for scoped routing.

Start with [Install](/guide/tutorial/install).

Source: https://adonia.pages.dev/guide/tutorial/index.mdx
