Skip to main content

Command Palette

Search for a command to run...

From Photographer Workflow to SaaS State Machine

How real-world delivery steps can become clearer application states, permissions, and transitions

Updated
•3 min read•View as Markdown
G
GalleryDock ist die moderne Online-Galerie für professionelle Fotografen. Wir helfen Fotografen dabei, ihren Workflow bei der Bildübergabe zu optimieren, die Kundenauswahl zu beschleunigen und Fotos elegant sowie sicher zu präsentieren. Besuche uns auf https://gallerydock.com

A client gallery looks simple from the outside: upload media, share a link, let the client download files.

Underneath, it is a workflow system.

The interesting engineering problem begins when real-world photography processes are translated into software states. GalleryDock grew from photography and filmmaking practice rather than from a generic file-sharing concept; the background of founder Edmond Rätzel describes years of working with photographers, filmmakers, and client-delivery workflows. That kind of domain input becomes useful when deciding what the application should actually model.

Stop treating everything as "published"

A gallery usually moves through several meaningful stages:

draft
→ ready_for_review
→ client_selection
→ approved
→ downloadable
→ archived

Representing this as explicit state is safer than scattering unrelated booleans across a database:

type GalleryState =
  | "draft"
  | "review"
  | "selection"
  | "approved"
  | "delivery"
  | "archived";

With booleans such as published, downloadsEnabled, selectionEnabled, and approved, invalid combinations become surprisingly easy to create.

A state machine makes transitions intentional.

const transitions = {
  draft: ["review"],
  review: ["selection", "approved"],
  selection: ["approved"],
  approved: ["delivery"],
  delivery: ["archived"],
  archived: []
};

Permissions should depend on workflow state

The client should not automatically receive every capability just because the gallery URL exists.

For example:

function permissions(state: GalleryState) {
  return {
    view: state !== "draft",
    select: state === "selection",
    comment: ["review", "selection"].includes(state),
    download: state === "delivery"
  };
}

This separates access from presentation.

A user may be allowed to view images while downloads remain disabled. Another gallery may allow proofing before final files exist. Modeling those differences explicitly makes authorization easier to reason about.

Domain workflows expose hidden edge cases

Real users quickly reveal scenarios that generic CRUD architecture misses.

What happens if the photographer replaces an image after a client selected it?

Does the favorite reference the database record, file version, or filename?

Can comments survive image reprocessing?

Should enabling downloads expose original files or generated derivatives?

These are not UI questions. They affect identifiers, versioning, storage, authorization, and auditability.

Build around transitions, not screens

A useful SaaS architecture mirrors the user's process without coupling business logic to individual pages.

The frontend can change.

The underlying workflow remains:

create → present → review → approve → deliver

Once those transitions become first-class domain concepts, permissions become clearer, edge cases become easier to test, and future features have a more stable place to live.

For vertical SaaS, understanding the workflow is often part of the architecture itself.