Apr 04, 2025·8 min read

Draft vs published records: approval-friendly versioning patterns

Learn draft vs published records patterns for business apps: practical versioning models, approvals, safe rollouts, and common mistakes to avoid.

Draft vs published records: approval-friendly versioning patterns

Why draft and published records matter in business apps

Most business apps change often: prices get updated, policies get revised, forms get tweaked, and rules evolve as the team learns. The problem is that not every change should go live the moment someone hits Save. A draft stage creates a safe place to work, and a published stage protects what customers and coworkers rely on every day.

The core idea behind draft vs published records is simple: separate “what we are editing” from “what is currently in use.” That separation makes approvals possible. It also reduces stress, because editors can make a messy first pass without worrying that a half-finished update will break a checkout flow or confuse a sales team.

In most apps, you will version two kinds of things:

  • Content: text, images, FAQs, help articles, product descriptions, email templates
  • Configuration: prices, discount rules, form fields, required documents, routing rules, permissions

Editing live data is where teams get burned. One wrong number can publish the wrong price. One removed field can break a form submission. One rule change can send requests to the wrong queue or block legit users.

A realistic example: someone updates a “Plan” record to change pricing and limits, but forgets to update a related “Features” list. If that edit is live, customers see a mismatch immediately and support tickets start piling up.

You do not need a complicated system from day one. Start with a simple model: one draft, one published version, and a clear “Publish” action. When you outgrow it, you can add richer states (like “In review”) and features like scheduling and rollback.

If you build in a no-code platform like AppMaster, this separation is easier to enforce because the database model, business logic, and UI can all reflect the same approval rules.

Key terms: draft, published, and approval states

When people say “draft vs published records”, they usually mean one simple thing: the version someone is editing is not the same version your users should see.

Here are the states that show up most often in business apps:

  • Draft: A work-in-progress version. It can change many times and is usually visible only to the author and reviewers.
  • Published: The live version. This is what end users see in the UI, what business rules rely on, and what integrations may send out.
  • Archived: A retired version kept for history. It should not be edited or shown by default, but it can be used for audits or rollback.
  • Scheduled: Approved (or pending approval) but set to go live at a specific time, like next Monday at 9:00.
  • Rejected: Reviewed and declined. It is not live, and it should carry a reason so the author can fix it.

“Published” should be defined in your app, not assumed. In many systems, published means all three of these are true: it is visible in customer-facing screens, it is the version used when your app applies rules (like eligibility, pricing, or routing), and it is the version used when sending messages or syncing data to tools like email/SMS or payment systems.

A simple Active flag is often not enough. It cannot express “approved but scheduled,” “rejected but kept for reference,” or “currently live, but a new draft exists.” It also breaks down when you need exactly one live version, plus a clean way to roll back.

Finally, be clear about roles:

  • Editors (authors) can create and update drafts.
  • Approvers can publish, schedule, or reject.
  • Admins can override in emergencies and manage permissions.

In AppMaster, these states typically live as fields in your data model (Data Designer), while the approval steps and permissions are enforced in your Business Process logic.

What usually needs versioning: content and configuration

Anything that can change what users see or how your app behaves is a candidate for versioning. The goal is simple: make edits safely, get approval when needed, and only then let changes go live. That is the practical reason teams adopt draft vs published records.

Content that benefits from drafts

Content is the obvious starting point because edits are frequent and usually low risk. Typical examples include help center articles, onboarding messages, and customer-facing pages that marketing or support needs to update without engineering.

A few common content items that often need an approval step:

  • Help center or FAQ articles
  • Email and SMS templates (including transaction messages)
  • Pricing tables and plan descriptions
  • Onboarding flows and in-app tips
  • Legal text like terms snippets or consent copy

Even “simple” content can be sensitive when it affects billing, compliance, or customer promises. A typo in a password reset email can spike support tickets fast.

Configuration that benefits from drafts (and why it is riskier)

Configuration changes can be riskier than content because they can change outcomes, not just wording. A small tweak to a rule, permission, or form can block users, expose data, or break a workflow.

Common configuration that deserves versioning and approval:

  • Feature flags and rollout settings
  • Business rules (discount rules, eligibility, validations)
  • Form definitions (fields, required flags, logic)
  • Permission matrices and role access
  • Automation steps and routing rules

