mcpField
N
n8n-project-management

n8n-project-management

github.com/datadrivenconstruction生産性375112 回インストール1 週間前に更新
リポジトリ

n8n-project-management について

建設プロジェクトの管理者向けに、n8n でタスク管理と報告を自動化するシステムです。Telegram と Google Sheets を使って作業を配信し、進捗、写真、位置情報の報告を整理します。

主な機能

  1. 01Telegram による定時タスクリマインダー
  2. 02テキストと写真による状況報告の収集
  3. 03作業員の GPS 座標の記録
  4. 04タスクデータの Google Sheets 保存
  5. 05管理者向けダッシュボード表示

活用シーン

  1. 01作業班への日次タスク配信
  2. 02現場作業員からの進捗報告収集
  3. 03節目の写真と位置情報の収集
  4. 04共有ダッシュボードでのタスク状況確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction --skill n8n-project-management

インストール後、Claude Code で/n8n-project-managementを入力して読み込まれたか確認します。

同梱ファイルclaw.jsoninstructions.md

詳細

建設向け n8n プロジェクト管理システム

n8n の自動化、Telegram ボット、Google Sheets を使用して、建設プロジェクト向けの汎用タスク管理・レポートシステムを構築します。

ビジネスケース

課題:建設現場の管理者は、毎日 2~3 時間を次の作業に費やしています。

  • 職長や作業員へのタスクの割り当て
  • 電話やメッセージによる進捗報告の収集
  • 写真による記録の取りまとめ
  • タスクの完了状況の追跡

解決策:次の機能を備えた自動化システムです。

  • 予定時刻に Telegram でタスクのリマインダーを送信
  • 状況報告(テキスト+写真+GPS)を収集
  • すべてのデータを Google Sheets に自動保存
  • 管理者にリアルタイムの状況を提供

ROI:タスク管理にかかる事務作業時間を 70% 削減

ソースリポジトリ

https://github.com/datadrivenconstruction/Project-management-n8n-with-task-management-and-photo-reports

システムアーキテクチャ

┌──────────────────────────────────────────────────────────────────────┐
│                    PROJECT MANAGEMENT SYSTEM                          │
├──────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   MANAGER                          WORKER                            │
│   ┌─────────────┐                  ┌─────────────┐                   │
│   │ Google      │                  │ Telegram    │                   │
│   │ Sheets      │                  │ Bot         │                   │
│   │             │                  │             │                   │
│   │ • Tasks     │    n8n           │ • /start    │                   │
│   │ • Schedule  │◄──Workflow──────►│ • Tasks     │                   │
│   │ • Reports   │                  │ • Photos    │                   │
│   │ • Photos    │                  │ • GPS       │                   │
│   └─────────────┘                  └─────────────┘                   │
│         │                                │                           │
│         ▼                                ▼                           │
│   ┌─────────────┐                  ┌─────────────┐                   │
│   │ Dashboard   │                  │ Google      │                   │
│   │ View        │                  │ Drive       │                   │
│   │             │                  │ (Photos)    │                   │
│   └─────────────┘                  └─────────────┘                   │
│                                                                       │
└──────────────────────────────────────────────────────────────────────┘

導入ガイド

ステップ 1:Telegram ボットを作成する
# 1. Open @BotFather in Telegram
# 2. Send /newbot
# 3. Name: "YourProject Tasks Bot"
# 4. Username: "YourProjectTasks_bot"
# 5. Save the token: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz

# Test bot connection
import requests

BOT_TOKEN = "YOUR_BOT_TOKEN"
response = requests.get(f"https://api.telegram.org/bot{BOT_TOKEN}/getMe")
print(response.json())
# Expected: {"ok": true, "result": {"id": ..., "first_name": "YourProject Tasks Bot"}}
ステップ 2:Google Sheets を設定する

次のシートを含むスプレッドシートを作成します。

シート 1:タスク

