Version & Lifecycle Management

Infomaxim provides a powerful version control and lifecycle management system that enables content staging, publishing workflows, and complete version history tracking for your data.

Overview

Version and lifecycle management in Infomaxim is built around the Aurora_Data table, which acts as a metadata layer on top of your content tables. This architecture provides:

  • Version History: Every change to a record creates a new version, maintaining a complete audit trail
  • Lifecycle States: Records can be in "Editing", "Staged", "Published", or "Deleted" states
  • Content Staging: Preview content changes before making them live to end users
  • Rollback Capability: Restore any previous version of a record
  • Scheduled Publishing: Set publish and expiration dates for timed content releases
Note: Lifecycle management applies only to versioned tables. Live tables always display their current data directly without versioning. Whether a table is versioned or live is configured in the aurora_tables system table.

The Aurora_Data Table

The Aurora_Data table is the central metadata repository that tracks versions and lifecycle states for all versioned records. Each record in a versioned content table has corresponding metadata entries in Aurora_Data.

Key Fields

Field Type Description
IDintUnique identifier for this metadata record
Shop_IDintApplication/site ID for multi-tenant support
Source_TablevarcharName of the content table this record belongs to
Current_IDintID of the current version of the record in the source table
Master_IDintID of the original/master record (remains constant across versions)
IsCurrentbitFlag indicating if this is the current version (1) or historical (0)
StatusvarcharLifecycle status: New, Editing, Staged, Published, Deleted, Expired, Rolled Back
PublishedbitFlag indicating if this version is published (1) or not (0)
StagedbitFlag indicating if this version is staged (1) or not (0)
IsExpiredbitFlag indicating if this version has expired (1) or not (0)
TitlevarcharDerived title of the record for display purposes
CreateddatetimeTimestamp when the record was created
Created_ByintUser ID of the creator
UpdateddatetimeTimestamp of the last update
Updated_ByintUser ID of the last updater
Publish_Set_DatedatetimeScheduled publish date
Publish_Expire_DatedatetimeScheduled expiration date
Publish_ByintUser ID who published the record
Last_IDintID of the previous version's Aurora_Data record
Next_IDintID of the next version's Aurora_Data record
LockbitFlag indicating if the record is locked for editing

Version Chain

The Last_ID and Next_ID fields form a linked list of versions, allowing you to traverse the version history both forward and backward:

Version 1 (Master_ID: 100, Current_ID: 100, Last_ID: null, Next_ID: 201)
    ↓
Version 2 (Master_ID: 100, Current_ID: 105, Last_ID: 200, Next_ID: 202)
    ↓
Version 3 (Master_ID: 100, Current_ID: 110, Last_ID: 201, Next_ID: null, IsCurrent: 1)

Live vs Versioned Tables

Infomaxim supports two types of data tables:

Live Tables

Live tables store data directly without versioning. Changes are immediately reflected to all users. The Live field in aurora_tables is set to True for these tables.

  • No version history maintained
  • Changes are immediate and visible to all users
  • Aurora_Data still tracks metadata but maintains only one current version
  • Useful for transactional data, user profiles, orders, etc.

Versioned Tables

Versioned tables maintain a full history of changes and support the complete lifecycle workflow. The Live field in aurora_tables is set to False for these tables.

  • Complete version history preserved
  • Support for Editing → Staging → Publishing workflow
  • Rollback to previous versions possible
  • Scheduled publishing and expiration
  • Useful for content management: articles, products, pages, etc.

Checking Table Type

To determine if a table is live or versioned, query the aurora_tables system table:

SELECT Live FROM aurora_tables WHERE table_database_name = 'your_table_name'

-- Live = 'True'  → Live table (no versioning)
-- Live = 'False' → Versioned table (full lifecycle support)

Version History

When a record in a versioned table is updated, the system automatically:

  1. Creates a new version in the source table with the updated data
  2. Copies the Aurora_Data record to preserve the old version's metadata
  3. Updates the original Aurora_Data record with IsCurrent = 0 and sets Next_ID
  4. Creates a new Aurora_Data record for the new version with IsCurrent = 1
  5. Links the versions using Last_ID and Next_ID