For example, changing a permissions matrix in an admin panel can accidentally grant access to customer data. If you are building in a platform like AppMaster, these “config” records often drive backend logic and UI behavior, so treating them as drafts first is a safer default.

Audit requirements also change the design. If you need to prove who approved what and when, you will want stored approvals, timestamps, and version history, not just “current draft” and “current published.”

Three common data models you can use

There is no single best way to handle draft vs published records. The right model depends on how strict your approvals are, how often changes happen, and how important audit and rollback are.

Pattern A: one record with a Status field (plus PublishedAt). You keep one row per item and add fields like Status (Draft, InReview, Published) and PublishedAt. When an editor changes the item, they are editing the same row, and the app decides what to show based on status and timestamps. This is the simplest to build, but it can get messy if you need to see exactly what was published last week.

Pattern B: separate draft and published tables (or collections). You store drafts in one place and published items in another. Publishing copies the approved draft into the published table. Reading is very fast and clear because the live app only queries the published table, but you now have two schemas to keep in sync.

Pattern C: immutable versions with a pointer to the current published version. Each edit creates a new version row (Version 1, 2, 3), and the main item points to the current published version. Publishing is just moving the pointer. This is great for history and rollback, but it adds one more join to most reads.

A quick way to choose:

  • Choose Pattern A when you need speed and simplicity, and rollback is rare.
  • Choose Pattern B when live reads must be simple and safe, and you can tolerate duplication.
  • Choose Pattern C when you need strong auditability, easy rollback, or multiple approvals.
  • If performance is critical, test read paths early (especially for Pattern C).

In tools like AppMaster, these models map cleanly to a PostgreSQL schema in the Data Designer, so you can start simple and evolve toward stronger versioning without rewriting the whole app.

How to model versions: IDs, history, and audit trail

Add approvals to your data
Build draft and published records with clear publish actions and role checks.
Try AppMaster

A good versioning model separates “what the thing is” from “which revision is live.” This is the core of draft vs published records: you want a stable identity for the record, plus a trail of changes that can be reviewed and approved.

Start by choosing a unique key that stays meaningful outside your database. For a help article it might be a slug, for a price rule it might be a code, and for synced data it might be an external ID. Keep that key stable across all versions so other parts of the app always know what record they are dealing with.

IDs: stable record ID + version ID

A common pattern is two tables (or two entities): one for the “record” (stable ID, unique key), and one for “record versions” (many rows per record). The record points to the current published version (and optionally the latest draft version). This makes it easy to show both: “what’s live” and “what’s being prepared.”

For each version, add fields that make review possible without guesswork:

  • version number (or an incrementing revision)
  • created by, created at
  • approved by, approved at
  • status (draft, in review, approved, rejected, published)
  • change summary (short text)

History and audit trail: approvals, comments, and evidence

Approvals should be first-class data, not just a status flip. Store who approved what and why, with optional comments. If you need multi-step approval, store an approval log linked to the version (one row per decision).

Localization and attachments need extra care. Avoid storing images or files “directly on the record” without versioning. Instead, attach them to the version so drafts can use new assets without overwriting what’s live. For translations, either store localized fields per version (one version contains all locales) or store per-locale version rows, but pick one and keep it consistent.

In AppMaster, you can model this cleanly in the Data Designer (PostgreSQL) and enforce the state changes in a Business Process so only approved versions can become published.

Step by step: a simple approval workflow that works

Most approval flows boil down to one idea: your app keeps two realities at once. Draft vs published records let people make changes safely, while customers and teammates keep seeing the last approved version.

Here’s a simple five-step workflow you can apply to pages, templates, pricing tables, feature flags, or any other “don’t break production” data.

  1. Create a draft. Start from scratch or clone the latest published version. Cloning is usually safer because it carries forward required fields and defaults.
  2. Edit and validate. Let editors update the draft, then run checks before it can move forward: required fields, length limits, formatting, and a preview that looks like the real screen.
  3. Submit for approval and lock. When the draft is submitted, freeze the parts that should not change (often the content itself) and allow only small fixes (like a typo note). Store who submitted it and when.
  4. Approve and publish. An approver either flips a “published pointer” to the new version or copies draft fields into the published record. Also record who approved it, the exact time, and any publish notes.
  5. Rollback. If something goes wrong, revert the published pointer to a prior version, or restore the previous published snapshot. Keep rollback fast and permissioned.

