Mini App Validation
Mini-App Builder Lifecycle
Overview
The Mini-App Builder lifecycle is the backend foundation for creating, validating, and publishing block-based mini apps. It turns a mini app from a simple database record into a versioned document made of ordered blocks, with explicit validation rules and a controlled publish gate.
This component supports two creation paths:
- template-driven mini apps, where the system seeds recommended blocks for a selected mini-app type
- a la carte mini apps, where users compose a campaign from allowed blocks that fit their use case
The system is designed so templates accelerate creation, but blocks remain the core composition unit.
Core Concepts
Mini App
The stable parent asset owned by a SaaS user. It tracks high-level identity, type, status, slug, and pointers to the current draft and published revisions.
Revision
A saved version of a mini app document. Revisions allow drafts and published experiences to be tracked separately. The current implementation saves each draft update as a new revision and marks a valid draft revision as published during publish.
Block
An ordered component inside a revision. Examples include hero, offer description, countdown timer, product grid, primary CTA, lead capture, share QR, poll, and token reward.
Block Registry
The shared backend contract for all supported block types. It defines:
- block key
- title
- icon
- description
- category
- default data
- allowed mini-app types
- recommended mini-app types
- publish requirements
Publish Validation
A validation gate that checks whether a saved draft is safe to publish. Draft save is intentionally more flexible; publish validation is stricter.
Data Model
The builder lifecycle adds these tables:
mini_app_revisionsmini_app_blocks
It also extends mini_apps with:
slugcurrent_draft_revision_idcurrent_published_revision_idarchived_at
At a high level:
mini_apps
├── current_draft_revision_id
├── current_published_revision_id
└── mini_app_revisions
└── mini_app_blocksAPI Surface
Builder Registry
GET /mapp/miniapp/builder-registryReturns block definitions, mini-app type definitions, default block sets, and document schema version.
Used by the builder UI to understand which blocks exist and which blocks are allowed or recommended for each mini-app type.
Save Draft
POST /mapp/miniapp/draftsCreates or updates a mini-app draft. Each save writes a new draft revision and its ordered block instances.
The request includes:
- optional mini app id
- title
- mini app type
- optional slug
- optional source template key
- theme config
- token rules
- ordered blocks
Draft save validates:
- title is present
- mini-app type is present
- block type exists in the registry
- block type is allowed for the selected mini-app type
Load Draft
GET /mapp/miniapp/:id/draftLoads the current draft revision and ordered blocks for the authenticated owner.
Validate Publish
POST /mapp/miniapp/:id/validate-publishRuns publish-time validation without mutating state.
Returns:
publishableerror_countwarning_count- validation issues
Validation errors block publishing. Warnings are visible but non-blocking.
Publish
POST /mapp/miniapp/:id/publishRuns publish validation and publishes the current draft only if validation passes.
If validation fails:
- returns
422 - returns validation issues
- does not mutate publish state
If validation passes:
- marks the current draft revision as
published - writes
published_at - stores validation summary
- updates parent mini app to
active - sets
current_published_revision_id
Validation Model
Validation rules are data-shaped metadata interpreted by Go code.
For example, the block registry defines that countdown_timer requires:
BlockPublishRequirement{
Rule: "required_field_if_present",
Description: "Countdown timer blocks must include an end time.",
Fields: []string{"endTime"},
}And it also defines a co-requisite rule:
BlockPublishRequirement{
Rule: "requires_block",
Description: "Countdown timers require an end date/time block so the end state is explicit.",
Blocks: []string{"end_datetime"},
}The validator currently supports these rule families:
required_field_if_presentone_of_required_if_presentrequires_blockrequires_one_of_blocksforbids_blocks
This supports flexible business logic such as:
- if block A is used, block B is required
- if block A is used, at least one of blocks B or C is required
- if block A is used, block D is forbidden
- if a block is present, specific fields must be populated
Example Validation Result
{
"publishable": false,
"error_count": 1,
"warning_count": 0,
"issues": [
{
"severity": "error",
"code": "missing_required_block",
"message": "Countdown timers require an end date/time block so the end state is explicit.",
"block_type": "countdown_timer",
"rule": "requires_block",
"blocks": ["end_datetime"]
}
]
}Current Behavior
The current implementation provides:
- authenticated draft save/load
- versioned draft revisions
- ordered block persistence
- block-definition registry
- allowed/recommended block policies
- publish-time validation
- publish endpoint gated by validation
- unit tests for validation co-requisites
Current Boundary
This component does not yet render published mini apps publicly. Publishing currently establishes database state only.
Known next steps:
- runtime rendering endpoint for
current_published_revision_id - immutable post-publish editing behavior
- template seeding endpoint
- frontend integration with builder APIs
- token reward validation
- render manifest generation
Design Principle
Templates should guide users, not trap them.
The architecture supports template-based creation and a la carte composition by treating blocks as the source of truth, while using registry-backed policies to keep published mini apps valid and safe.