列種類説明
Task_IDテキスト一意の識別子(TASK-001)
Projectテキストプロジェクト名
Objectテキスト建物/エリア
Sectionテキスト階/ゾーン
Taskテキストタスクの説明
Executorテキスト割り当てられた作業員の名前
Executor_ID数値Telegram ユーザー ID
Date日付期限(DD.MM.YYYY)
Send_Time時刻リマインダーの時刻
Priorityテキスト🔴高 / 🟡中 / 🟢低
Statusテキスト保留/送信済み/完了/一部完了
Responseテキスト作業員からの返信
Response_Time日時返信日時
Photo_LinkURLGoogle Drive のリンク
GPS_Lat数値緯度
GPS_Lon数値経度

シート 2:作業員

列種類説明
Nameテキスト作業員の氏名
Roleテキスト職長/作業員/請負業者
Telegram_ID数値/start から取得したユーザー ID
Phoneテキスト電話番号
Registered日時登録日時

シート 3:写真レポート

列種類説明
Report_IDテキスト一意の ID
Report_Typeテキスト日次/安全/品質
Executorテキスト提出する作業員
Date日付レポートの日付
Time時刻締め切り
Statusテキスト保留/提出済み
Photo_LinkURLDrive フォルダーのリンク
Commentテキスト作業員のコメント
ステップ 3:n8n ワークフローをインポートする
// Core workflow structure (simplified)
{
  "nodes": [
    {
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "parameters": {
        "updates": ["message", "callback_query"]
      }
    },
    {
      "name": "Route Messages",
      "type": "n8n-nodes-base.switch",
      "parameters": {
        "rules": [
          {"value": "/start"},
          {"value": "/status"},
          {"value": "/help"},
          {"value": "text_reply"},
          {"value": "photo"},
          {"value": "location"}
        ]
      }
    },
    {
      "name": "Check Tasks Schedule",
      "type": "n8n-nodes-base.cron",
      "parameters": {
        "cronExpression": "* * * * *"
      }
    },
    {
      "name": "Get Pending Tasks",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "readRows",
        "sheetName": "Tasks",
        "filters": {
          "Status": "Pending",
          "Send_Time": "now"
        }
      }
    },
    {
      "name": "Send Task Reminder",
      "type": "n8n-nodes-base.telegram",
      "parameters": {
        "operation": "sendMessage",
        "chatId": "={{$json.Executor_ID}}",
        "text": "📋 *Задача: {{$json.Task}}*\n📍 Объект: {{$json.Object}}\n⏰ Срок: {{$json.Date}}\n{{$json.Priority}}"
      }
    }
  ]
}
ステップ 4:Webhook を設定する
# Set Telegram webhook to n8n
curl -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" \
  -d "url=https://your-n8n-instance.com/webhook/telegram-project-manager"

# Verify webhook is set
curl "https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo"

作業員向けコマンド

登録:/start
User: /start

Bot: 👋 Добро пожаловать в систему управления задачами!

Пожалуйста, укажите ваше имя:

User: Иван Петров

Bot: Выберите вашу роль:
[Прораб] [Рабочий] [Субподрядчик]

User: [Прораб]

Bot: ✅ Регистрация завершена!
Имя: Иван Петров
Роль: Прораб
ID: 123456789

Вы будете получать задачи автоматически.
Используйте /help для справки.
タスクの受信
Bot: 📋 *ЗАДАЧА #TASK-047*
━━━━━━━━━━━━━━━━━━━━━
📍 Объект: ЖК Солнечный, Корпус 2
🏗 Секция: 5 этаж, кв. 51-55
📝 Задача: Монтаж электропроводки
⏰ Срок: 24.01.2026
🔴 Приоритет: Высокий
━━━━━━━━━━━━━━━━━━━━━

