Skip to Content
Core ConceptsDemo Mode

Demo mode

Every SeqDesk installation can host disposable demo workspaces — fully isolated, token-keyed copies of a researcher (or facility-admin) experience that anyone can spin up, poke at, and walk away from. The data lives in the same database as the rest of the install but is partitioned per token, so a demo session can’t see or affect real facility data. After a configurable expiry the workspace is deleted by a cleanup job.

This is what the seqdesk.com/demo URL points at, but the same surface is available in any install — handy for training, screencasts, or letting a prospective researcher click around before they sign up.

Enabling demo mode

Demo mode is off by default. All demo routes return 404 unless the install is started with SEQDESK_ENABLE_PUBLIC_DEMO=true (the client-exposed NEXT_PUBLIC_SEQDESK_ENABLE_PUBLIC_DEMO=true works too). With the flag unset, /demo, /demo/admin, and the embed variants all notFound().

Heads up: demo bootstrap overwrites the install’s global siteSettings singleton (display name, post-submission instructions, modules config). Don’t enable the public demo flag on a production install you also use for real work — the demo seeding mutates shared site-level state, not just per-token data.

URLs

PathAudienceWhat it shows
/demoPublic researcher demoStandalone researcher dashboard with seeded orders/studies
/demo/adminPublic facility-admin demoSame install seen as a facility admin (form builders, modules, ENA settings)
/demo/embedEmbeddable researcher demoStripped-down chrome for use inside an iframe (e.g., on the marketing site)
/demo/admin/embedEmbeddable facility-admin demoThe admin experience with the same iframe-friendly chrome as /demo/embed

All flows share the same backend. The difference is just which demoExperience is requested at bootstrap and how the page chrome renders.

Lifecycle

The flow is bootstrap → use → reset (optional) → expire → cleanup.

1. Bootstrap

When a user first hits /demo, the page calls POST /api/demo/bootstrap. The server either reuses an existing workspace (matched by a token cookie) or creates a new one:

What gets createdDetail
DemoWorkspace rowNew id, fresh random token, hashed and stored as tokenHash, expiresAt set in the future
Demo userEither a researcher or facility-admin user, marked isDemo: true
Seed dataA small set of demo orders, samples, studies, and form fields — enough that the dashboard isn’t empty
Site-settings overridesDisplay name set to “SeqDesk Demo”, help text set to a “this is a disposable session” reminder
Modules configReset to defaults
Auth cookieA session token cookie scoped to the demo user, expiring at expiresAt

The bootstrap response includes:

{ "created": true, "workspaceId": "ckxx...", "expiresAt": "2026-05-12T12:00:00.000Z", "demoExperience": "researcher" }

2. Use

From this point on, every API request the demo session makes carries the session cookie. Server-side, isDemoSession() checks the user.isDemo flag and disables a small number of features that don’t make sense in a sandbox (see Restrictions).

3. Reset

A logged-in demo user can call POST /api/demo/reset to wipe their workspace and re-seed. The same workspaceId is kept; the auth session token is re-issued. Useful when a demo gets “messy” mid-walkthrough.

4. Expire

Each DemoWorkspace.expiresAt is set at bootstrap to 12 hours in the future (the built-in DEMO_SESSION_TTL_HOURS default; reset refreshes it). Once that time passes the session cookie no longer authenticates and the workspace becomes a candidate for deletion.

5. Cleanup

GET /api/demo/cleanup deletes every DemoWorkspace whose expiresAt is in the past. The endpoint is gated behind a Bearer token check so it can be wired to a cron job (Vercel Cron, GitHub Actions, systemd timer) without exposing the cleanup ability to anonymous traffic. The expected secret comes from CRON_SECRET (or DEMO_CLEANUP_SECRET as an alias); the request must send Authorization: Bearer <that value>. In non-production environments with no secret configured the endpoint is open, to keep local testing simple. A typical setup runs it every 15 minutes.

Embed mode

/demo/embed renders the same researcher demo with chrome simplified for iframe embedding:

  • Top navigation collapsed
  • Branded SeqDesk header hidden
  • Sidebar minimized

The marketing site at seqdesk.com embeds this view to give visitors a working demo without leaving the page. The bootstrap, reset, and expiry flows are identical to the standalone /demo route — only the layout differs. There is also a /demo/admin/embed variant that renders the facility-admin demo with the same iframe-friendly chrome.

Restrictions

In a demo session the following are deliberately disabled:

  • File downloads/api/files/download returns 403 for isDemo users.
  • Assembly downloads — the Assemblies viewer hides the download column and shows a banner.
  • Real ENA submissions — submission attempts fall through to test mode regardless of the configured ENA settings.
  • Pipeline execution — pipelines can be inspected but not actually launched.

Outbound side effects (sending mail, calling external APIs) are also gated. Everything else — clicking through orders, editing forms, browsing studies — behaves exactly like the real app.

DemoWorkspace fields

Defined at prisma/schema.prisma:

FieldTypePurpose
idcuidWorkspace identifier
tokenHashunique stringSHA-256 of the bootstrap token; the raw token only lives in the browser cookie
userIdunique stringResearcher User row owned by this workspace
adminUserIdoptional stringFacility-admin User row, populated for admin demos
seedVersionintBumped when the seeder schema changes, used for migrations
lastSeenAtdatetimeUpdated on each request — useful for “active demos” telemetry
expiresAtdatetime, indexedCleanup query target
createdAt / updatedAtdatetimeStandard timestamps

Operating a public demo

A typical configuration for a public-facing demo:

# Run the cleanup endpoint every 15 minutes */15 * * * * curl -fsS -H "Authorization: Bearer $CRON_SECRET" \ https://your-host/api/demo/cleanup

Set CRON_SECRET (or DEMO_CLEANUP_SECRET) in the demo install’s environment to the same value the cron sends, plus SEQDESK_ENABLE_PUBLIC_DEMO=true to expose the demo routes at all. Workspace expiry defaults to 12 hours (DEMO_SESSION_TTL_HOURS) and is baked into the build; rebuild the install to change it.

When to use it

  • Onboarding — give new researchers a working sandbox before exposing them to production.
  • Marketing — embed /demo/embed on a landing page; visitors can interact with a fully functional SeqDesk without account creation.
  • Training & screencasts — record against /demo so the URL reset flow gives you a clean state between takes.
  • Bug repro — file uploads and pipeline launches are gated, but everything else (form configuration, MIxS validation, study workflows) reproduces faithfully.