Dollie Editor SDK guide
Laravel Post Backend
Adopt the optional post model, lifecycle services and policy-protected endpoints.
The Dollie\Editor\Posts module in dollie/editor-laravel supplies reusable backend
operations. It does not require Inertia or your website's controllers. Follow
Laravel installation first, then register the same
post catalogue in React and in a generated Laravel manifest.
Choose storage
For a new installation, publish the optional migration:
php artisan vendor:publish --tag=dollie-editor-posts-migrations
php artisan migrate
It creates editor_posts for the default Dollie\Editor\Posts\Post model. Installing the
package alone does not run this migration.
For an existing table with the same columns, retain its migrations and extend the model:
namespace App\Models;
use Dollie\Editor\Posts\Post;
class BlogPost extends Post
{
protected $table = 'blog_posts';
}
Compare your schema with the package migration before adopting it. Required storage includes title/slug, excerpt, cover_image, featured_image JSON, definition JSON, revision, publication JSON, published_at, publication_updated_at, category, tags JSON, SEO JSON and timestamps. The default schema uses globally unique slugs. Reusing a compatible table preserves IDs, URLs, revisions and publication snapshots without copying content.
Configure the module
Add a manifest for the article surface and configure your actual section IDs in
config/dollie-editor.php:
'manifests' => [
'article' => resource_path('editor/manifests/article.json'),
// Retain your other manifests here.
],
'posts' => [
'model' => App\Models\BlogPost::class,
'repository' => Dollie\Editor\Posts\EloquentPostRepository::class,
'content_policy' => Dollie\Editor\Posts\DefaultPostContentPolicy::class,
'surface' => 'article',
'header_component' => 'article-header',
'initial_definition' => ['sections' => [
['component' => 'article-prose', 'props' => ['content' => '']],
]],
'archive_per_page' => 12,
'routes' => [
'enabled' => true,
'prefix' => 'editor/posts',
'middleware' => ['web', 'auth'],
],
],
The default content policy accepts catalog-valid body sections except an additional header,
and requires nonempty content to publish. Implement Posts\Contracts\PostContentPolicy
to enforce extra requirements for your images, illustrations, links or imported tags.
For tenant applications, supply model global scopes or a PostRepository implementation
that scopes every query and assigns the tenant on creation. The default repository preserves
global scopes for reads and atomic updates. It does not infer a tenant or user policy.
Enable JSON routes or keep host controllers
The optional routes are disabled by default. Register a Laravel policy for your configured model before enabling them; without one, requests are denied.
| Method and path (under your prefix) | Policy ability | Payload |
|---|---|---|
GET / |
viewAny |
Query filters |
POST / |
create |
None; uses initial definition |
GET /{post} |
view |
None |
PUT /{post} |
update |
revision, definition, optional pageData |
PATCH /{post}/details |
update |
revision, title, slug, optional excerpt/category/tags |
GET /{post}/preview |
view |
None |
POST /{post}/publish |
publish |
revision |
POST /{post}/unpublish |
publish |
revision |
Create returns HTTP 201 with { document }; load returns { document }. Saves return
{ document, revisions: [] }. Revision conflicts return HTTP 409 with
{ "error": "revision_conflict" }; validation failures use Laravel's JSON validation response.
Send Accept: application/json and your host's authentication/CSRF credentials.
PATCH always saves a draft, even if the caller supplies publish: true. It preserves the
stored body, images and SEO. A published slug cannot change until the post is unpublished.
Preview returns private JSON with no-store and noindex headers; your host renders the page.
Mount these routes before a host catch-all.
These post endpoints have their own request/response shape. Do not point createHttpTransport
at them unchanged. Use a small host HTTP client, or connect PostPageStore through the
existing editor transport and an authorized PageStoreResolver.
Services for Inertia and other hosts
Keep posts.routes.enabled false if your controllers already handle URLs and permissions.
Authorize first, then resolve services after ActivateEditorSurface::class.':article':
// Inside an authorized route action, after the article surface middleware:
$posts = app(\Dollie\Editor\Posts\PostManager::class);
$canvas = app(\Dollie\Editor\Posts\PostCanvas::class);
$post = $posts->create();
$document = $canvas->document($post); // Pass to your React editor.
// Later, with an authorized post and validated request envelope:
$saved = $canvas->save($post, $request->all());
PostManager exposes create, save, saveDetails, publish, and unpublish.
PostCanvas maps between the stored post and editing document. Service calls are trusted
application operations; they do not run Laravel policies themselves. Map
RevisionConflictException to your form's conflict state or HTTP 409 and keep unsaved writing.
revision is a concurrency token. This module has no historical revision archive.
PostPageStore::listRevisions() returns an empty list, and restore requests are rejected.
Its generic save label and trail arguments are not persisted. Add host revision storage
if your product needs durable history beyond the current draft and publication snapshot.