Ответьте на это сообщение для отчета:
• Текст: статус + комментарий
• Фото: прикрепите фото работ
• GPS: отправьте геолокацию
タスクへの返信
User: (reply to task message)
выполнено
Проводка смонтирована по всем квартирам, ждем приемку

Bot: ✅ Отчет принят!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
📊 Статус: Выполнено
💬 Комментарий: Проводка смонтирована...
⏰ Время: 24.01.2026 14:35
━━━━━━━━━━━━━━━━━━━━━
写真レポート
User: (sends photo as reply to task)
[Photo of completed electrical work]
Caption: Монтаж завершен, готово к проверке

Bot: 📷 Фото получено и сохранено!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
🔗 Фото: [Ссылка на Google Drive]
💬 Комментарий: Монтаж завершен...
⏰ Время: 24.01.2026 14:38
━━━━━━━━━━━━━━━━━━━━━
GPS の位置情報
User: (sends location)
📍 [Location: 55.7558, 37.6173]

Bot: 📍 Геолокация получена!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
🗺 Координаты: 55.7558, 37.6173
🔗 Карта: [Google Maps Link]
⏰ Время: 24.01.2026 14:40
━━━━━━━━━━━━━━━━━━━━━

管理者ダッシュボード

Google Sheets の表示
┌────────────────────────────────────────────────────────────────────────┐
│ TASK DASHBOARD                                          🔄 Auto-refresh │
├────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  TODAY'S SUMMARY                                                       │
│  ┌───────────┬───────────┬───────────┬───────────┐                    │
│  │ Total: 24 │ ✅ Done:15│ ⏳ Pending:7│ ⚠️ Late:2│                    │
│  └───────────┴───────────┴───────────┴───────────┘                    │
│                                                                         │
│  TASK LIST                                             Filter: [Today ▼]│
│  ┌──────────┬────────────┬──────────┬────────┬────────┬──────────────┐│
│  │ Task ID  │ Task       │ Worker   │ Status │ Photo  │ Response     ││
│  ├──────────┼────────────┼──────────┼────────┼────────┼──────────────┤│
│  │ TASK-047 │ Электрика  │ Петров   │ ✅     │ 📷 3   │ Выполнено    ││
│  │ TASK-048 │ Сантехника │ Иванов   │ ⏳     │ -      │ -            ││
│  │ TASK-049 │ Штукатурка │ Сидоров  │ ⚠️     │ 📷 1   │ Частично     ││
│  └──────────┴────────────┴──────────┴────────┴────────┴──────────────┘│
│                                                                         │
└────────────────────────────────────────────────────────────────────────┘

Python 連携

import gspread
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
from datetime import datetime, timedelta

