mirror-tasks
v1.3.3
Published
Bidirectional sync between Leantime and Trello with status mapping, milestones, users, and HTML to Markdown conversion
Maintainers
Readme
Mirror Tasks - Leantime ↔ Trello Sync
A TypeScript application that provides bidirectional synchronization between Leantime and Trello, with project-based filtering, automatic backup/restore, and advanced features like status mapping, milestone labels, and user assignments.
Features
- ✅ Project-based sync: Only syncs projects listed in
projects.csv(max 10) - ✅ Project code suffixes: Adds
#CODE-<task-id>suffix to task names (at the end) - ✅ Status synchronization: Maps Leantime statuses to Trello lists automatically
- ✅ Milestone labels: Syncs Leantime milestones as Trello labels
- ✅ User assignments: Syncs Leantime user assignments to Trello card members
- ✅ Task relations: Syncs task dependencies and relations as comments and in descriptions
- ✅ HTML to Markdown: Converts Leantime HTML descriptions to clean Markdown for Trello
- ✅ Override mode: Force one-way sync from Leantime to Trello (overwrites Trello)
- ✅ Optional Leantime prefixes: Can add suffixes to Leantime headlines (via
ADD_PREFIX_TO_LEANTIMEenv var) - ✅ Automatic cleanup: Removes Trello cards for projects not in CSV list (with backup)
- ✅ Backup & restore: Automatically backs up removed projects and supports restore
- ✅ Bidirectional sync: Syncs changes from both Leantime and Trello
- ✅ Dry-run mode: Test sync without making changes
- ✅ Simulation mode: Fetch and save data without making changes
- ✅ Continuous sync server: Run as a service with web UI for play/pause/force sync
- ✅ Multi-instance support: Support multiple Leantime and Trello instances with separate mappings
Prerequisites
- Node.js 18+ (for native
fetchsupport) - TypeScript 5.9+
- Leantime API token
- Trello API key and token
Installation
- Clone the repository:
git clone <repository-url>
cd mirror-tasks- Install dependencies:
npm install- Copy the example environment file:
cp .env.example .envEdit
.envwith your configuration (see Configuration)Copy the example projects CSV:
cp projects.csv.example projects.csv- Edit
projects.csvwith your project codes and names (see Project CSV Format)
Configuration
Environment Variables
Create a .env file based on .env.example:
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| LEANTIME_URL | Yes* | - | Leantime server URL (or LEANTIME1_URL, LEANTIME2_URL, etc. for multi-instance) |
| LEANTIME_APITOKEN | Yes* | - | Leantime API token (or LEANTIME1_APITOKEN, LEANTIME2_APITOKEN, etc.) |
| TRELLO_API_KEY | Yes* | - | Trello API key (or TRELLO1_API_KEY, TRELLO2_API_KEY, etc. for multi-instance) |
| TRELLO_APITOKEN | Yes* | - | Trello API token (or TRELLO1_APITOKEN, TRELLO2_APITOKEN, etc.) |
| TRELLO_BOARD_ID | Conditional | - | Trello board ID (or TRELLO1_BOARD_ID, TRELLO2_BOARD_ID, etc.) |
| TRELLO_LIST_ID | No | First open list | Default Trello list for new cards |
| PROJECTS_CSV_PATH | No | ./projects.csv | Path to projects CSV file |
| STATUS_MAPPING_PATH | No | ./status-mapping.json | Path to status mapping configuration |
| USER_MAPPING_PATH | No | ./user-mapping.json | Path to user mapping configuration |
| LEANTIME_RATE_LIMIT_MS | No | 5000 | Rate limit delay for Leantime API (milliseconds) |
| BACKUP_DIR | No | ./backups | Directory for backups |
| SYNC_STATE_FILE | No | ./.data/sync-state.json | Sync state file path |
| ADD_PREFIX_TO_LEANTIME | No | false | Add suffix to Leantime headlines |
| SYNC_INTERVAL_SECONDS | No | 0 | Sync interval (0 = single run) |
| SYNC_INTERVAL_MINUTES | No | 10 | Sync interval for server mode (minutes) |
| PORT | No | 3000 | Server port for web UI |
| SYNC_DRY_RUN | No | false | Enable dry-run mode |
*Trello credentials are optional in simulation mode.
Project CSV Format
The projects.csv file should have the following columns:
- CODE: Short project code (e.g., "CRM", "OPS", "XCR")
- NAME: Exact Leantime project name (case-sensitive matching)
- TRELLO_BOARD_ID (optional): Trello board ID for per-project boards
- LEANTIME_INSTANCE (optional): Leantime instance identifier (1, 2, 3, etc.). Defaults to "1"
- TRELLO_INSTANCE (optional): Trello instance identifier (1, 2, 3, etc.). Defaults to "1"
Example (single instance):
CODE,NAME,TRELLO_BOARD_ID
XCR,XCerdible,bUgDmx8G
CRM,CRM System Rollout,
OPS,Internal Ops Improvements,Example (multiple instances):
CODE,NAME,TRELLO_BOARD_ID,LEANTIME_INSTANCE,TRELLO_INSTANCE
XCR,XCerdible,bUgDmx8G,1,1
PROJ2,Project 2,boardId2,2,2
PROJ3,Project 3,boardId3,1,3Notes:
- Only the first 10 projects are processed
- If
TRELLO_BOARD_IDis provided in CSV, each project syncs to its own board - If
TRELLO_BOARD_IDis not in CSV, useTRELLO_BOARD_IDfrom.envfor all projects - Project name matching is case-insensitive but must match exactly after trimming
- Multi-instance support: Each instance pair (Leantime + Trello) has separate:
- API credentials (LEANTIME1_URL, TRELLO1_API_KEY, etc.)
- Sync state files (
.data/sync-state-leantime1-trello1.json) - Status and user mapping configs (optional:
status-mapping-1.json,user-mapping-1.json)
Usage
Build the project:
npm run buildRun a single sync (bidirectional):
npm run sync
# or
npm start
# or
npm run devRun in override mode (force Leantime → Trello):
npm run sync:override
# or
npm run dev -- --overrideOverride mode:
- Forces all Leantime tasks to Trello cards (one-way sync)
- Updates existing cards or creates new ones
- Ignores timestamps and sync state
- Useful for initial sync or when you want to overwrite Trello with Leantime data
Run in dry-run mode (test without changes):
npm run sync:dry
# or
npm run dev -- --dry-runRun in simulation mode (fetch and save data only):
npm run simulate
# or
npm run dev -- --simulate
# With custom output directory:
npm run dev -- --simulate --simulation-output ./my-dataSimulation mode:
- Fetches all data from Leantime (projects and tasks)
- Fetches data from Trello (if
TRELLO_BOARD_IDis provided) - Saves data to JSON files in
./simulation-data/(or custom directory) - Does NOT make any changes to either system
- Creates a summary file with statistics
Restore a project from backup:
npm run dev -- --restore-project CRM --restore-folder ./backups/removed-projects/CRMRun as continuous sync server (with web UI):
# Development mode (uses ts-node, no build needed)
npm run server
# Production mode (uses compiled JS, faster, requires build first)
npm run build
npm run server:prod
# Or via CLI flag
npm run dev -- --serverDifference between server and server:prod:
npm run server: Runs TypeScript directly usingts-node(development mode, slower startup, no build needed)npm run server:prod: Runs compiled JavaScript fromdist/(production mode, faster startup, requiresnpm run buildfirst)
The server mode provides:
- Web UI: Open
http://localhost:3000(or customPORTenv var) in your browser - Play/Pause: Control sync execution
- Force Sync: Manually trigger a sync immediately
- Status Display: Shows current status, last sync time, and errors
- Automatic Sync: Runs sync every X minutes (configurable via
SYNC_INTERVAL_MINUTESenv var, default: 10 minutes)
Environment Variables for Server Mode:
PORT: Server port (default:3000)SYNC_INTERVAL_MINUTES: Sync interval in minutes (default:10)
Example:
# Start server on port 3000, sync every 10 minutes
PORT=3000 SYNC_INTERVAL_MINUTES=10 npm run server
# Start server on port 8080, sync every 5 minutes
PORT=8080 SYNC_INTERVAL_MINUTES=5 npm run serverThe web UI provides:
- Real-time status updates (refreshes every 2 seconds)
- Play button to resume paused sync
- Pause button to pause sync
- Force Sync button to trigger immediate sync
- Last sync time display
- Error messages if sync fails
CLI Commands
All commands can be run with npm run <script> or npm run dev -- <flags>:
| Command | Description |
|---------|-------------|
| npm run build | Compile TypeScript to JavaScript |
| npm run dev | Run TypeScript directly (development) |
| npm start | Run compiled JavaScript |
| npm run sync | Run single bidirectional sync |
| npm run sync:dry | Run sync in dry-run mode (no changes) |
| npm run sync:override | Run override mode (force Leantime → Trello) |
| npm run simulate | Fetch and save data without changes |
| npm run server | Start continuous sync server with web UI |
| npm run server:prod | Start server (production, uses compiled JS) |
CLI Flags
--dry-runor--dry: Enable dry-run mode--override: Enable override mode (force Leantime → Trello)--simulateor--simulation: Enable simulation mode--simulation-output <dir>: Custom output directory for simulation--restore-project <code>: Restore a project from backup--restore-folder <path>: Backup folder path for restore
How It Works
Sync Process
- Project Matching: Matches Leantime projects to CSV entries by name (case-insensitive)
- Status Mapping: Fetches Leantime statuses and creates/uses Trello lists
- Milestone Mapping: Fetches Leantime milestones and creates/uses Trello labels
- User Mapping: Matches Leantime users to Trello board members (by email/username)
- Task Prefixing: Adds
#CODE-<task-id>suffix to task names (at the end, e.g., "Task Name #XCR-123") - HTML Conversion: Converts Leantime HTML descriptions to Markdown for Trello
- Sync Logic:
- Normal mode: Bidirectional sync based on last modified timestamps
- Override mode: Force all Leantime tasks → Trello cards (one-way)
- New Leantime tasks → Create Trello cards with suffix
- New Trello cards → Create Leantime tasks (normal mode only)
- Updated items sync based on last modified timestamp (normal mode)
- Cleanup: Cards with project codes not in CSV are backed up and archived
- Backup: Full snapshots saved to
BACKUP_DIR, removed projects saved toBACKUP_DIR/removed-projects/
Status Synchronization
- Fetches status configuration from Leantime API
- Uses status mapping configuration to map Leantime status names to Trello list names
- Creates Trello lists for each mapped status (or uses existing lists with matching names)
- Moves cards to the correct list based on task status
- Status 100 (Done) → Card is closed in Trello
Status Mapping
You can configure custom mappings between Leantime status names and Trello list names using status-mapping.json:
{
"statusMappings": {
"New": "To Do",
"In Progress": "Doing",
"Review": "Review",
"Done": "Done",
"Blocked": "Blocked"
},
"statusIdMappings": {
"1": "To Do",
"2": "Doing",
"3": "Review",
"4": "Done",
"5": "Blocked"
},
"defaultMapping": "To Do"
}- statusMappings: Maps Leantime status names (keys) to Trello list names (values)
- statusIdMappings: Maps Leantime status IDs (keys as strings) to Trello list names (values). Use this when the status API doesn't return data or you want direct ID mapping.
- defaultMapping: Default Trello list name if no mapping is found for a status
Note: If the status API doesn't return data, the system will use statusIdMappings to map status IDs directly. Check the console logs to see what status IDs your tasks have, then add them to statusIdMappings.
If no mapping file is provided, Leantime status names are used directly as Trello list names.
Milestone Labels
- Fetches milestones from Leantime
- Creates Trello labels for each milestone (with colors)
- Assigns labels to cards based on task milestone
User Assignments
- Fetches users from Leantime
- Matches users to Trello board members by email or username
- Assigns Trello members to cards based on Leantime user assignments
HTML to Markdown Conversion
- Strips ProseMirror and other rich text editor data attributes
- Converts HTML tags to Markdown (headings, lists, links, bold, italic, etc.)
- Extracts plain text from nested HTML structures
- Cleans up whitespace and formatting
Project Structure
.
├── src/
│ ├── index.ts # Main entry point
│ ├── sync-service.ts # Sync logic
│ ├── leantime-client.ts # Leantime API client
│ ├── trello-client.ts # Trello API client
│ ├── backup-service.ts # Backup management
│ ├── project-config.ts # CSV loader
│ └── types.ts # TypeScript types
├── projects.csv # Project configuration (not in git)
├── projects.csv.example # Example project configuration
├── .env.example # Example environment variables
├── package.json
├── tsconfig.json
└── README.mdDevelopment
Type checking:
npx tsc --noEmitRun in development mode:
npm run devBuild for production:
npm run build
npm startNotes
- Project matching is case-insensitive but must match exactly after trimming
- Trello cards are identified by the
#CODE-<number>suffix pattern (at the end of the name) - Removed projects are archived (closed) in Trello, not deleted
- All sync operations are logged to console
- Backup files are JSON format with timestamps
- Rate limiting: 3 seconds between Leantime API calls to avoid 429 errors
- HTML conversion handles ProseMirror, TinyMCE, and other rich text editor formats
Troubleshooting
Cards not syncing
- Check that project names in CSV exactly match Leantime project names
- Verify API credentials are correct
- Check console logs for errors
HTML not converting properly
- The converter handles most HTML formats, but complex nested structures may need manual cleanup
- Check the Trello card description to see the converted Markdown
Status lists not created
- Ensure the Leantime API returns status configuration
- Check console logs for status fetching errors
- Lists are created automatically on first sync
Users not matching
- Ensure Trello board members have email addresses set
- Check that Leantime users have matching emails or usernames
- User matching is case-insensitive
License
MIT
