# How the Luban H5 Publish Workflow and view_mode Preview System Works

> Understand the Luban H5 publish workflow and view_mode preview system. Learn how is_publish and view_mode=preview enforce access control on frontend and backend.

- Repository: [小小鲁班/luban-h5](https://github.com/ly525/luban-h5)
- Tags: internals
- Published: 2026-03-06

---

**The Luban H5 editor distinguishes between permanent publishing and temporary previewing by combining a boolean `is_publish` flag with a `view_mode=preview` query parameter, enforcing access control in both the Vue.js front-end engine and the Node.js back-end controller.**

The `ly525/luban-h5` repository implements a dual-layer visibility system that allows creators to preview unpublished works while ensuring only released content is publicly accessible. This design centers on two complementary mechanisms: a persistent `is_publish` property stored on the work model and a transient `view_mode` query string that grants temporary render access.

## Publishing a Work from the Editor

The publish workflow originates in the editor's header component, where user actions translate into state mutations and API calls.

### Triggering the Publish Action

In [`front-end/h5/src/components/core/editor/header/action-menu.js`](https://github.com/ly525/luban-h5/blob/main/front-end/h5/src/components/core/editor/header/action-menu.js), the publish button triggers the `handlePublish()` method. This function updates the work's publication status through a Vuex mutation before persisting the change to the server.

```javascript
// action-menu.vue
handlePublish () {
  this.updateWork({ is_publish: true })   // mark work as published
  this.saveWork({ successMsg: '发布成功' }) // persist to server
}

```

The `updateWork` mutation writes `is_publish: true` into the work object. In [`front-end/h5/src/components/core/models/work.js`](https://github.com/ly525/luban-h5/blob/main/front-end/h5/src/components/core/models/work.js), the model stores this flag as `this.is_publish = !!work.is_publish`, ensuring a strict boolean value for downstream checks.

## Generating Shareable Preview URLs

When a creator opens the Share Info modal, the system generates two distinct URLs based on the current work ID. In [`front-end/h5/src/components/core/editor/modals/share-info.js`](https://github.com/ly525/luban-h5/blob/main/front-end/h5/src/components/core/editor/modals/share-info.js), the logic constructs these endpoints:

```javascript
// share-info.vue
previewUrl: `${window.location.origin}/works/preview/${this.work.id}?view_mode=preview`
releaseUrl: `${window.location.origin}/works/preview/${this.work.id}`

```

The **`previewUrl`** appends `?view_mode=preview` to force the rendering engine into preview mode, while the **`releaseUrl`** omits this parameter to simulate the experience of a standard visitor viewing a published work.

## Front-End Rendering Decision Logic

The rendering engine entry point at [`front-end/h5/src/engine-entry.js`](https://github.com/ly525/luban-h5/blob/main/front-end/h5/src/engine-entry.js) implements the authorization gate. It inspects the URL query string and the work's `is_publish` property to determine whether to render the page content or display an unpublished placeholder.

```javascript
const query = new URLSearchParams(window.location.search)
const canRender = query.get('view_mode') === 'preview' || work.is_publish
if (!canRender) return this.renderUnPublishTip()

```

This logic executes on lines 88–90 of the engine entry file. If the query parameter equals `'preview'` **or** the work's `is_publish` flag is truthy, the engine proceeds to render the work's pages. Otherwise, it invokes `renderUnPublishTip()` to show a "未发布" (not published) message.

## Back-End Verification Layer

The `ly525/luban-h5` back-end duplicates this authorization check to prevent data leakage through API requests. In [`back-end/h5-api/api/work/controllers/Work.js`](https://github.com/ly525/luban-h5/blob/main/back-end/h5-api/api/work/controllers/Work.js), the `previewOne` controller evaluates the same conditions before returning page data.

```javascript
const { view_mode } = ctx.request.query
const canRender = view_mode === VIEW_MODE.PREVIEW || work.is_publish
if (!canRender) work.pages = []   // hide unpublished content

```

Lines 24–27 of the Work controller demonstrate this defense-in-depth strategy. Even if a request bypasses the front-end checks, the server strips the `pages` array from the response when neither the preview query parameter nor the publish flag is present.

## Summary

- **Publishing** sets `is_publish: true` via the `handlePublish()` action in [`action-menu.js`](https://github.com/ly525/luban-h5/blob/main/action-menu.js), persisting the state through the work model.
- **Preview URLs** use the `?view_mode=preview` query parameter to grant temporary access to unpublished works without modifying the database.
- **Front-end enforcement** in [`engine-entry.js`](https://github.com/ly525/luban-h5/blob/main/engine-entry.js) requires either the preview parameter or the publish flag to render content.
- **Back-end verification** in [`Work.js`](https://github.com/ly525/luban-h5/blob/main/Work.js) mirrors this logic, returning empty page arrays for unauthorized requests to prevent data exposure.

## Frequently Asked Questions

### What is the difference between preview mode and published mode in Luban H5?

Preview mode provides temporary read-only access via the `view_mode=preview` query parameter, allowing creators to review changes before committing them. Published mode activates when `is_publish` is set to `true` in the database, making the work permanently accessible to all visitors without requiring special URL parameters.

### How does the back-end prevent unauthorized access to unpublished works?

The `previewOne` controller in [`back-end/h5-api/api/work/controllers/Work.js`](https://github.com/ly525/luban-h5/blob/main/back-end/h5-api/api/work/controllers/Work.js) checks both the `view_mode` query and the `work.is_publish` property. If neither condition is satisfied, the controller explicitly sets `work.pages = []` before sending the response, ensuring unpublished content never reaches the client.

### Where is the publish state stored in the Luban H5 data model?

The publish state lives as a boolean `is_publish` property on the work model, defined in [`front-end/h5/src/components/core/models/work.js`](https://github.com/ly525/luban-h5/blob/main/front-end/h5/src/components/core/models/work.js). The Vuex store synchronizes this value between the client UI and the back-end API, with the database persisting the flag for long-term access control.

### Can a user preview a work without clicking the Publish button?

Yes. The Share Info modal generates a `previewUrl` containing `?view_mode=preview`, which bypasses the `is_publish` check in both the front-end engine and back-end controller. This allows safe sharing of draft works with stakeholders without marking them as publicly released.