class ProjectTaskManager:
    """Integration with n8n Project Management System"""

    def __init__(self, credentials_path: str, spreadsheet_id: str):
        scope = [
            'https://spreadsheets.google.com/feeds',
            'https://www.googleapis.com/auth/drive'
        ]
        creds = ServiceAccountCredentials.from_json_keyfile_name(
            credentials_path, scope
        )
        self.client = gspread.authorize(creds)
        self.spreadsheet = self.client.open_by_key(spreadsheet_id)

    def create_task(self, task: dict) -> str:
        """Create new task in system"""
        tasks_sheet = self.spreadsheet.worksheet('Tasks')

        # Generate task ID
        all_tasks = tasks_sheet.get_all_records()
        task_num = len(all_tasks) + 1
        task_id = f"TASK-{task_num:04d}"

        # Prepare row
        row = [
            task_id,
            task.get('project', ''),
            task.get('object', ''),
            task.get('section', ''),
            task.get('description', ''),
            task.get('executor_name', ''),
            task.get('executor_id', ''),
            task.get('date', datetime.now().strftime('%d.%m.%Y')),
            task.get('send_time', '09:00'),
            task.get('priority', '🟡Medium'),
            'Pending',  # Status
            '',  # Response
            '',  # Response_Time
            '',  # Photo_Link
            '',  # GPS_Lat
            ''   # GPS_Lon
        ]

        tasks_sheet.append_row(row)
        return task_id

    def create_bulk_tasks(self, tasks: list) -> list:
        """Create multiple tasks at once"""
        task_ids = []
        for task in tasks:
            task_id = self.create_task(task)
            task_ids.append(task_id)
        return task_ids

    def get_today_summary(self) -> dict:
        """Get summary of today's tasks"""
        tasks_sheet = self.spreadsheet.worksheet('Tasks')
        all_tasks = tasks_sheet.get_all_records()

        today = datetime.now().strftime('%d.%m.%Y')
        today_tasks = [t for t in all_tasks if t['Date'] == today]

        return {
            'total': len(today_tasks),
            'completed': len([t for t in today_tasks if t['Status'] == 'Completed']),
            'pending': len([t for t in today_tasks if t['Status'] == 'Pending']),
            'partial': len([t for t in today_tasks if t['Status'] == 'Partial']),
            'with_photos': len([t for t in today_tasks if t['Photo_Link']])
        }

    def get_worker_performance(self, worker_name: str, days: int = 30) -> dict:
        """Analyze worker performance over period"""
        tasks_sheet = self.spreadsheet.worksheet('Tasks')
        all_tasks = tasks_sheet.get_all_records()

        cutoff_date = datetime.now() - timedelta(days=days)

        worker_tasks = [
            t for t in all_tasks
            if t['Executor'] == worker_name
            and datetime.strptime(t['Date'], '%d.%m.%Y') >= cutoff_date
        ]

        if not worker_tasks:
            return {'error': 'No tasks found'}

        completed = len([t for t in worker_tasks if t['Status'] == 'Completed'])
        total = len(worker_tasks)

        return {
            'worker': worker_name,
            'period_days': days,
            'total_tasks': total,
            'completed': completed,
            'completion_rate': round(completed / total * 100, 1),
            'with_photos': len([t for t in worker_tasks if t['Photo_Link']]),
            'with_gps': len([t for t in worker_tasks if t['GPS_Lat']])
        }


# Usage Example
if __name__ == "__main__":
    manager = ProjectTaskManager(
        'credentials.json',
        'your-spreadsheet-id'
    )

    # Create tasks for the week
    weekly_tasks = [
        {
            'project': 'ЖК Солнечный',
            'object': 'Корпус 2',
            'section': '5 этаж',
            'description': 'Монтаж электропроводки кв. 51-55',
            'executor_name': 'Петров И.И.',
            'executor_id': '123456789',
            'date': '24.01.2026',
            'send_time': '08:00',
            'priority': '🔴High'
        },
        {
            'project': 'ЖК Солнечный',
            'object': 'Корпус 2',
            'section': '5 этаж',
            'description': 'Монтаж сантехники кв. 51-55',
            'executor_name': 'Иванов А.П.',
            'executor_id': '987654321',
            'date': '25.01.2026',
            'send_time': '08:00',
            'priority': '🟡Medium'
        }
    ]

    task_ids = manager.create_bulk_tasks(weekly_tasks)
    print(f"Created tasks: {task_ids}")

    # Get summary
    summary = manager.get_today_summary()
    print(f"Today's summary: {summary}")

n8n ワークフローテンプレート

テンプレート 1:朝のタスク割り当て
name: Morning Task Distribution
trigger:
  type: cron
  expression: "0 8 * * 1-6"  # 8:00 AM, Mon-Sat