Version Creation Process

// Internal versioning logic (simplified)

// 1. Find current Aurora_Data record
SELECT id FROM Aurora_Data 
WHERE Source_table = 'products' 
  AND IsCurrent = 1 
  AND Current_ID = 100;

// 2. Copy the current record to create history
INSERT INTO Aurora_Data (...) 
SELECT ... FROM Aurora_Data WHERE ID = current_aurora_id;

// 3. Mark old version as not current
UPDATE Aurora_Data 
SET IsCurrent = 0, Lock = 0, Next_ID = new_aurora_id 
WHERE ID = current_aurora_id;

// 4. Update new version metadata
UPDATE Aurora_Data 
SET Title = 'New Title', 
    IsCurrent = 1, 
    Status = 'Editing', 
    Published = 0, 
    Staged = 0,
    Current_ID = new_record_id,
    Last_ID = old_aurora_id,
    Updated_By = user_id,
    Updated = GetDate() 
WHERE ID = new_aurora_id;

Fetching Versions

You can retrieve version history for any record by querying the Aurora_Data table.

Get All Versions of an Item

Use the Master_ID to find all versions of a specific record:

// API Request - Get version history
POST /getDataRows
{
  "table": "aurora_data",
  "fields": "id, current_id, title, status, published, staged, created, updated, updated_by",
  "isAppGrid": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      {
        "field": "master_id",
        "operator": "equals",
        "value": "100"
      },
      {
        "field": "source_table",
        "operator": "equals", 
        "value": "products"
      }
    ]
  },
  "orderBy": "id DESC"
}

Response Example

{
  "status": "Success",
  "data": [
    {
      "id": 503,
      "current_id": 110,
      "title": "Product v3 - Latest",
      "status": "Editing",
      "published": 0,
      "staged": 0,
      "created": "2024-01-15T14:30:00Z",
      "updated": "2024-01-15T14:30:00Z",
      "updated_by": 5
    },
    {
      "id": 502,
      "current_id": 105,
      "title": "Product v2 - Published",
      "status": "Published",
      "published": 1,
      "staged": 1,
      "created": "2024-01-10T09:15:00Z",
      "updated": "2024-01-12T10:00:00Z",
      "updated_by": 3
    },
    {
      "id": 501,
      "current_id": 100,
      "title": "Product v1 - Original",
      "status": "Published",
      "published": 0,
      "staged": 0,
      "created": "2024-01-01T12:00:00Z",
      "updated": "2024-01-01T12:00:00Z",
      "updated_by": 1
    }
  ]
}

Fetch a Specific Version

To retrieve the actual content of a specific version, query the source table using the Current_ID from the Aurora_Data record:

// First get the version's Current_ID from Aurora_Data
POST /getDataRows
{
  "table": "aurora_data",
  "fields": "current_id",
  "isAppGrid": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      { "field": "id", "operator": "equals", "value": "502" }
    ]
  },
  "record": true
}

// Then fetch the actual content using that Current_ID
POST /getDataRows
{
  "table": "products",
  "fields": "*",
  "isAppGrid": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      { "field": "id", "operator": "equals", "value": "105" }
    ]
  },
  "record": true
}

Rollback

Rolling back restores a previous version as the current version. This operation:

  1. Marks the current version's Aurora_Data record as not current
  2. Marks the selected historical version as current
  3. Updates the status to "Rolled Back"
Note: Rollback is currently managed through the Admin UI. API support for rollback operations is planned for a future release.

Rollback Logic (Admin System)

// Rollback process (internal)

// 1. Mark current version as not current
UPDATE Aurora_Data 
SET IsCurrent = 0, Updated = GetDate(), Updated_By = @userId 
WHERE ID = @currentVersionId;

// 2. Restore selected version as current
UPDATE Aurora_Data 
SET Status = 'Rolled Back', 
    IsCurrent = 1, 
    Updated = GetDate(), 
    Updated_By = @userId 
WHERE ID = @rollbackToVersionId;

After rollback, the Current_ID of the rolled-back Aurora_Data record points to the actual content record that should now be displayed.

Lifecycle Overview

The Infomaxim lifecycle system provides a content workflow from creation to publication and expiration:

┌──────────┐     ┌──────────┐     ┌───────────┐     ┌───────────┐
│   NEW    │ ──► │ EDITING  │ ──► │  STAGED   │ ──► │ PUBLISHED │
└──────────┘     └──────────┘     └───────────┘     └───────────┘
                      │                                    │
                      │                                    ▼
                      │                             ┌───────────┐
                      │                             │  EXPIRED  │
                      │                             └───────────┘
                      ▼
                ┌───────────┐
                │  DELETED  │
                └───────────┘

This workflow allows teams to:

  • Create and edit content without affecting the live site
  • Preview staged content on a staging environment
  • Schedule content for future publication
  • Automatically expire content after a set date

Lifecycle States

Each version of a record can be in one of the following states:

Status Published Staged Description
New 0 0 Newly created record, not yet edited
Editing 0 0 Record is being edited (draft state)
Staged 0 1 Record is approved for preview on staging environment
Published 1 1 Record is live and visible to end users
Expired 0 0 Record has passed its expiration date
Deleted 0 0 Record has been soft-deleted (not visible, but preserved)
Rolled Back - - Previous version restored as current

State Transitions

  • New → Editing: Automatic when first edited
  • Editing → Staged: Publish action with staging target
  • Editing → Published: Publish action with live target
  • Staged → Published: Promote staged content to live
  • Published → Expired: Automatic when Publish_Expire_Date is reached
  • Any → Deleted: Delete action (soft delete)

Publishing & Staging

The publishing system allows content to move through different visibility states:

Staging Content

Staging makes content visible on the staging/preview environment but not on the live production site:

// Publishing updates Aurora_Data with staging flags
UPDATE Aurora_Data 
SET Status = 'Staged',
    IsExpired = 0,
    Published = 0,
    Staged = 1,
    IsCurrent = 1,
    Lock = 0,
    Updated = GetDate(),
    Updated_By = @userId,
    Publish_By = @userId,
    Publish_Set_Date = @publishDate
WHERE ID = @auroraDataId;

Publishing Content

Publishing makes content visible on both staging and production environments:

// Publishing updates Aurora_Data with published flags
UPDATE Aurora_Data 
SET Status = 'Published',
    IsExpired = 0,
    Published = 1,
    Staged = 1,
    IsCurrent = 1,
    Lock = 0,
    Updated = GetDate(),
    Updated_By = @userId,
    Publish_By = @userId,
    Publish_Set_Date = @publishDate,
    Publish_Expire_Date = @expireDate
WHERE ID = @auroraDataId;

// Unpublish previous version
UPDATE Aurora_Data 
SET Published = 0, Staged = 0 
WHERE (Staged = 1 OR Published = 1) 
  AND Source_Table = @table 
  AND Master_ID = @masterId
  AND ID != @auroraDataId;

Scheduled Publishing

Content can be scheduled for future publication using Publish_Set_Date. The system will automatically make content visible when the scheduled date is reached:

// Query condition for scheduled content
WHERE Aurora_Data.Published = 1 
  AND Aurora_Data.Publish_Set_Date <= GetDate()
  AND (Aurora_Data.Publish_Expire_Date > GetDate() 
       OR Aurora_Data.Publish_Expire_Date IS NULL)
  AND Aurora_Data.IsExpired != 1

Fetching by Lifecycle Stage

The API provides several options to control which lifecycle stage of content is returned:

Option: isPublished / production

Returns only published content that has passed its publish date and has not expired:

POST /getDataRows
{
  "table": "products",
  "fields": "id, title, price, description",
  "isPublished": true,
  "orderBy": "title ASC"
}

This generates a query that includes:

SELECT ... FROM products
INNER JOIN Aurora_Data ON products.id = Aurora_Data.Current_ID
WHERE Aurora_Data.Source_Table = 'products'
  AND Aurora_Data.Published = 1
  AND Aurora_Data.Publish_Set_Date <= GetDate()
  AND (Aurora_Data.Publish_Expire_Date > GetDate() 
       OR Aurora_Data.Publish_Expire_Date IS NULL)
  AND Aurora_Data.IsExpired != 1

Option: isStage