A small detail that saves a lot of pain: decide which fields are editable at each stage (Draft, In Review, Approved). For example, you might allow a preview-only “test URL” in Draft, but block it after submission.

If you build this in AppMaster, the states and locks can live in your data model, and the approval rules can sit in a visual Business Process so the same logic runs every time, no matter who clicks the button.

Publishing behavior: scheduling, conflicts, and rollback

Lock down who can publish
Separate editor, approver, and admin actions so publishing rights stay controlled.
Set Permissions

Publishing is where a nice approval flow can break down. The goal is simple: approved changes go live when you expect, without surprises for editors or users.

Publish now vs schedule

“Publish now” is easy, but scheduling needs clear rules. Store a publish time in a single standard (usually UTC), and always show editors the local time they expect. Add a small buffer (for example, a minute) between “approved” and “live” so background jobs have time to update caches and search indexes.

If you have multiple regions or teams, decide what “midnight” means. A scheduled change at 00:00 in New York is a different moment than 00:00 in London. One clear time zone in the UI prevents most mistakes.

Conflicts: stop people overwriting each other

Conflicts happen when two people edit the same draft or approve two different drafts for the same record. Common fixes are locking or optimistic checks.

  • Locking: when someone opens a draft, mark it “in editing” and show who has it.
  • Optimistic checks: store a version number, and block saving if the version changed since the editor loaded it.
  • Merge rules: allow merging only for safe fields (like text), and force manual choice for risky fields (like prices or permissions).

This is especially important with draft vs published records, where the published version is the source of truth for users.

What in-flight users experience

Even with perfect data, users might not see changes instantly. Pages can be cached, sessions can live for hours, and long-running processes (like checkout, onboarding, or bulk exports) may rely on the old configuration.

A practical approach is “read by published pointer”: users always read the version marked as current, and publishing only switches that pointer. If you need safe rollout, delay cache refresh until after the pointer changes, and keep sessions stable by not changing required fields mid-flow.

Rollback and keeping history without clutter

Rollback should be boring: switch the published pointer back to the previous version. Keep old versions for audit and comparison, but hide them from everyday screens. Show only the current draft, the current published version, and a “history” drawer with the last few versions and who approved them.

In AppMaster, this maps cleanly to separate “version” records plus a single “current published version” reference, so your UI stays simple while your data stays traceable.

Example scenario: updating a customer-facing portal safely

Design for audit and rollback
Set up stable record IDs, version IDs, and audit fields that hold up in real use.
Model Data

A common case is a customer portal that shows an onboarding checklist for new clients. The checklist includes steps like accepting terms, uploading documents, and setting up billing. Legal wants to approve any wording changes before they go live.

Your editor creates a new draft version of the checklist. The published version stays in place, so customers continue to see the current, approved text while the new draft is prepared. This is the core benefit of draft vs published records: you can work in progress without changing what real users rely on.

In the draft, the editor updates a step from "Upload ID" to "Upload government-issued photo ID" and adds a note about data retention. They also change the order of steps so "Accept terms" is first.

Legal reviews the draft and leaves comments on specific items. For example: "Replace 'photo ID' with 'valid photo identification'" and "Remove the promise that documents are deleted in 30 days; our policy is 90 days." During this review, someone also catches a small but important mistake: a rule in the draft marks the checklist as complete when only 2 of 3 documents are uploaded. That would have let customers proceed before compliance checks.

After the edits are applied, the draft is approved and published. Publishing swaps what the portal reads from: the new version becomes the published record, and the old published version becomes the previous version (kept for rollback).

What customers see stays predictable:

  • Before publish: the portal shows the old checklist and old completion rules.
  • After publish: the portal shows the new wording, updated ordering, and the fixed completion requirement.

If something still looks off after launch, you can quickly roll back by republishing the previous approved version, without rebuilding the whole portal.

Common mistakes and traps teams run into

The fastest way to break trust in an approval flow is to let people edit the live record “just this once.” It starts as a shortcut, then someone forgets to revert a test change, and customers see half-finished text or a broken rule. If you’re building draft vs published records, make it impossible to edit the published version except through a publish action.

