友田 陽大
← ブログ一覧に戻る

レガシー産業DXにおける技術選定の決定版フレームワーク:木材流通業界の実例から

電話・FAX・Excelが主流のレガシー産業で、どのようにDXを実現するか。TypeScript、Python、Golang、AWS Terraformの技術選定から、実装、運用まで、木材流通業界での成功事例を基に実践的なフレームワークを公開します。

2025/1/86分友田 陽大
レガシー産業DX
技術選定
業界DX
デジタル変革
TypeScript
Python
Golang
AWS

レガシー産業DXにおける技術選定の決定版フレームワーク:木材流通業界の実例から

はじめに:なぜレガシー産業DXは難しいのか

製造業、建設業、物流業、農林水産業——これらの「レガシー産業」は、依然として電話、FAX、Excelでの業務が主流です。デジタル化の恩恵を受けられず、非効率な業務フロー、情報の属人化、人材不足に悩んでいます。

私はこの2年間、木材流通業界という「超レガシー産業」のDXに挑戦し、経済産業大臣賞を受賞するプロダクトを開発しました。本記事では、その経験から導き出した**「レガシー産業DXにおける技術選定の決定版フレームワーク」**を公開します。

特に、「どの技術を選ぶべきか」 という技術選定の意思決定に焦点を当て、実践的な指針を提供します。


フレームワーク概要:5つの評価軸

レガシー産業DXの技術選定では、以下の5つの評価軸で技術を選定します。

評価軸重要度説明
業界適合性★★★★★業界特有の複雑さ(商流、ユーザー属性、業務フロー)に対応できるか
非エンジニア対応★★★★☆現場の非エンジニアが使いこなせるか(UI/UX、マニュアル)
段階的導入★★★★☆既存業務フローと併存しながら、段階的に移行できるか
長期保守性★★★★★10年以上の長期運用に耐えられるか(技術的負債、属人化リスク)
コスト最適化★★★☆☆初期コスト、ランニングコストが適切か

ケーススタディ:木材流通業界DXの技術選定

業界の特徴:8種類のステークホルダーと複雑な商流

木材流通業界には、以下の8種類のステークホルダーが存在します。

林業 → 市場 → 製材所 → プレカット → 工務店
                ↓
            メーカー → 問屋 → その他

各ステークホルダーで以下が異なります:

  • 実行可能な機能(発注、在庫管理、見積作成)
  • 閲覧可能な情報(自社の在庫のみ、市場の全在庫、取引先の在庫)
  • 価格設定権限(市場価格、卸価格、小売価格)

技術選定の決定プロセス

軸1: 業界適合性 - AWS Cognito + カスタムロジック

要件:

  • 8種類のユーザー属性ごとの認証・認可
  • 各属性で異なる権限管理

候補技術の比較:

技術メリットデメリット評価
Firebase Auth簡単、無料枠大カスタム属性の柔軟性低い×
Auth0柔軟性高いコスト高(MAU課金)
AWS CognitoAWS統合、カスタム属性学習コスト
自前実装完全カスタマイズセキュリティリスク、工数大×

決定: AWS Cognito

理由:

// AWS Cognitoのカスタム属性で8種類のユーザー属性を管理
interface UserAttributes {
  'custom:user_type': 'lumber_mill' | 'market' | 'manufacturer' | 'precut' | 'builder' | 'wholesaler' | 'other';
  'custom:company_id': string;
  'custom:permissions': string; // "create_order,view_inventory,manage_users"
}

// 権限チェック関数
const hasPermission = (user: UserAttributes, permission: string): boolean => {
  const permissions = user['custom:permissions'].split(',');
  return permissions.includes(permission);
};

軸2: フロントエンド - React + TypeScript + Vite

要件:

  • 複雑なユーザー属性ごとのUI制御
  • 大量のデータ操作(在庫一覧、発注履歴)
  • 高速なレスポンス

候補技術の比較:

技術メリットデメリット評価
jQuery学習コスト低複雑なUI管理困難×
Vue.jsシンプル、学習容易大規模アプリに不向き
React + TypeScript型安全、エコシステム学習コスト
Next.jsSSR/SSG最適化オーバースペック(SPA向き)

決定: React + TypeScript + Vite

理由:

// TypeScriptによる型安全なユーザー属性管理
type UserType = 'lumber_mill' | 'market' | 'manufacturer';