Returns staged content (preview environment). Useful for previewing content before it goes live:

POST /getDataRows
{
  "table": "products",
  "fields": "id, title, price, description",
  "isStage": true,
  "orderBy": "title ASC"
}

This generates a query that includes:

SELECT ... FROM products
INNER JOIN Aurora_Data ON products.id = Aurora_Data.Current_ID
WHERE Aurora_Data.Source_Table = 'products'
  AND Aurora_Data.Staged = 1
  AND Aurora_Data.Publish_Set_Date <= GetDate()
  AND (Aurora_Data.Publish_Expire_Date > GetDate() 
       OR Aurora_Data.Publish_Expire_Date IS NULL)
  AND Aurora_Data.IsExpired != 1

Option: isLive / isAdmin

Returns the current version regardless of publish status (admin view). Useful for content management interfaces:

POST /getDataRows
{
  "table": "products",
  "fields": "id, title, price, description",
  "isLive": true,
  "orderBy": "title ASC"
}

This generates a query that includes:

SELECT ... FROM products
INNER JOIN Aurora_Data ON products.id = Aurora_Data.Current_ID
WHERE Aurora_Data.Source_Table = 'products'
  AND Aurora_Data.IsCurrent = 1

Option: isAppGrid

Bypasses the versioning system entirely, returning raw data from the table:

POST /getDataRows
{
  "table": "products",
  "fields": "id, title, price",
  "isAppGrid": true,
  "orderBy": "id DESC"
}

This generates a direct query:

SELECT id, title, price FROM products ORDER BY id DESC
Caution: Using isAppGrid: true bypasses all versioning and security controls. Use only for system tables or when you specifically need unfiltered access. Never use isAppGrid with user-generated content or in production APIs exposed to untrusted clients. This option should be reserved for admin-only operations on trusted, internal data.

Expiration

Content can be automatically expired based on the Publish_Expire_Date field:

Setting Expiration

When publishing content, set an expiration date to automatically remove it from public view:

// Expiration is set during the publish action
UPDATE Aurora_Data 
SET Published = 1,
    Staged = 1,
    Publish_Set_Date = '2024-03-01',
    Publish_Expire_Date = '2024-03-31'
WHERE ID = @auroraDataId;

Manual Expiration

Content can also be manually expired:

UPDATE Aurora_Data 
SET Status = 'Expired',
    Published = 0,
    Staged = 0,
    IsExpired = 1,
    Publish_Expire_Date = GetDate(),
    Updated = GetDate(),
    Updated_By = @userId
WHERE Master_ID = @masterId 
  AND (Published = 1 OR Staged = 1)
  AND Source_Table = @table;

Expiration Queries

The system automatically excludes expired content from published and staged queries by checking:

  • IsExpired != 1
  • Publish_Expire_Date > GetDate() OR Publish_Expire_Date IS NULL

Lifecycle API Options

Summary of all lifecycle-related options available in the /getDataRows endpoint:

Option Type Description
isPublished boolean Returns only published content visible to end users
production boolean Alias for isPublished
isStage boolean Returns staged content for preview environments
isLive boolean Returns current version regardless of publish status
isAdmin boolean Alias for isLive
isAppGrid boolean Bypasses versioning system entirely

Priority Order

When multiple options are set, the system applies them in this order:

  1. isAppGrid - Direct table query (highest priority)
  2. isLive / isAdmin - Current version query
  3. isStage - Staged content query
  4. isPublished / production - Published content query (default for public APIs)

Meta Fields

When querying versioned tables, the API automatically includes metadata fields from Aurora_Data:

Field Description
meta_master_idThe permanent ID of the record across all versions
meta_current_idThe ID of the current version in the source table
meta_titleThe derived title of the record
meta_statusCurrent lifecycle status
meta_updatedLast update timestamp
Tip: Use meta_master_id as the stable identifier when building relationships between records, as this ID remains constant across version changes.

Encrypted ID

The API also returns an encrypted _id field for secure client-side handling:

{
  "_id": "encrypted_master_id_string",
  "meta_master_id": 100,
  "meta_current_id": 110,
  "meta_status": "Published",
  "meta_title": "Product Name",
  "meta_updated": "2024-01-15T14:30:00Z",
  "id": 110,
  "title": "Product Name",
  "price": 99.99
}

