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
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 |
|---|---|---|
ID | int | Unique identifier for this metadata record |
Shop_ID | int | Application/site ID for multi-tenant support |
Source_Table | varchar | Name of the content table this record belongs to |
Current_ID | int | ID of the current version of the record in the source table |
Master_ID | int | ID of the original/master record (remains constant across versions) |
IsCurrent | bit | Flag indicating if this is the current version (1) or historical (0) |
Status | varchar | Lifecycle status: New, Editing, Staged, Published, Deleted, Expired, Rolled Back |
Published | bit | Flag indicating if this version is published (1) or not (0) |
Staged | bit | Flag indicating if this version is staged (1) or not (0) |
IsExpired | bit | Flag indicating if this version has expired (1) or not (0) |
Title | varchar | Derived title of the record for display purposes |
Created | datetime | Timestamp when the record was created |
Created_By | int | User ID of the creator |
Updated | datetime | Timestamp of the last update |
Updated_By | int | User ID of the last updater |
Publish_Set_Date | datetime | Scheduled publish date |
Publish_Expire_Date | datetime | Scheduled expiration date |
Publish_By | int | User ID who published the record |
Last_ID | int | ID of the previous version's Aurora_Data record |
Next_ID | int | ID of the next version's Aurora_Data record |
Lock | bit | Flag 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:
- Creates a new version in the source table with the updated data
- Copies the Aurora_Data record to preserve the old version's metadata
- Updates the original Aurora_Data record with
IsCurrent = 0and setsNext_ID - Creates a new Aurora_Data record for the new version with
IsCurrent = 1 - Links the versions using
Last_IDandNext_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:
- Marks the current version's Aurora_Data record as not current
- Marks the selected historical version as current
- Updates the status to "Rolled Back"
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_Dateis 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
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 != 1Publish_Expire_Date > GetDate()ORPublish_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:
isAppGrid- Direct table query (highest priority)isLive/isAdmin- Current version queryisStage- Staged content queryisPublished/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_id | The permanent ID of the record across all versions |
meta_current_id | The ID of the current version in the source table |
meta_title | The derived title of the record |
meta_status | Current lifecycle status |
meta_updated | Last update timestamp |
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' });