Skip to content

Manage project delivery

import { Aside, Steps } from ‘@astrojs/starlight/components’;

The Delivery tab is where you keep the client informed about where their project is. Once you set it up, the client sees a Status page with the ETA, the ordered checkpoint list, and (optionally) a live preview URL. This guide walks the admin side.

For the client-side view and how access is granted, see Client portal.

  • A Melbora Website you can administer
  • The Website has at least one client with access — either an owner (transferred) or a linked client (added via “Add Client”). Without one, the Delivery tab still works, but nobody’s reading it.

Brand-new Websites have no delivery block. Until you set one up, clients see an empty Status page.

  1. Open the Website in the portal and go to the Delivery tab.

    If no delivery block exists yet, you’ll see a single Set up delivery tracking button.

  2. Click “Set up delivery tracking”.

    This calls PUT /websites/:id/delivery with the default body and seeds the default checkpoint template. The page reloads into the editable Delivery surface.

  3. Adjust the ETA.

    The default ETA is 30 days from setup — almost always wrong. Set it to your actual estimated completion date.

  4. Edit, add, or remove checkpoints to match the project.

    The default list is intentionally generic. Customize per project.

Setting up tracking seeds these six checkpoints, in this order, all with status: "pending":

OrderIdLabel
10kickoffKickoff
20design-approvedDesign approved
30initial-deployInitial deploy
40content-loadedContent loaded
50qaQA
60launchLaunch

You can add, rename, reorder, or delete entries per Website — the seed is just a starting point. The order field uses ints with gaps of 10 so you can insert new checkpoints mid-list without renumbering everything (e.g. an order: 35 slots between initial-deploy and content-loaded).

Checkpoint ids must be slug-ish (alphanumerics + dashes) and unique within the delivery block. A Website can have up to 40 checkpoints.

The Delivery tab supports drag-to-reorder. Grab a checkpoint by its burger handle and drag vertically — the motion is constrained to the parent column so a stray horizontal drag won’t tear the row out of the list. On drop, the portal renumbers the whole list with the standard 10-step spacing (10, 20, 30, …) and persists the new order ints via the same PUT /websites/:id/delivery call. There’s no API change — the wire payload still carries the checkpoints array in its new sequence with refreshed order values.

Each checkpoint accepts an optional dueAt (ISO timestamp). In the Delivery tab, click the dashed + deadline pill on any checkpoint row to seed a default 14-days-out date and open the DatePicker popover; the × on the pill clears it. The portal anchors the picked date at noon UTC before sending it to the server so timezone shifts can’t push it across a day boundary.

dueAt is display-only — no reminder emails, no status auto-flips, no escalations. It exists so the client can see what you’re aiming for on the Status timeline: “Due Aug 14” on pending checkpoints, a “due …” subtext on in-progress ones, and the completion timestamp on done ones (which supersedes the deadline once shipped).

The ETA shows up on the client’s Status page as the headline date. Bump it whenever the schedule changes — the client sees the new value on next load.

import { VantageClient } from "@vantageconnections/sdk";
const vc = new VantageClient({ token: process.env.VANTAGE_TOKEN! });
const { delivery: current } = await vc.websites.delivery.get("wb_01J7XXX");
await vc.websites.delivery.update("wb_01J7XXX", {
estimatedCompletionAt: "2026-07-15T00:00:00.000Z",
showPreviewUrl: current?.showPreviewUrl ?? false,
// Omit `checkpoints` to keep the current list; include it to replace.
// Each entry may carry an optional `dueAt` (ISO; anchor it at noon UTC
// to dodge timezone-shift surprises) that surfaces on the client
// Status timeline. `dueAt` is display-only — no automation fires off it.
checkpoints: [
{ id: "kickoff", label: "Kickoff", order: 10, status: "done" },
{
id: "design-approved",
label: "Design approved",
order: 20,
status: "in_progress",
dueAt: "2026-06-20T12:00:00.000Z",
},
{ id: "launch", label: "Launch", order: 30, status: "pending" },
],
});

The update endpoint replaces the delivery block whole when checkpoints is included; omit it to keep the existing list.

showPreviewUrl defaults to false on freshly-seeded delivery blocks. While it’s off, the client’s Status page doesn’t surface any link to the work-in-progress site — you keep working privately.

Flip it to true when you’re comfortable with the build state and ready to let the client poke at it.

await vc.websites.delivery.update("wb_01J7XXX", {
estimatedCompletionAt: current!.estimatedCompletionAt,
showPreviewUrl: true,
});

The URL Melbora shows the client is resolved server-side, in this order:

  1. previewUrlOverride if you’ve set one (see below).
  2. The latest Vercel deployment URL for the linked Vercel project.
  3. Nothing — the client just won’t see a preview button this poll if neither is available (e.g. Vercel API hiccup).

Admins always see the resolved preview URL in the Delivery tab regardless of the toggle — the toggle only gates client visibility, not your own.

previewUrlOverride for custom-domain previews

Section titled “previewUrlOverride for custom-domain previews”

By default Melbora resolves the preview to the latest Vercel deployment URL (e.g. client-slug-abc123.vercel.app). If the canonical preview lives somewhere else — a staging subdomain, a custom domain Vercel doesn’t know about — set previewUrlOverride to that full URL. It takes precedence over the Vercel lookup whenever it’s non-empty.

await vc.websites.delivery.update("wb_01J7XXX", {
estimatedCompletionAt: current!.estimatedCompletionAt,
showPreviewUrl: true,
previewUrlOverride: "https://staging.acme.com",
});

Set it back to "" (empty string) to clear it and fall back to Vercel’s latest deployment.

Each checkpoint has three valid statuses: pending, in_progress, done. Flipping the status persists immediately.

// "Design approved" just shipped:
await vc.websites.delivery.setCheckpointStatus(
"wb_01J7XXX",
"design-approved",
"done"
);

When a checkpoint flips to done, the server stamps completedAt on the row. Flipping it out of done (back to in_progress or pending) clears completedAt.

The 8px progress bar above the checkpoint list shows three segments — done (solid gold), in_progress (animated diagonal stripes, the Domino’s-tracker idiom), and pending (empty). The animation respects prefers-reduced-motion. The sub-label adds ”· N in progress” in gold whenever any checkpoint is mid-flight. The same bar renders on the client Status page, so the visual treatment is intentional and shared across both surfaces.

This corresponds to PUT /websites/:id/delivery/checkpoints/:checkpointId (WebsitesDeliveryApi.setCheckpointStatus in the SDK; vantage websites delivery checkpoint in the CLI reference).

The same operations from a terminal:

Terminal window
# Read the current delivery block + resolved preview URL.
vantage websites delivery get <websiteId>
# Push a new ETA (positional ISO timestamp).
vantage websites delivery set-eta <websiteId> 2026-07-15T00:00:00Z
# Show / hide the preview URL to the client.
vantage websites delivery set-preview <websiteId> true
vantage websites delivery set-preview <websiteId> false
# Flip one checkpoint's status.
vantage websites delivery checkpoint <websiteId> design-approved done

A previewUrlOverride (for surfacing a custom staging URL instead of the latest Vercel deployment) is set via the portal’s Delivery tab or the SDK — there’s no CLI flag for it today.

Exact subcommand listing is in the auto-generated CLI reference.