Another common issue is copying records without a stable key. If you duplicate a record to create a draft but don’t keep a consistent “root” identifier (like ContentKey, PolicyKey, PriceListKey), duplicates spread everywhere. Search results show multiple “same” items, integrations can’t tell which is current, and reports become unreliable.

Approvals without an audit trail are also fragile. When something goes wrong, “who changed what” becomes guesswork. Even a simple log of submitted by, approved by, timestamps, and a short change note prevents long arguments and helps training.

Validation often gets skipped until after publishing. That’s risky for templates, business rules, or pricing logic where a small mistake can have big impact. Validate drafts before they can be submitted, and validate again right before publish (because related data may have changed).

Finally, teams forget the “satellite” data that must move with the main record: translations, attachments, permission rules, category links, and feature flags. The draft looks correct in one screen, but the live experience is incomplete.

A quick trap-avoidance checklist:

  • Block direct edits to published records (use roles and API rules)
  • Keep a stable root key across versions to prevent duplicates
  • Store an audit log for submit/approve/publish actions
  • Run validation on draft and again at publish time
  • Publish related objects together (translations, files, permissions)

If you build in a no-code platform like AppMaster, these safeguards map cleanly to status fields, version tables, and a Business Process that enforces the “only publish via workflow” rule.

Quick checklist before you ship an approval flow

Turn the pattern into an app
Turn your approval checklist into working screens and processes without custom coding every time.
Try the Builder

Before you ship a draft vs published records setup, do a quick pass for the things that break most often. These checks are less about UI polish and more about keeping data safe when real people start using the workflow.

Five checks that save you later

  • Make “what’s live right now?” a one-step answer. In practice, that means every consumer query can point to the current published version without sorting, guessing, or complex filters.
  • Give reviewers a true preview. A reviewer should be able to see the draft exactly as users would, but without it being reachable from the public app or customer portal.
  • Plan a rollback that is a switch, not a repair job. If a bad change slips through, you should be able to revert to the previous published version by changing a pointer or status, not by editing fields by hand.
  • Capture approval evidence. Record who approved, when they approved, and what they approved (version number or version ID). This matters for audits, but also for basic accountability.
  • Lock down publishing rights. Editing a draft is not the same as publishing it. Make sure only the right roles can publish, and that your API and UI both enforce it.

A quick practical test: ask a teammate to create a draft, request approval, and then try to publish it from an account that should not have permission. If it works even once, you have a gap.

If you’re building this in AppMaster, treat publishing as a separate business process step with role checks, and keep the “published version” selection in one place (one field, one rule). That keeps your web app, mobile apps, and backend in sync when a change goes live.

Next steps: implement the pattern in your app with minimal risk

Pick one place to start, not your entire system. A good first candidate is something that changes often but is easy to test, like email templates, help-center articles, or a pricing rules table. You will learn more from one well-done workflow than from trying to force draft vs published records across every table at once.

Write down who can do what before you build anything. Keep it simple and make the default safe. For most teams, three roles are enough: editor (creates drafts), reviewer (checks content and rules), and publisher (makes it live). If one person wears multiple hats, that is fine, but your app should still record which action happened and when.

Add lightweight checks early so you do not publish surprises. Basic validation (required fields, date ranges, broken references) prevents most bad releases. Preview is just as important: give reviewers a way to see what will change before they approve, especially for customer-facing pages.

Here is a small, low-risk rollout plan:

  • Implement the pattern for one entity and one screen.
  • Add role-based permissions for edit, approve, and publish.
  • Build a preview step and a short validation checklist.
  • Run a pilot with a small group of real users and real data.
  • Expand to the next entity only after you fix the first round of feedback.

If you want to move fast without custom coding every admin screen, a no-code platform can help. For example, AppMaster lets you model data, build an admin panel UI, and add approval logic with visual workflows, then generate production-ready apps when you are ready to ship.

Finally, plan your first release like a drill. Choose a narrow scope, set success criteria (time to approve, number of rollbacks, errors caught in review), and only then scale the pattern to more content and configuration.

Easy to start
Create something amazing

Experiment with AppMaster with free plan.
When you will be ready you can choose the proper subscription.

Get Started