Back to Platform

Huly Export Service

services/export/pod-export/README.md

0.7.41311.3 KB
Original Source

Huly Export Service

The Export Service provides asynchronous data export functionality for Huly workspaces. It allows workspace owners and administrators to export documents and their associated data in multiple formats (JSON, CSV, Unified).

Overview

The Export Service is a standalone microservice that:

  • Exports workspace data asynchronously via REST API
  • Exports documents from one workspace to another workspace
  • Converts Huly documents to standardized formats
  • Handles complex document relationships (references, collections, attachments)
  • Packages exports as ZIP archives and saves them to the workspace Drive
  • Sends notifications upon completion or failure

Architecture

Components

  • Server (server.ts): Express REST API server with authentication
  • Exporter (exporter.ts): Main export orchestration logic for file exports
  • Workspace Exporter (workspace/): Cross-workspace document export functionality
    • workspace-exporter.ts: Main orchestrator for workspace-to-workspace exports
    • document-exporter.ts: Individual document export logic
    • attachment-exporter.ts: Attachment and blob migration
    • relation-exporter.ts: Forward and inverse relation handling
    • space-exporter.ts: Space migration and reuse
    • data-mapper.ts: Data transformation and field mapping
  • Converter (converter.ts): Document conversion and type resolution
  • Serializers: Format-specific output writers
    • json/json-serializer.ts: JSON format output
    • csv/csv-serializer.ts: CSV format output
  • Types (types.ts): Unified document model definitions

Export Flow

Client Request → Authentication → Export Job Created → Async Processing
                                                      ↓
                        Notification ← Save to Drive ← ZIP Archive ← Serialize ← Convert Docs

API Endpoints

POST /exportAsync

Initiates an asynchronous export job.

Authentication: Required (Bearer token or Cookie)

Query Parameters:

  • format (required): Export format - json, csv, or unified

Request Body:

json
{
  "_class": "task:class:Issue",
  "query": {
    "status": "active"
  },
  "attributesOnly": false
}

Parameters:

  • _class (required): Ref to the document class to export (e.g., task:class:Issue)
  • query (optional): MongoDB-style query to filter documents
  • attributesOnly (boolean): If true, excludes attachments and collections

Response:

json
{
  "message": "Export started"
}

Authorization:

  • Requires workspace Owner role or system admin privileges
  • Read-only tokens are rejected

Process:

  1. Job is queued and response is returned immediately
  2. Documents are fetched, converted, and serialized
  3. Output is packaged as a ZIP archive
  4. Archive is uploaded to workspace Drive
  5. User receives notification with download link

POST /export-to-workspace

Exports documents from the current workspace to another workspace. This endpoint copies documents, their attachments, and related data to a target workspace while preserving relationships and remapping IDs.

Authentication: Required (Bearer token or Cookie)

Request Body:

json
{
  "targetWorkspace": "target-workspace-uuid",
  "_class": "documents:class:ControlledDocument",
  "query": {
    "_id": { "$in": ["doc-id-1", "doc-id-2"] }
  },
  "conflictStrategy": "duplicate",
  "includeAttachments": true,
  "relations": [
    {
      "field": "references",
      "class": "documents:class:ControlledDocument",
      "direction": "forward"
    }
  ],
  "fieldMappers": {
    "documents:class:ControlledDocument": {
      "author": "$currentUser",
      "owner": "$currentUser",
      "state": "draft",
      "code": "$ensureUnique",
      "seqNumber": "$ensureUnique"
    }
  },
  "objectId": "doc-id-1",
  "objectSpace": "space-id"
}

Parameters:

  • targetWorkspace (required): UUID of the target workspace to export to
  • _class (required): Ref to the document class to export (e.g., documents:class:ControlledDocument)
  • query (optional): MongoDB-style query to filter documents. If not provided and specific documents are selected, uses _id: { $in: [...] }
  • conflictStrategy (optional): How to handle existing documents in target workspace
    • "duplicate" (default): Create new documents with new IDs
    • "skip": Skip documents that already exist (based on matching criteria)
  • includeAttachments (optional, default: true): Whether to copy attachment blob data
  • relations (optional): Array of relation definitions to export
    • field: Field name containing the relation
    • class: Class of related documents
    • direction: "forward" (dependencies) or "inverse" (references)
  • fieldMappers (optional): Field value overrides per document class. Supports special values:
    • $currentUser: Replaced with current account's employee ID
      • Example: { "author": "$currentUser" } sets author to current user
    • $ensureUnique: Ensures the field value is unique by checking the database and modifying if needed
      • For strings: appends a suffix like "-1", "-2", etc.
      • For numbers: increments until unique
      • Example: { "code": "$ensureUnique", "seqNumber": "$ensureUnique" } ensures unique code and seqNumber
  • objectId (optional): ID of the primary document for notification context
  • objectSpace (optional): Space of the primary document for notification context

Response:

json
{
  "message": "Export started"
}

Authorization:

  • Requires Owner role in both source and target workspaces (or system admin privileges)
  • Read-only tokens are rejected
  • Target workspace must be accessible to the user