Complete Examples

Example 1: Get Published Products for Storefront

Retrieve all products that are currently published and visible to customers:

POST /getDataRows
{
  "table": "products",
  "fields": "id, title, price, description, image",
  "isPublished": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      {
        "field": "category",
        "operator": "equals",
        "value": "electronics"
      },
      {
        "field": "price",
        "operator": "less_than",
        "value": "1000"
      }
    ]
  },
  "orderBy": "price ASC",
  "isPaging": true,
  "perPage": 20,
  "page": 1
}

Example 2: Preview Staged Content

For a staging environment, retrieve content that has been staged but not yet published:

POST /getDataRows
{
  "table": "articles",
  "fields": "id, title, content, author, publish_date",
  "isStage": true,
  "orderBy": "publish_date DESC",
  "perPage": 10
}

Example 3: Admin Content Management

For the admin interface, show all current versions including drafts:

POST /getDataRows
{
  "table": "articles",
  "fields": "id, title, meta_status, meta_updated",
  "isLive": true,
  "orderBy": "meta_updated DESC"
}

Example 4: Get Version History

Retrieve the complete version history for a specific product:

// Step 1: Find the master_id for the current product
POST /getDataRows
{
  "table": "aurora_data",
  "fields": "master_id",
  "isAppGrid": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      { "field": "current_id", "operator": "equals", "value": "110" },
      { "field": "source_table", "operator": "equals", "value": "products" },
      { "field": "iscurrent", "operator": "equals", "value": "1" }
    ]
  },
  "record": true
}

// Step 2: Get all versions with that master_id
POST /getDataRows
{
  "table": "aurora_data",
  "fields": "id, current_id, title, status, published, staged, created, updated, updated_by, publish_set_date",
  "isAppGrid": true,
  "whereConditions": {
    "operator": "AND",
    "conditions": [
      { "field": "master_id", "operator": "equals", "value": "100" },
      { "field": "source_table", "operator": "equals", "value": "products" }
    ]
  },
  "orderBy": "id DESC"
}

Example 5: JavaScript Implementation

Complete JavaScript example for fetching products based on environment:

// Configuration - set your API base URL
// Development: http://localhost:3001
// Production: Replace 'YOUR_DOMAIN' with your actual domain
const API_BASE_URL = 'https://YOUR_DOMAIN/infomaxim/api/v2';

// Utility function to fetch products based on environment
// Note: accessToken should be obtained from your authentication flow
// See authentication.asp for details on obtaining tokens
async function getProducts(accessToken, options = {}) {
  const {
    environment = 'production', // 'production', 'staging', 'admin'
    category = null,
    page = 1,
    perPage = 20
  } = options;

  // Determine lifecycle option based on environment
  let lifecycleOption = {};
  switch (environment) {
    case 'staging':
      lifecycleOption = { isStage: true };
      break;
    case 'admin':
      lifecycleOption = { isLive: true };
      break;
    default:
      lifecycleOption = { isPublished: true };
  }

  // Build conditions
  const conditions = [];
  if (category) {
    conditions.push({
      field: 'category',
      operator: 'equals',
      value: category
    });
  }

  const response = await fetch(API_BASE_URL + '/getDataRows', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      table: 'products',
      fields: 'id, title, price, description, image',
      ...lifecycleOption,
      whereConditions: conditions.length > 0 ? {
        operator: 'AND',
        conditions
      } : undefined,
      orderBy: 'title ASC',
      isPaging: true,
      perPage,
      page
    })
  });

  return await response.json();
}

// Usage examples:
// IMPORTANT: Replace with actual token from authentication
// See authentication.asp for how to obtain tokens via /signin
const accessToken = 'REPLACE_WITH_ACTUAL_JWT_TOKEN';

// Production storefront
const liveProducts = await getProducts(accessToken, { environment: 'production' });

// Staging preview
const stagedProducts = await getProducts(accessToken, { environment: 'staging' });

// Admin CMS
const allProducts = await getProducts(accessToken, { environment: 'admin' });