Admin Golden Path List Create Edit Example
This page shows the governed shape of a simple addon Admin list/create/edit/action workflow.
Related pages: Admin UI/Admin Addon View Developer Contract, Admin UI/Admin Form Actions Permissions and CSRF Rules, Reference Samples/Admin Runtime Sample.
Purpose
This document describes the expected shape of a simple addon Admin workflow that includes:
- list
- create
- edit
- action route
- CSRF
- permissions
- notices
- return-state handling
It is written as a reference pattern for cleanup and future Wiki examples.
It is not a claim that every helper named in planning documents already exists.
Example Addon Surface
Example addon: Notes
Admin routes:
- GET /admin/addons/notes
- GET /admin/addons/notes/new
- POST /admin/addons/notes/new
- GET /admin/addons/notes/edit
- POST /admin/addons/notes/edit
- POST /admin/addons/notes/action
Permissions:
- notes.view
- notes.create
- notes.update
- notes.delete
- notes.archive
List Route
The list route reads:
- q
- page
- per_page
- sort
- dir
- state when a real state filter exists
The list route checks notes.view.
It renders:
- breadcrumb
- task panel eyebrow
- task panel title
- notice area
- toolbar
- table or empty state
- bottom pagination
- optional Advanced section only when needed
Toolbar order:
- New
- Edit
- Delete
- Archive
- spacer
- row-count selector
- search input
- state filter only when the filter is real
Edit is disabled until exactly one row is selected.
Delete and Archive are disabled until one or more rows are selected.
List Table
Column order:
- checkbox
- title
- author or owner when useful
- State
- updated date
The title is human-readable and clickable.
The row does not show UUID, slug, table id, source key, or filesystem path by default.
State renders as:
[square marker] Activeor:
[square marker] ArchivedRaw lowercase database state values are converted before display.
Create Route
The create GET route checks notes.create.
It renders one form.
It does not appear inside the list screen.
The create POST route:
- validates CSRF
- checks notes.create
- validates fields
- inserts the note
- writes a success notice
- redirects after POST
On validation error, the route returns or redirects using the shared Admin error pattern.
The form action row order is:
- Save
- Cancel
Cancel returns to the owning list and preserves list state.
Edit Route
The edit GET route checks notes.update.
It loads one record.
It renders one form.
The edit POST route:
- validates CSRF
- checks notes.update
- verifies the record exists
- validates fields
- updates the note
- writes a success notice
- redirects after POST
Delete is normally not placed on the edit form.
If the domain requires a destructive edit-form action, the reason must be documented.
Action Route
The action route handles selected-row mutations.
Inputs:
- CSRF token
- action name
- selected row identifiers
- return/list state
The route:
- validates CSRF
- rejects empty selection
- checks the permission for the requested action
- validates that the action is supported
- performs the mutation
- writes a notice
- redirects to the list with state preserved
Example action mapping:
- delete requires notes.delete
- archive requires notes.archive
Do not trust the client to enforce which actions are allowed.
Return-State Example
When the user is on:
/admin/addons/notes?q=test&page=2&per_page=10&sort=updated_at&dir=desc&state=activeand opens edit, the edit route should preserve the return state.
Cancel or post-success return should take the user back to the same list context when that is the expected workflow.
Current Drift and Intended Rule
The final intended implementation should use shared Admin helpers for toolbar, pagination, state markers, notices, forms, and return-state URLs.
If the shared helpers are not available yet, implementers must still produce the same structure and behavior manually.
This example should become a live Wiki page only after it has been checked against actual code helper names or clearly marked as a governed pattern rather than a helper API reference.
Final Checklist
This example is correct only when:
- list/create/edit are separate
- route permissions are checked
- POST validates CSRF
- POST redirects after success
- list state is preserved
- toolbar order matches the contract
- query keys match the contract
- table columns match the contract
- state marker and label match the contract
- developer identifiers are not shown by default
- notices use the shared placement
- old local UI code is not left behind
Updated: 2026-05-03 17:36:20