インポート & エクスポート

プロジェクトをバックアップや移行のためにポータブルな .mpz ファイルとしてエクスポートし、他のテナントにインポートします。また、プロジェクトのサムネイル画像を管理します。

プロジェクトパッケージ (.mpz)

.mpz 形式は mindzie Package Zip で、以下を含みます:

  • プロジェクト設定とメタデータ
  • すべてのデータセットとその構成
  • 調査およびノートブック
  • ダッシュボードとパネル
  • Blob ストレージファイル(イベントログ、添付ファイル)

プロジェクトのエクスポート

GET /api/{tenantId}/project/{projectId}/download

プロジェクトを .mpz (mindzie Package Zip) ファイルとしてエクスポートします。

パスパラメータ

パラメータ 必須 説明
tenantId GUID はい テナント識別子
projectId GUID はい エクスポートするプロジェクト

レスポンス

以下の内容でバイナリファイルのダウンロードを返します:

  • Content-Type: application/octet-stream
  • ファイル名: {projectName}.mpz

ユースケース

  • バックアップ: 重要なプロジェクトの定期バックアップ作成
  • 移行: プロジェクトをテナント間やインスタンス間で移動
  • テンプレート: 構成済みプロジェクトを新規分析のテンプレートとしてエクスポート

プロジェクトのインポート

POST /api/{tenantId}/project/import

.mpz ファイルからプロジェクトをインポートします。

パスパラメータ

パラメータ 必須 説明
tenantId GUID はい 対象のテナント

リクエスト

  • Content-Type: multipart/form-data
  • ファイルパラメータ: file (.mpz ファイル)

制約

制約
最大ファイルサイズ 1 GB
ファイル拡張子 .mpz であること
ファイル形式 有効な mindzie プロジェクトエクスポート形式であること

レスポンス (200 OK)

{
  "success": true,
  "projectId": "99999999-9999-9999-9999-999999999999",
  "projectName": "Imported Project",
  "datasetsImported": 2,
  "investigationsImported": 3,
  "dashboardsImported": 1,
  "message": "Project imported successfully"
}

レスポンスフィールド

フィールド 説明
success boolean インポートが成功したかどうか
projectId GUID 新規作成されたプロジェクトのID
projectName string インポートされたプロジェクト名
datasetsImported integer インポートされたデータセット数
investigationsImported integer インポートされた調査数
dashboardsImported integer インポートされたダッシュボード数
message string 人間が読めるステータスメッセージ

エラーレスポンス

Bad Request (400):

{
  "success": false,
  "errorMessage": "Invalid file format. Expected .mpz file."
}

サムネイル管理

プロジェクト一覧に表示されるプロジェクトサムネイルは視覚的な識別を助けます。

サムネイル取得

GET /api/{tenantId}/project/{projectId}/thumbnail

プロジェクトのサムネイル画像を取得します。

レスポンス (200 OK)

{
  "projectId": "87654321-4321-4321-4321-210987654321",
  "hasThumbnail": true,
  "base64Image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
}

レスポンスフィールド

フィールド 説明
projectId GUID プロジェクト識別子
hasThumbnail boolean サムネイルが存在するか
base64Image string data URI プレフィックス付きのBase64エンコード画像

サムネイル更新

POST /api/{tenantId}/project/{projectId}/thumbnail

プロジェクトのサムネイル画像を更新します。

リクエストボディ

{
  "base64Image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
}

注意: Base64文字列には data URI プレフィックス(例: data:image/jpeg;base64, または data:image/png;base64,)を含めてください。

レスポンス (200 OK)

{
  "message": "Thumbnail updated successfully"
}

サムネイル削除

DELETE /api/{tenantId}/project/{projectId}/thumbnail

プロジェクトのサムネイル画像を削除します。

レスポンス (200 OK)

{
  "message": "Thumbnail removed successfully"
}

実装例

cURL

# プロジェクトをファイルにエクスポート
curl -X GET "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/download" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  --output project_backup.mpz

# ファイルからプロジェクトをインポート
curl -X POST "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/import" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -F "file=@project_backup.mpz"

# サムネイル取得
curl -X GET "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/thumbnail" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# サムネイル更新(base64ファイルから)
curl -X POST "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/thumbnail" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"base64Image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."}'

# サムネイル削除
curl -X DELETE "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/thumbnail" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Python

import requests
import base64
from pathlib import Path

TENANT_ID = '12345678-1234-1234-1234-123456789012'
BASE_URL = 'https://your-mindzie-instance.com'