steps:
  - get_today_tasks:
      node: Google Sheets
      operation: readRows
      sheet: Tasks
      filter: Date = TODAY(), Status = Pending

  - group_by_worker:
      node: Code
      code: |
        const grouped = {};
        items.forEach(item => {
          const worker = item.json.Executor_ID;
          if (!grouped[worker]) grouped[worker] = [];
          grouped[worker].push(item.json);
        });
        return Object.entries(grouped).map(([id, tasks]) => ({
          worker_id: id,
          tasks: tasks
        }));

  - send_task_list:
      node: Telegram
      operation: sendMessage
      chatId: "={{$json.worker_id}}"
      text: |
        🌅 *Доброе утро! Ваши задачи на сегодня:*

        {{#each tasks}}
        ━━━━━━━━━━━━━━━━━━━━━
        {{priority}} *{{Task}}*
        📍 {{Object}} / {{Section}}
        ⏰ Срок: {{Date}}
        {{/each}}

        Ответьте на каждую задачу по мере выполнения.
テンプレート 2:写真レポートの収集
name: Scheduled Photo Reports
trigger:
  type: cron
  expression: "0 12,17 * * 1-6"  # 12:00 and 17:00

steps:
  - get_photo_reports:
      node: Google Sheets
      operation: readRows
      sheet: Photo Reports
      filter: Date = TODAY(), Status = Pending

  - send_photo_request:
      node: Telegram
      operation: sendMessage
      chatId: "={{$json.Executor_ID}}"
      text: |
        📷 *Требуется фото-отчет*
        ━━━━━━━━━━━━━━━━━━━━━
        📋 Тип: {{$json.Report_Type}}
        📍 Объект: {{$json.Object}}
        ⏰ Срок: {{$json.Time}}

        Пожалуйста, отправьте фото с комментарием.
      replyMarkup:
        inline_keyboard:
          - [{text: "📷 Отправить фото", callback_data: "photo_{{$json.Report_ID}}"}]
テンプレート 3:一日の終わりの概要
name: End of Day Report
trigger:
  type: cron
  expression: "0 18 * * 1-6"  # 18:00

steps:
  - get_day_stats:
      node: Google Sheets
      operation: readRows
      sheet: Tasks
      filter: Date = TODAY()

  - calculate_stats:
      node: Code
      code: |
        const stats = {
          total: items.length,
          completed: items.filter(i => i.json.Status === 'Completed').length,
          partial: items.filter(i => i.json.Status === 'Partial').length,
          pending: items.filter(i => i.json.Status === 'Pending').length,
          photos: items.filter(i => i.json.Photo_Link).length
        };
        stats.completion_rate = Math.round(stats.completed / stats.total * 100);
        return [{ json: stats }];

  - send_to_manager:
      node: Telegram
      operation: sendMessage
      chatId: "MANAGER_CHAT_ID"
      text: |
        📊 *Итоги дня: {{$now.format('DD.MM.YYYY')}}*
        ━━━━━━━━━━━━━━━━━━━━━

        📋 Всего задач: {{$json.total}}
        ✅ Выполнено: {{$json.completed}}
        ⏳ Частично: {{$json.partial}}
        ❌ Не выполнено: {{$json.pending}}

        📷 Фото-отчетов: {{$json.photos}}
        📈 Выполнение: {{$json.completion_rate}}%

        [Открыть таблицу]({{SPREADSHEET_URL}})

ベストプラクティス

タスクの設計
  1. タスクは分割可能な最小単位にします(1 タスク=1 アクション)。
  2. 明確な場所を記載します(Object + Section)。
  3. 現実的な期限を設定します。
  4. 優先度を適切に設定します(すべてを 🔴高 にしないでください)。
写真レポート
  1. 写真は継続的ではなく、節目ごとに依頼します。
  2. プロジェクト/日付ごとに Google Drive のフォルダーを使用します。
  3. 場所の確認(GPS)を含めます。
  4. 何を写真に含めるべきか、明確に伝えます。
作業員の参加促進
  1. すべての返信に速やかに応答します。
  2. 毎日フィードバックを提供します。
  3. 成果を上げた作業員を評価します。
  4. ボットのメッセージは簡潔にします。

リソース


「自動化は人を置き換えることではなく、人にしかできないことに専念できるようにすることです。」

コメント