Process:

  1. Validates user permissions for both source and target workspaces
  2. Response is returned immediately (async processing)
  3. Documents are fetched from source workspace
  4. Forward relations (dependencies) are exported first
  5. Main documents are exported with ID remapping
  6. Inverse relations (references) are exported
  7. Attachments and blob data are copied to target workspace
  8. Spaces are created or reused in target workspace
  9. User receives notification with export results

Example Use Cases:

  • Copying controlled documents to a new workspace
  • Migrating project data between workspaces
  • Creating workspace templates
  • Sharing documents with another team

Error Handling:

  • Individual document failures don't stop the entire export
  • Errors are collected and reported in the notification
  • Failed documents are logged with specific error messages

Export Formats

JSON Format

  • Human-readable nested JSON structure
  • Preserves document relationships
  • Includes metadata and attachments
  • File structure: {spaceName}/{className}/{docId}.json

CSV Format

  • Flat tabular format
  • One row per document
  • Nested objects converted to JSON strings
  • File structure: {spaceName}/{className}.csv

Unified Format

  • Standardized document structure
  • Generic type system
  • Suitable for data migration/integration
  • File structure: {spaceName}/{className}/{docId}.json

Document Conversion

The converter transforms Huly documents into a unified format that:

Handles Special Types

  • References (RefTo): Resolved to readable format (e.g., person names)
  • Collections: Nested child documents included
  • Timestamps: Formatted as ISO 8601 strings
  • Markdown: Preserved with field markers
  • Collaborative Docs: Fetched from storage and included
  • Attachments: Binary data handled separately

Field Categories

Documents are analyzed and fields are categorized:

  • markdownFields: Fields containing markdown content
  • collabFields: Fields referencing collaborative documents
  • refFields: Fields containing document references
  • collectionFields: Fields containing nested collections
  • attachments: Associated attachment metadata

Example Unified Document

json
{
  "_class": "task:class:Issue",
  "_id": "issue-123",
  "space": "project-1",
  "data": {
    "title": "Fix bug",
    "description": "...",
    "assignee": "John Doe",
    "status": "In Progress"
  },
  "markdownFields": ["description"],
  "refFields": ["assignee", "status"],
  "collectionFields": ["comments"],
  "attachments": [
    {
      "id": "attach-1",
      "name": "screenshot.png",
      "size": 45678,
      "contentType": "image/png"
    }
  ]
}

Configuration

Environment Variables

Required:

  • PORT: Service port (default: 4006)
  • SECRET: JWT token secret
  • ACCOUNTS_URL: URL to accounts service
  • SERVICE_ID: Service identifier

Storage configuration (via storageConfigFromEnv):

  • STORAGE_PROVIDER: Storage backend (minio, s3, etc.)
  • STORAGE_ENDPOINT: Storage endpoint URL
  • STORAGE_ACCESS_KEY: Storage access credentials
  • STORAGE_SECRET_KEY: Storage secret credentials

Docker Deployment

bash
docker build -t hardcoreeng/export .
docker run -p 4006:4006 \
  -e SECRET=your-secret \
  -e ACCOUNTS_URL=http://accounts:3000 \
  -e SERVICE_ID=export-service \
  -e STORAGE_PROVIDER=minio \
  -e STORAGE_ENDPOINT=http://minio:9000 \
  hardcoreeng/export

Development

Build

bash
rush build --to @hcengineering/pod-export

Run Locally

bash
cd services/export/pod-export
ACCOUNTS_URL="http://127.0.0.1:3000" SECRET="secret" DB_URL=postgresql://[email protected]:26257/defaultdb?sslmode=disable SERVICE_ID="export" STORAGE_CONFIG="datalake|http://huly.local:4030" rushx run-local

Testing

bash
rushx test

Output Structure

export-{workspace}-{class}-{format}-{timestamp}.zip
├── Space Name 1/
│   ├── ClassName/
│   │   ├── doc-1.json
│   │   ├── doc-2.json
│   │   └── attachments/
│   │       ├── file1.pdf
│   │       └── file2.png
├── Space Name 2/
│   └── ClassName/
│       └── docs.csv

Notifications

Users receive in-app notifications:

Success:

Export completed successfully
[Link to download from Drive]

Failure:

Export failed: {error message}

Security

  • JWT token validation
  • Workspace access verification
  • Role-based authorization (Owner role required for both source and target workspaces)
  • Target workspace permission validation
  • Secure file storage
  • Temporary directory cleanup
  • Read-only token rejection

Limitations

  • Maximum documents per export: Limited by available memory
  • Attachment size: Limited by storage configuration
  • Export timeout: 30 minutes (configurable)
  • Concurrent exports per workspace: 1

Troubleshooting

Common Issues

401 Unauthorized

  • Check token validity
  • Verify workspace access
  • Ensure user has Owner role

400 Missing required parameters

  • Verify _class is provided
  • Check format query parameter

403 Forbidden

  • Read-only tokens cannot export
  • Upgrade to full access token
  • Verify Owner role in target workspace
  • Check that target workspace is accessible

404 Target workspace not found

  • Verify target workspace UUID is correct
  • Ensure target workspace exists and is accessible
  • Check user has access to target workspace

Export fails silently

  • Check service logs
  • Verify storage connectivity
  • Ensure sufficient disk space
  • Verify both source and target workspace connections are working

Logs

bash
docker logs -f export-service

License

Eclipse Public License 2.0

Support

For issues and questions, see the main Huly Platform repository.