class ProjectExportManager:
    def __init__(self, token):
        self.headers = {
            'Authorization': f'Bearer {token}'
        }

    def export_project(self, project_id, output_path):
        """プロジェクトを .mpz ファイルとしてエクスポート。"""
        url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/download'
        response = requests.get(url, headers=self.headers, stream=True)
        response.raise_for_status()

        with open(output_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                f.write(chunk)

        print(f"{output_path} にエクスポートしました")
        return output_path

    def import_project(self, file_path):
        """.mpz ファイルからプロジェクトをインポート。"""
        url = f'{BASE_URL}/api/{TENANT_ID}/project/import'

        with open(file_path, 'rb') as f:
            files = {'file': (Path(file_path).name, f, 'application/octet-stream')}
            response = requests.post(url, headers=self.headers, files=files)

        response.raise_for_status()
        result = response.json()

        print(f"インポートしました: {result['projectName']}")
        print(f"  データセット: {result['datasetsImported']}")
        print(f"  調査: {result['investigationsImported']}")
        print(f"  ダッシュボード: {result['dashboardsImported']}")

        return result

    def get_thumbnail(self, project_id):
        """プロジェクトのサムネイルを base64 形式で取得。"""
        url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/thumbnail'
        response = requests.get(url, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def set_thumbnail(self, project_id, image_path):
        """画像ファイルからプロジェクトのサムネイルを設定。"""
        url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/thumbnail'

        # 画像読み込みとエンコード
        with open(image_path, 'rb') as f:
            image_data = f.read()

        # MIMEタイプ判定
        ext = Path(image_path).suffix.lower()
        mime_type = 'image/jpeg' if ext in ['.jpg', '.jpeg'] else 'image/png'

        # Base64 データURI作成
        base64_data = base64.b64encode(image_data).decode('utf-8')
        data_uri = f'data:{mime_type};base64,{base64_data}'

        headers = {**self.headers, 'Content-Type': 'application/json'}
        response = requests.post(url, json={'base64Image': data_uri}, headers=headers)
        response.raise_for_status()

        print(f"プロジェクト {project_id} のサムネイルを更新しました")
        return response.json()

    def remove_thumbnail(self, project_id):
        """プロジェクトのサムネイルを削除。"""
        url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/thumbnail'
        response = requests.delete(url, headers=self.headers)
        response.raise_for_status()
        return response.json()

# 利用例
manager = ProjectExportManager('your-auth-token')
project_id = '87654321-4321-4321-4321-210987654321'

# バックアップ用にプロジェクトをエクスポート
manager.export_project(project_id, 'my_project_backup.mpz')

# 同一または別テナントにインポート
result = manager.import_project('my_project_backup.mpz')
new_project_id = result['projectId']

# サムネイルを設定
manager.set_thumbnail(project_id, 'project_thumbnail.png')

# サムネイルを取得
thumbnail = manager.get_thumbnail(project_id)
if thumbnail['hasThumbnail']:
    print("サムネイルが存在します")

JavaScript/Node.js

const fs = require('fs');
const path = require('path');
const FormData = require('form-data');

const TENANT_ID = '12345678-1234-1234-1234-123456789012';
const BASE_URL = 'https://your-mindzie-instance.com';

class ProjectExportManager {
  constructor(token) {
    this.headers = {
      'Authorization': `Bearer ${token}`
    };
  }

  async exportProject(projectId, outputPath) {
    const url = `${BASE_URL}/api/${TENANT_ID}/project/${projectId}/download`;
    const response = await fetch(url, { headers: this.headers });

    if (!response.ok) {
      throw new Error(`エクスポート失敗: ${response.status}`);
    }

    const buffer = await response.arrayBuffer();
    fs.writeFileSync(outputPath, Buffer.from(buffer));
    console.log(`${outputPath} にエクスポートしました`);
  }

  async importProject(filePath) {
    const url = `${BASE_URL}/api/${TENANT_ID}/project/import`;

    const formData = new FormData();
    formData.append('file', fs.createReadStream(filePath));

    const response = await fetch(url, {
      method: 'POST',
      headers: {
        ...this.headers,
        ...formData.getHeaders()
      },
      body: formData
    });

    if (!response.ok) {
      throw new Error(`インポート失敗: ${response.status}`);
    }

    const result = await response.json();
    console.log(`インポートしました: ${result.projectName}`);
    return result;
  }

  async setThumbnail(projectId, imagePath) {
    const url = `${BASE_URL}/api/${TENANT_ID}/project/${projectId}/thumbnail`;

    // 画像を読み込みエンコード
    const imageBuffer = fs.readFileSync(imagePath);
    const ext = path.extname(imagePath).toLowerCase();
    const mimeType = ext === '.png' ? 'image/png' : 'image/jpeg';
    const base64Data = imageBuffer.toString('base64');
    const dataUri = `data:${mimeType};base64,${base64Data}`;

    const response = await fetch(url, {
      method: 'POST',
      headers: {
        ...this.headers,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ base64Image: dataUri })
    });

    if (!response.ok) {
      throw new Error(`サムネイル更新失敗: ${response.status}`);
    }

    return await response.json();
  }
}

// 利用例
const manager = new ProjectExportManager('your-auth-token');

// エクスポートとインポート
await manager.exportProject('project-id', 'backup.mpz');
const imported = await manager.importProject('backup.mpz');

// サムネイルを設定
await manager.setThumbnail('project-id', 'thumbnail.png');

ベストプラクティス

  1. 定期的なバックアップ: 重要なプロジェクトの定期的なエクスポートをスケジューリングする
  2. バージョン命名: エクスポートファイル名に日付を含める(例: project_2024-01-15.mpz
  3. インポートのテスト: 本番環境前に非本番テナントでインポートをテストする
  4. サムネイルサイズ: 高速ロードのためサムネイルは100KB以下に抑える
  5. サムネイル形式: 写真は JPEG、透過グラフィックスは PNG を使用すること