Skip to content

Choose an application interface

View as Markdown

One Sapporta application can be used through generated screens, HTTP routes, typed clients, CLI commands, and privileged SQL. This guide explains what each interface preserves and how to choose the smallest one that expresses the operation.

You will learn why ordinary record edits, domain transactions, and aggregate questions belong on different surfaces. The same decision applies when you add a browser workflow, an integration, an operator command, or an agent task.

I need to add <outcome> to this Sapporta app. Inspect its existing screens,
tables, endpoints, and reports, then recommend the highest-level interface that
fits. Explain what validation and row scope that choice preserves.

The interface follows the shape of the work. A generated surface already knows the table schema, editable fields, row labels, and request authority. An app-owned endpoint adds a business transition. A report adds a reusable read model. SQL operates below those application boundaries.

OperationUse firstTask-app example
Interactive record workGenerated record screenEdit a task priority
Programmatic CRUDTable API or rows commandCreate or update one task
Multi-table transitionApp-owned endpointComplete a task and insert history
Reusable aggregateReport route and screenShow progress by project
Repository changeCoding agent with the Sapporta skillAdd the completion workflow
Exceptional administrationPrivileged SQLInspect a value unavailable through an app surface

The browser, CLI, and typed client are different callers. They can still reach the same generated or app-owned route. Choosing a caller is separate from choosing the application operation.

Start the task app and discover its mounted surfaces before selecting one:

Terminal window
pnpm dev
pnpm exec sapporta tables show tasks
pnpm exec sapporta endpoints show "PUT /api/tables/tasks/{id}"
pnpm exec sapporta endpoints show "POST /api/tasks/{id}/complete"
pnpm exec sapporta endpoints show "GET /api/reports/project-progress"

Changing priority is a single-table update, so the generated route is the correct boundary:

Terminal window
pnpm exec sapporta rows update tasks 1 --values '{"priority":"high"}'
pnpm exec sapporta rows get tasks 1 --output json

Completing the same task is different. The operation changes the task and inserts an immutable event. The app-owned endpoint can apply both writes in one transaction and return a declared conflict if the task is already complete.

Terminal window
pnpm exec sapporta api post /api/tasks/1/complete --body '{}'
pnpm exec sapporta api get /api/reports/project-progress

Use sql query only when no generated route, domain endpoint, or report answers the question. SQL access is privileged and bypasses the generated row helpers, so it is an administrative interface rather than a substitute for application behavior.

The important result is not the command syntax. The task now runs through the surface that owns its rules: CRUD through generated tables, transitions through domain endpoints, and summaries through reports. From here, continue with the CLI guide for operation or custom API endpoints when the application needs a new business action.