interface User {
  id: string;
  userType: UserType;
  companyId: string;
  permissions: Set<Permission>;
}

// ユーザー属性ごとの条件付きレンダリング
const Dashboard: React.FC<{ user: User }> = ({ user }) => {
  return (
    <div>
      {user.permissions.has('create_order') && <CreateOrderButton />}
      {user.permissions.has('view_inventory') && <InventoryList />}
      {user.userType === 'market' && <MarketPriceChart />}
    </div>
  );
};

Tanstack Query(React Query)の導入:

import { useQuery } from '@tanstack/react-query';

const useInventory = (companyId: string) => {
  return useQuery({
    queryKey: ['inventory', companyId],
    queryFn: () => fetchInventory(companyId),
    staleTime: 5 * 60 * 1000, // 5分間キャッシュ
    refetchOnWindowFocus: true,
  });
};

// コンポーネントでの使用
const InventoryList: React.FC = () => {
  const { data, isLoading, error } = useInventory(user.companyId);

  if (isLoading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return <Table data={data} />;
};

メリット:

  • APIキャッシュの効率化(無駄なリクエスト削減)
  • データフェッチの責務分離(コンポーネントとロジックの分離)

軸3: バックエンド - Python (Flask + SQLAlchemy)

要件:

  • PDF/Excelの重いバッチ処理(並列処理)
  • 複雑なビジネスロジック(価格計算、在庫管理)
  • 既存ExcelデータのDB化

候補技術の比較:

技術メリットデメリット評価
Node.js (Express)TypeScript統一、軽量重い処理に不向き
Python (Flask)データ処理、並列処理パフォーマンス(GIL)
Golang (Gin)高速、並行処理エコシステム小
Java (Spring Boot)エンタープライズ実績重い、学習コスト×

決定: Python (Flask + SQLAlchemy)

理由:

# PDF生成(ReportLab)
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4

def generate_invoice_pdf(order):
    """請求書PDF生成"""
    pdf = canvas.Canvas(f"invoices/{order.id}.pdf", pagesize=A4)
    pdf.drawString(100, 750, f"請求書番号: {order.invoice_number}")
    pdf.drawString(100, 730, f"顧客: {order.customer_name}")
    # ... 詳細な請求書生成ロジック
    pdf.save()

# Excel読み込み・DB化(pandas)
import pandas as pd

def import_excel_to_db(file_path):
    """既存ExcelをDBに一括インポート"""
    df = pd.read_excel(file_path)

    # データクレンジング
    df = df.dropna(subset=['product_id', 'price'])
    df['price'] = df['price'].astype(float)

    # DB一括挿入
    for _, row in df.iterrows():
        product = Product(
            product_id=row['product_id'],
            name=row['product_name'],
            price=row['price'],
            stock=row['stock']
        )
        db.session.add(product)
    db.session.commit()

メリット:

  • pandas: Excel操作が容易、データクレンジングが強力
  • ReportLab: PDF生成が柔軟
  • asyncio: 並列処理で重い処理を高速化

軸4: インフラ - AWS (ECS on Fargate + Terraform)

要件:

  • スケーラブルなSaaS基盤
  • 再現性の高いインフラ(IaC)
  • コンテナベースのマイクロサービス

候補技術の比較:

技術メリットデメリット評価
AWS EC2自由度高スケール手動、管理コスト×
AWS ECS on Fargateサーバーレス、自動スケール若干高コスト
Kubernetes (EKS)柔軟性最高複雑、オーバースペック
Heroku簡単コスト高、柔軟性低×

決定: AWS ECS on Fargate + Terraform

Terraformによるインフラコード化:

# ECS Cluster
resource "aws_ecs_cluster" "main" {
  name = "lumber-saas-cluster"

  setting {
    name  = "containerInsights"
    value = "enabled"
  }
}

# ECS Task Definition
resource "aws_ecs_task_definition" "app" {
  family                   = "lumber-saas-app"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "1024"
  memory                   = "2048"

  container_definitions = jsonencode([{
    name  = "app"
    image = "${var.ecr_repository_url}:latest"
    portMappings = [{
      containerPort = 8080
      protocol      = "tcp"
    }]
    environment = [
      { name = "DATABASE_URL", value = var.database_url },
      { name = "COGNITO_USER_POOL_ID", value = aws_cognito_user_pool.main.id }
    ]
  }])
}

# Auto Scaling
resource "aws_appautoscaling_target" "ecs_target" {
  max_capacity       = 10
  min_capacity       = 2
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.app.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "ecs_policy" {
  name               = "scale-up"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs_target.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs_target.service_namespace

  target_tracking_scaling_policy_configuration {
    target_value = 70.0
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
  }
}

メリット:

  • Fargate: サーバー管理不要、自動スケール
  • Terraform: インフラ全体をコード化、再現性100%
  • Auto Scaling: CPU使用率に応じて自動スケール(コスト最適化)

非エンジニア対応:UI/UXの徹底的な簡略化

課題:現場の非エンジニアが使えるか

レガシー産業の現場では、ITリテラシーが低いユーザーが多数います。「Excelは使えるが、Webシステムは使えない」というユーザーに対応する必要があります。

実装:直感的なUI設計

1. Excelライクな操作性

// ag-Grid を使用したExcelライクなテーブル
import { AgGridReact } from 'ag-grid-react';

const InventoryTable: React.FC = () => {
  const columnDefs = [
    { field: 'product_name', headerName: '商品名', editable: true },
    { field: 'stock', headerName: '在庫数', editable: true },
    { field: 'price', headerName: '単価', editable: true },
  ];

  const onCellValueChanged = (params: any) => {
    // セル編集時、自動保存
    updateInventory(params.data);
  };

  return (
    <AgGridReact
      columnDefs={columnDefs}
      rowData={inventoryData}
      onCellValueChanged={onCellValueChanged}
      enableRangeSelection={true} // Excel風の範囲選択
    />
  );
};

2. わかりやすいエラーメッセージ

// ❌ 悪い例
throw new Error('ValidationError: field "price" must be positive');

// ✅ 良い例
throw new Error('価格は0円以上で入力してください。現在の入力値: -1000円');

段階的導入:既存業務との併存

課題:「いきなり全面移行」は失敗する

レガシー産業では、「いきなりExcelを廃止してWebシステムに移行」すると、現場が混乱し、失敗します。

戦略:3段階導入

Phase 1(1-3ヶ月): 情報共有のみ(Excel併用OK)
  ↓
Phase 2(4-6ヶ月): 発注機能の一部移行(Excel併用)
  ↓
Phase 3(7-12ヶ月): 全面移行(Excel廃止)

実装例:

# Phase 1: Excel アップロード機能
@app.route('/api/inventory/upload', methods=['POST'])
def upload_excel():
    """既存Excelをアップロードして、DBに同期"""
    file = request.files['file']
    df = pd.read_excel(file)

    # DB同期
    sync_inventory_from_dataframe(df)

    return jsonify({'message': 'Excelをアップロードしました。Web画面でも確認できます。'})

# Phase 2: Excelダウンロード機能(Excel併用)
@app.route('/api/inventory/download', methods=['GET'])
def download_excel():
    """Web上のデータをExcelでダウンロード"""
    inventory = Inventory.query.all()
    df = pd.DataFrame([inv.to_dict() for inv in inventory])

    output = io.BytesIO()
    df.to_excel(output, index=False)
    output.seek(0)

    return send_file(output, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                     as_attachment=True, download_name='inventory.xlsx')

まとめ:レガシー産業DX技術選定の5原則

  1. 業界適合性を最優先せよ - 汎用的なソリューションではなく、業界特有の複雑さに対応できる技術を選ぶ
  2. 非エンジニア対応を徹底せよ - ITリテラシーが低いユーザーでも使える、直感的なUI/UXを設計
  3. 段階的導入を計画せよ - いきなり全面移行せず、既存業務と併存しながら段階的に移行
  4. 長期保守性を確保せよ - 10年以上の長期運用に耐えられる、技術的負債を生まない設計
  5. IaCで再現性を担保せよ - インフラをコード化し、災害復旧やスケールアウトに対応

あなたのレガシー産業DXも実現可能です

製造業、建設業、物流業、農林水産業——あらゆるレガシー産業のDXをサポートします。要件定義から設計、実装、インフラ構築まで、ワンストップで対応可能です。

無料技術相談(30分) を実施していますので、お気軽にご連絡ください。

お問い合わせはこちら

同様の課題はありませんか?

あなたのビジネス課題も、最新の技術で解決できるかもしれません。
まずは30分、無料技術相談で状況をお聞かせください。

無料技術相談を予約する

※ プロジェクト単位(請負)・技術顧問、どちらも対応可能です