with one click
backend-ui-design-codex
Internal Codex-flavored copy of the backend UI design guidance for `@open-mercato/ui`. Prefer the main `om-backend-ui-design` skill for normal backend page, CRUD, table, and form work.
Menu
Internal Codex-flavored copy of the backend UI design guidance for `@open-mercato/ui`. Prefer the main `om-backend-ui-design` skill for normal backend page, CRUD, table, and form work.
Approve (submit an approving review) and squash-merge a GitHub PR given only its number. Optionally file a follow-up issue at the same time. Use when the user says "approve and merge PR 123", "ship PR 123", "om-approve-merge 123", or gives a PR number with intent to merge.
Turn a review comment into a follow-up GitHub issue assigned to the PR author. Paste a link to a PR or a PR comment; the skill extracts the actionable ask from the comment, gathers PR context, and opens a tracking issue. Assignee is the comment's @-mention if present, otherwise the PR author. Use during code review when the user says "make a follow-up issue", "create an issue for this", "om-followup", or pastes a PR/comment link with that intent.
Browser-first GitHub issue fix workflow. Claims a GitHub issue, checks for existing solutions, creates an isolated worktree, reproduces the bug through the Browser against the ephemeral integration environment, records a failing Playwright integration test, fixes the bug, makes the test green, runs validation/review gates, pushes a branch, and opens a PR linked to the issue.
Scaffold a new module from scratch with all required files and conventions. Use when creating a new module, adding a new entity with CRUD, or bootstrapping module features (API routes, backend pages, DI, ACL, events, search). Triggers on "create module", "new module", "scaffold module", "add module", "bootstrap module", "generate module".
Implement a specification (or specific phases) using coordinated subagents with unit tests, integration tests, docs, and code-review compliance. Tracks progress by updating the spec. Triggers on "implement spec", "implement phases", "build from spec", "code the spec".
Review code changes for architecture, security, conventions, and quality compliance. Use when reviewing pull requests, code changes, or auditing code quality.
| name | backend-ui-design-codex |
| description | Internal Codex-flavored copy of the backend UI design guidance for `@open-mercato/ui`. Prefer the main `om-backend-ui-design` skill for normal backend page, CRUD, table, and form work. |
| metadata | {"short-description":"Backend UI design using @open-mercato/ui","author":"Open Mercato","version":"1.0.0","tags":["ui","backend","admin","crud","forms","tables"]} |
This skill guides creation of consistent, production-grade backend/backoffice interfaces using the established @open-mercato/ui component library. All implementations must leverage existing components to maintain visual and behavioral consistency across modules.
For complete component documentation, see references/ui-components.md. Pair this skill with packages/ui/AGENTS.md and packages/ui/src/backend/AGENTS.md for the current design-system and backend-host rules.
Backend UI prioritizes usability, consistency, and productivity over creative expression:
StatusBadge, Alert, FormField, SectionHeader, CollapsibleSection, EmptyState). No hardcoded status colors or arbitrary text sizes.ALWAYS import from @open-mercato/ui. Reference the component documentation at .ai/specs/SPEC-001-2026-01-21-ui-reusable-components.md.
import { Page, PageHeader, PageBody } from '@open-mercato/ui/backend/Page'
import { AppShell } from '@open-mercato/ui/backend/AppShell'
// Every backend page follows this structure
<Page>
<PageHeader>
{/* Title, actions, breadcrumbs */}
</PageHeader>
<PageBody>
{/* Main content */}
</PageBody>
</Page>
Use DataTable for ALL tabular data. Never implement custom tables.
import { DataTable } from '@open-mercato/ui/backend/DataTable'
import type { FilterDef } from '@open-mercato/ui/backend/FilterBar'
import { RowActions } from '@open-mercato/ui/backend/RowActions'
import { TruncatedCell } from '@open-mercato/ui/backend/TruncatedCell'
import { BooleanIcon, EnumBadge } from '@open-mercato/ui/backend/ValueIcons'
Column configuration patterns:
TruncatedCell with meta.maxWidth for long contentBooleanIconEnumBadge with severity presetsRowActions for context menusUse CrudForm for ALL forms. Never build forms from scratch.
import { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'
import { JsonBuilder } from '@open-mercato/ui/backend/JsonBuilder'
Form field types available:
text, textarea, number, email, passwordselect, multiselect, comboboxcheckbox, switchdate, datetimecustom (for JsonBuilder, TagsInput, etc.)import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@open-mercato/ui/primitives/dialog'
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
// Dialog forms MUST use embedded={true}
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="sm:max-w-2xl [&_.grid]:!grid-cols-1">
<DialogHeader>
<DialogTitle>Edit Item</DialogTitle>
</DialogHeader>
<CrudForm
fields={fields}
groups={groups}
initialValues={initialValues}
onSubmit={handleSubmit}
embedded={true}
submitLabel="Save"
/>
</DialogContent>
</Dialog>
import {
DetailFieldsSection,
LoadingMessage,
ErrorMessage,
TabEmptyState
} from '@open-mercato/ui/backend/detail'
import { NotesSection } from '@open-mercato/ui/backend/detail/NotesSection'
import { TagsSection } from '@open-mercato/ui/backend/detail/TagsSection'
import { CustomDataSection } from '@open-mercato/ui/backend/detail/CustomDataSection'
import { flash } from '@open-mercato/ui/backend/FlashMessages'
// Success
flash('Record saved successfully', 'success')
// Error
flash('Failed to save record', 'error')
// Warning/Info
flash('This action cannot be undone', 'warning')
flash('Processing in background', 'info')
NEVER use alert(), console.log(), or custom toast implementations.
import { Spinner } from '@open-mercato/ui/primitives/spinner'
import { DataLoader } from '@open-mercato/ui/primitives/DataLoader'
import { ErrorNotice } from '@open-mercato/ui/primitives/ErrorNotice'
import { EmptyState } from '@open-mercato/ui/backend/EmptyState'
import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
import { Button } from '@open-mercato/ui/primitives/button'
import { Input } from '@open-mercato/ui/primitives/input'
import { Label } from '@open-mercato/ui/primitives/label'
import { Badge } from '@open-mercato/ui/primitives/badge'
import { Alert, AlertTitle, AlertDescription } from '@open-mercato/ui/primitives/alert'
import { Separator } from '@open-mercato/ui/primitives/separator'
import { Switch } from '@open-mercato/ui/primitives/switch'
import { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'
Before writing any backend UI code, verify:
CrudForm for forms (not custom form implementations)DataTable for lists (not custom tables)flash() for notifications (not alert/toast)embedded={true}LoadingMessage or DataLoaderErrorMessage or ErrorNoticeEmptyStatemeta.truncate and meta.maxWidthBooleanIconEnumBadgeRowActions componentp-4 for cards, p-6 for page sectionsgap-4 or gap-6 for flex/grid layoutsspace-y-4 or space-y-6variant="destructive" on buttonsuseSeverityPreset() for consistent coloringPageHeadertext-lg font-semiboldimport { apiCall, apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
import { createCrud, updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
import { mapCrudServerErrorToFormErrors, createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'
// For CRUD operations
const handleCreate = async (values: FormValues) => {
const result = await createCrud<ResponseType>('module/resource', values)
if (result.ok) {
flash('Created successfully', 'success')
router.push(`/backend/module/${result.result.id}`)
}
return result
}
// For custom endpoints
const result = await apiCall<ResponseType>('/api/custom-endpoint', {
method: 'POST',
body: JSON.stringify(data)
})
When building CRUD interfaces that support custom fields:
import { useCustomFieldDefinitions } from '@open-mercato/ui/backend/utils/customFieldDefs'
import { buildCustomFieldFormFields } from '@open-mercato/ui/backend/utils/customFieldForms'
import { buildCustomFieldColumns } from '@open-mercato/ui/backend/utils/customFieldColumns'
import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'
Only create new components when:
@open-mercato/uiIf creating something new, it should eventually be added to the shared library, not kept in a single module.