+
diff --git a/client/components/common/originalPosition.js b/client/components/common/originalPosition.js
new file mode 100644
index 000000000..37e0a4522
--- /dev/null
+++ b/client/components/common/originalPosition.js
@@ -0,0 +1,98 @@
+import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
+import { ReactiveVar } from 'meteor/reactive-var';
+import { Meteor } from 'meteor/meteor';
+import { Template } from 'meteor/templating';
+import './originalPosition.html';
+
+/**
+ * Component to display original position information for swimlanes, lists, and cards
+ */
+class OriginalPositionComponent extends BlazeComponent {
+ onCreated() {
+ super.onCreated();
+ this.originalPosition = new ReactiveVar(null);
+ this.isLoading = new ReactiveVar(false);
+ this.hasMoved = new ReactiveVar(false);
+
+ this.autorun(() => {
+ const data = this.data();
+ if (data && data.entityId && data.entityType) {
+ this.loadOriginalPosition(data.entityId, data.entityType);
+ }
+ });
+ }
+
+ loadOriginalPosition(entityId, entityType) {
+ this.isLoading.set(true);
+
+ const methodName = `positionHistory.get${entityType.charAt(0).toUpperCase() + entityType.slice(1)}OriginalPosition`;
+
+ Meteor.call(methodName, entityId, (error, result) => {
+ this.isLoading.set(false);
+ if (error) {
+ console.error('Error loading original position:', error);
+ this.originalPosition.set(null);
+ } else {
+ this.originalPosition.set(result);
+
+ // Check if the entity has moved
+ const movedMethodName = `positionHistory.has${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Moved`;
+ Meteor.call(movedMethodName, entityId, (movedError, movedResult) => {
+ if (!movedError) {
+ this.hasMoved.set(movedResult);
+ }
+ });
+ }
+ });
+ }
+
+ getOriginalPosition() {
+ return this.originalPosition.get();
+ }
+
+ isLoading() {
+ return this.isLoading.get();
+ }
+
+ hasMovedFromOriginal() {
+ return this.hasMoved.get();
+ }
+
+ getOriginalPositionDescription() {
+ const position = this.getOriginalPosition();
+ if (!position) return 'No original position data';
+
+ if (position.originalPosition) {
+ const entityType = this.data().entityType;
+ let description = `Original position: ${position.originalPosition.sort || 0}`;
+
+ if (entityType === 'list' && position.originalSwimlaneId) {
+ description += ` in swimlane ${position.originalSwimlaneId}`;
+ } else if (entityType === 'card') {
+ if (position.originalSwimlaneId) {
+ description += ` in swimlane ${position.originalSwimlaneId}`;
+ }
+ if (position.originalListId) {
+ description += ` in list ${position.originalListId}`;
+ }
+ }
+
+ return description;
+ }
+
+ return 'No original position data';
+ }
+
+ getOriginalTitle() {
+ const position = this.getOriginalPosition();
+ return position ? position.originalTitle : '';
+ }
+
+ showOriginalPosition() {
+ return this.getOriginalPosition() !== null;
+ }
+}
+
+OriginalPositionComponent.register('originalPosition');
+
+export default OriginalPositionComponent;
diff --git a/client/lib/originalPositionHelpers.js b/client/lib/originalPositionHelpers.js
new file mode 100644
index 000000000..cc1bbe755
--- /dev/null
+++ b/client/lib/originalPositionHelpers.js
@@ -0,0 +1,114 @@
+/**
+ * Helper functions for integrating original position tracking into existing Wekan templates
+ */
+
+/**
+ * Add original position tracking to swimlane templates
+ */
+export function addOriginalPositionToSwimlane(swimlaneId) {
+ if (!swimlaneId) return;
+
+ // Track original position when swimlane is created or first accessed
+ Meteor.call('positionHistory.trackSwimlane', swimlaneId, (error) => {
+ if (error) {
+ console.warn('Failed to track original position for swimlane:', error);
+ }
+ });
+}
+
+/**
+ * Add original position tracking to list templates
+ */
+export function addOriginalPositionToList(listId) {
+ if (!listId) return;
+
+ // Track original position when list is created or first accessed
+ Meteor.call('positionHistory.trackList', listId, (error) => {
+ if (error) {
+ console.warn('Failed to track original position for list:', error);
+ }
+ });
+}
+
+/**
+ * Add original position tracking to card templates
+ */
+export function addOriginalPositionToCard(cardId) {
+ if (!cardId) return;
+
+ // Track original position when card is created or first accessed
+ Meteor.call('positionHistory.trackCard', cardId, (error) => {
+ if (error) {
+ console.warn('Failed to track original position for card:', error);
+ }
+ });
+}
+
+/**
+ * Get original position description for display in templates
+ */
+export function getOriginalPositionDescription(entityId, entityType) {
+ return new Promise((resolve, reject) => {
+ const methodName = `positionHistory.get${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Description`;
+
+ Meteor.call(methodName, entityId, (error, result) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(result);
+ }
+ });
+ });
+}
+
+/**
+ * Check if an entity has moved from its original position
+ */
+export function hasEntityMoved(entityId, entityType) {
+ return new Promise((resolve, reject) => {
+ const methodName = `positionHistory.has${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Moved`;
+
+ Meteor.call(methodName, entityId, (error, result) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(result);
+ }
+ });
+ });
+}
+
+/**
+ * Template helper for displaying original position info
+ */
+Template.registerHelper('originalPositionInfo', function(entityId, entityType) {
+ if (!entityId || !entityType) return null;
+
+ const description = getOriginalPositionDescription(entityId, entityType);
+ const hasMoved = hasEntityMoved(entityId, entityType);
+
+ return {
+ description: description,
+ hasMoved: hasMoved,
+ entityId: entityId,
+ entityType: entityType
+ };
+});
+
+/**
+ * Template helper for checking if entity has moved
+ */
+Template.registerHelper('hasEntityMoved', function(entityId, entityType) {
+ if (!entityId || !entityType) return false;
+
+ return hasEntityMoved(entityId, entityType);
+});
+
+/**
+ * Template helper for getting original position description
+ */
+Template.registerHelper('getOriginalPositionDescription', function(entityId, entityType) {
+ if (!entityId || !entityType) return 'No original position data';
+
+ return getOriginalPositionDescription(entityId, entityType);
+});
diff --git a/docs/Design/Original-Positions.md b/docs/Design/Original-Positions.md
new file mode 100644
index 000000000..358467307
--- /dev/null
+++ b/docs/Design/Original-Positions.md
@@ -0,0 +1,248 @@
+# Original Positions Tracking Feature
+
+This feature allows users to see the original positions of swimlanes, lists, and cards before the list naming feature was added in commit [719ef87efceacfe91461a8eeca7cf74d11f4cc0a](https://github.com/wekan/wekan/commit/719ef87efceacfe91461a8eeca7cf74d11f4cc0a).
+
+## Overview
+
+The original positions tracking system automatically captures and stores the initial positions of all board entities (swimlanes, lists, and cards) when they are created. This allows users to:
+
+- View the original position of any entity
+- See if an entity has moved from its original position
+- Track the original title before any changes
+- View a complete history of original positions for a board
+
+## Features
+
+### 1. Automatic Position Tracking
+- **Swimlanes**: Tracks original sort position and title
+- **Lists**: Tracks original sort position, title, and swimlane assignment
+- **Cards**: Tracks original sort position, title, swimlane, and list assignment
+
+### 2. Database Schema
+The system uses a new `PositionHistory` collection with the following structure:
+```javascript
+{
+ boardId: String, // Board ID
+ entityType: String, // 'swimlane', 'list', or 'card'
+ entityId: String, // Entity ID
+ originalPosition: Object, // Original position data
+ originalSwimlaneId: String, // Original swimlane (for lists/cards)
+ originalListId: String, // Original list (for cards)
+ originalTitle: String, // Original title
+ createdAt: Date, // When tracked
+ updatedAt: Date // Last updated
+}
+```
+
+### 3. UI Components
+
+#### Individual Entity Display
+- Shows original position information for individual swimlanes, lists, or cards
+- Indicates if the entity has moved from its original position
+- Displays original title if different from current title
+
+#### Board-Level View
+- Complete overview of all original positions on a board
+- Filter by entity type (swimlanes, lists, cards)
+- Search and sort functionality
+- Export capabilities
+
+## Usage
+
+### 1. Automatic Tracking
+Position tracking happens automatically when entities are created. No manual intervention required.
+
+### 2. Viewing Original Positions
+
+#### In Templates
+```html
+
+{{> originalPosition entityId=swimlane._id entityType="swimlane"}}
+
+
+{{> originalPosition entityId=list._id entityType="list"}}
+
+
+{{> originalPosition entityId=card._id entityType="card"}}
+```
+
+#### In JavaScript
+```javascript
+import { addOriginalPositionToSwimlane, addOriginalPositionToList, addOriginalPositionToCard } from '/client/lib/originalPositionHelpers';
+
+// Track original position for a swimlane
+addOriginalPositionToSwimlane(swimlaneId);
+
+// Track original position for a list
+addOriginalPositionToList(listId);
+
+// Track original position for a card
+addOriginalPositionToCard(cardId);
+```
+
+### 3. Server Methods
+
+#### Track Original Positions
+```javascript
+// Track swimlane
+Meteor.call('positionHistory.trackSwimlane', swimlaneId);
+
+// Track list
+Meteor.call('positionHistory.trackList', listId);
+
+// Track card
+Meteor.call('positionHistory.trackCard', cardId);
+```
+
+#### Get Original Position Data
+```javascript
+// Get swimlane original position
+Meteor.call('positionHistory.getSwimlaneOriginalPosition', swimlaneId);
+
+// Get list original position
+Meteor.call('positionHistory.getListOriginalPosition', listId);
+
+// Get card original position
+Meteor.call('positionHistory.getCardOriginalPosition', cardId);
+```
+
+#### Check if Entity Has Moved
+```javascript
+// Check if swimlane has moved
+Meteor.call('positionHistory.hasSwimlaneMoved', swimlaneId);
+
+// Check if list has moved
+Meteor.call('positionHistory.hasListMoved', listId);
+
+// Check if card has moved
+Meteor.call('positionHistory.hasCardMoved', cardId);
+```
+
+#### Get Board History
+```javascript
+// Get all position history for a board
+Meteor.call('positionHistory.getBoardHistory', boardId);
+
+// Get position history by entity type
+Meteor.call('positionHistory.getBoardHistoryByType', boardId, 'swimlane');
+Meteor.call('positionHistory.getBoardHistoryByType', boardId, 'list');
+Meteor.call('positionHistory.getBoardHistoryByType', boardId, 'card');
+```
+
+## Integration Examples
+
+### 1. Add to Swimlane Template
+```html
+
+