Banner image for Versioning
Core Concepts 8 min read

Versioning

Understand the versioning patterns Catalio uses — explicit Application Versions, paper-trail change tracking, and the superseding pattern for Requirements

Updated
On this page

Catalio uses several distinct versioning patterns, each designed for a different kind of change. Understanding which pattern applies — and why — helps you build a reliable, traceable record of how your systems and specifications evolve over time.

The three patterns are:

  1. Application Versions — explicit snapshots of a software system state, used as anchors for journey capture and before/after comparison
  2. Paper Trail — automatic field-level change history on many Catalio resources, built on AshPaperTrail
  3. Superseding — a semantic replacement pattern specific to Requirements, where an old requirement is formally replaced by a new one while both remain in the system

Application Versions

An Application Version is a named, discrete snapshot of an Application at a point in time. It might represent a specific software release, a particular environment state (production vs. staging), or a design milestone before a modernization effort.

Why Versions Exist

Journeys in Catalio are anchored to a specific Application Version. Without this anchor, journey data is ambiguous — a journey captured against a legacy system in January and a journey captured against the same system after a major patch in June may describe meaningfully different user experiences. Application Versions make that distinction explicit and queryable.

This anchoring enables the core Catalio modernization workflow:

  1. Define a legacy Application Version (e.g., "Oracle EBS 12.2.9 Pre-Migration")
  2. Capture journeys against that version — recording friction, step sequences, and pain points
  3. Define a target Application Version (e.g., "Target SaaS Platform v1")
  4. Capture journeys against the new system once available
  5. Create a Journey Comparison to prove measurable UX improvement

Key Fields

Field Description
version_label Human-readable label, e.g. "Legacy", "V1.0", "Target Design v1". Required; unique per application.
version_number Optional structured identifier for sorting, e.g. "1.0.0" or "2.0.0-rc1"
release_date When this version was released or became active
status :active, :deprecated, or :archived
notes Additional context about what this version represents

version_label is unique per application — you cannot have two versions with the same label under the same parent. This is enforced at the database level via a unique index on [:application_id, :version_label].

Relationship to Application and Journeys

Application Versions are always children of a parent Application. An orphaned version cannot exist. Each version has a has_many :journeys relationship — all journeys recorded against that version of the system.

Common Patterns

Legacy modernization — create a “Legacy” version as the baseline, then a “Target” version as a placeholder before the new system exists. Pre-wire your journey captures and comparison structures early.

Incremental release tracking — create one version per meaningful release boundary (v2.0, v3.0), not one per patch. Versions should correspond to states where user experience measurably differs.

Environment-based analysis — create separate versions for “Production” and “UAT” when you need to compare how users behave in each environment.

Retirement — when a version is no longer active, mark it :deprecated or :archived rather than deleting it. Historical journey data remains intact and queryable.

Paper Trail Change Tracking

Many resources in Catalio use the AshPaperTrail.Resource extension to automatically record a change history for every create, update, and delete operation. This is field-level audit tracking — when a field value changes, the old and new values are captured in a version record.

How It Works

When a resource opts into PaperTrail with change_tracking_mode: :full_diff, every mutation produces a version record containing:

  • The type of change (create, update, destroy)
  • The before and after values for each changed field
  • A timestamp
  • The actor (user) who made the change, stored as created_by and updated_by belongs-to relationships

Resources using PaperTrail with full-diff tracking include Application Versions, Journey Comparisons, and others across the Journeys and Documentation domains. The Catalio.Journeys and Catalio.Documentation domains declare paper_trail do include_versions? true end at the domain level, opting all their resources into the version history system.

What You Can Do With It

The version history provides an audit trail that answers questions like:

  • Who changed this Application Version’s status from :active to :deprecated, and when?
  • What was the original metrics value on a Journey Comparison before it was updated?
  • Has this resource been modified since it was created?

In Catalio’s UI, version history surfaces in the activity feeds and audit views for supported resources. Programmatically, you can load versions via Ash’s standard association loading using the versions relationship that AshPaperTrail adds to participating resources.

What It Does Not Cover

PaperTrail tracks changes to resource fields — it does not track relationship adds/removes (joining a Persona to a Requirement, for example) unless the join table resource also opts into PaperTrail. For semantic replacement of a concept (an old requirement replaced by a new one), the superseding pattern is more appropriate.

The Superseding Pattern

The superseding pattern is specific to Requirements. It handles the case where a requirement’s meaning changes so significantly that the original can no longer be edited in place — a new requirement should be written instead, and the old one should be formally retired with a record of why.

How It Works

When a requirement needs to be replaced:

  1. Create a new requirement containing the updated specification
  2. Trigger the :supersede action on the old requirement, linking it to the new one
  3. Provide a reason explaining why the replacement was necessary
  4. Add notes with further context if needed

Both requirements remain in the system. The old requirement is marked with status :superseded and carries a relationship pointing to the requirement that replaced it. The new requirement carries a complementary relationship pointing back to what it superseded.

Example

Plaintext
REQ-001: "As a User, I want to export data as CSV so that I can analyze it in Excel"
Status: Superseded → REQ-042
Reason: "User feedback showed need for multiple formats and field selection"
REQ-042: "As a User, I want to export as CSV, JSON, or Excel with custom field selection
so that I can analyze in multiple tools and choose relevant fields"
Status: Active
Supersedes: REQ-001

Why Not Just Edit?

Editing a requirement in place erases the history of what was originally specified. For audit-sensitive organizations (compliance, regulated industries), that history matters. The superseding pattern also makes impact visible — any test cases, use cases, or policies linked to REQ-001 remain attached to it, giving teams an explicit list of downstream artifacts that may need to be re-evaluated against the new specification.

When to Use Which Pattern

Scenario Pattern to use
You need to anchor journey captures to a specific system state Application Version
You want to prove before/after UX improvement across a release Application Version + Journey Comparison
You want to know who changed a field and what the old value was Paper Trail
You need a compliance-ready audit log of resource mutations Paper Trail
A requirement’s meaning has changed enough to warrant a new record Superseding
A requirement has been formally retired and replaced by another Superseding
You just need to correct a typo in a requirement Edit in place (no special pattern needed)

The patterns are not mutually exclusive. A requirement could be superseded (semantic replacement), and both the old and new requirement records are independently tracked by PaperTrail (field-level history). The Application Version that journeys were captured against is also PaperTrail-tracked, so you can see when its status or notes changed.

Best Practices

Name Application Versions for stakeholders, not machines. "Oracle 12.2.9 Pre-Migration" is clearer to a business analyst in a comparison report than "v12.2.9.0-legacy".

Create target versions before the system exists. You can create a "Target Design v1" Application Version as a placeholder before the modernized system is available. This lets you pre-wire journey capture sessions and comparison structures.

Let PaperTrail run silently. You do not need to think about PaperTrail during normal usage — it captures changes automatically. Reference it when you need to investigate a change or produce an audit report.

Supersede rather than delete. When a requirement changes significantly, avoid deleting the original. The superseding relationship preserves the decision trail and keeps downstream artifacts (test cases, policies, components) connected to the historical record.

Retire old Application Versions explicitly. Mark versions :deprecated when no longer active. This keeps the version picker clean without losing the journey history captured against them.

Next Steps

  • Application — Understand the parent entity that Application Versions belong to
  • Requirements — Learn more about the superseding lifecycle and requirement states
  • Journey Comparisons — See how Application Versions enable rigorous before/after comparison
  • Journeys — Understand how journeys are anchored to specific versions

Support

  • Documentation: Continue reading about Applications and Journeys
  • Email: support@catalio.ai
  • Community: Share versioning strategies with other Catalio users