n8n-project-management

star 161

Build a complete project management system with Telegram bot, task distribution, and photo reports using n8n. Based on DDC Project Management repository.

datadrivenconstruction By datadrivenconstruction schedule Updated 2/14/2026

name: "n8n-project-management" description: "Build a complete project management system with Telegram bot, task distribution, and photo reports using n8n. Based on DDC Project Management repository." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw": {"emoji": "πŸ”§", "os": ["darwin", "linux", "win32"], "homepage": "https://datadrivenconstruction.io", "requires": {"bins": ["python3"]}}}

n8n Project Management System for Construction

Build a universal task management and reporting system for construction projects using n8n automation, Telegram bot, and Google Sheets.

Business Case

Problem: Construction managers spend 2-3 hours daily on:

  • Distributing tasks to foremen and workers
  • Collecting progress updates via calls/messages
  • Compiling photo documentation
  • Tracking task completion status

Solution: Automated system that:

  • Sends task reminders via Telegram at scheduled times
  • Collects status reports (text + photos + GPS)
  • Auto-saves all data to Google Sheets
  • Provides real-time visibility to managers

ROI: 70% reduction in administrative time for task management

Source Repository

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

System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    PROJECT MANAGEMENT SYSTEM                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                       β”‚
β”‚   MANAGER                          WORKER                            β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚   β”‚ Google      β”‚                  β”‚ Telegram    β”‚                   β”‚
β”‚   β”‚ Sheets      β”‚                  β”‚ Bot         β”‚                   β”‚
β”‚   β”‚             β”‚                  β”‚             β”‚                   β”‚
β”‚   β”‚ β€’ Tasks     β”‚    n8n           β”‚ β€’ /start    β”‚                   β”‚
β”‚   β”‚ β€’ Schedule  │◄──Workflow──────►│ β€’ Tasks     β”‚                   β”‚
β”‚   β”‚ β€’ Reports   β”‚                  β”‚ β€’ Photos    β”‚                   β”‚
β”‚   β”‚ β€’ Photos    β”‚                  β”‚ β€’ GPS       β”‚                   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚         β”‚                                β”‚                           β”‚
β”‚         β–Ό                                β–Ό                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚   β”‚ Dashboard   β”‚                  β”‚ Google      β”‚                   β”‚
β”‚   β”‚ View        β”‚                  β”‚ Drive       β”‚                   β”‚
β”‚   β”‚             β”‚                  β”‚ (Photos)    β”‚                   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚                                                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Implementation Guide

Step 1: Create Telegram Bot

# 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"}}

Step 2: Setup Google Sheets

Create spreadsheet with these sheets:

Sheet 1: Tasks

Column Type Description
Task_ID Text Unique identifier (TASK-001)
Project Text Project name
Object Text Building/area
Section Text Floor/zone
Task Text Task description
Executor Text Assigned worker name
Executor_ID Number Telegram user ID
Date Date Due date (DD.MM.YYYY)
Send_Time Time Reminder time
Priority Text πŸ”΄High / 🟑Medium / 🟒Low
Status Text Pending/Sent/Completed/Partial
Response Text Worker's response
Response_Time DateTime When responded
Photo_Link URL Google Drive link
GPS_Lat Number Latitude
GPS_Lon Number Longitude

Sheet 2: Workers

Column Type Description
Name Text Worker full name
Role Text Foreman/Worker/Contractor
Telegram_ID Number User ID from /start
Phone Text Phone number
Registered DateTime Registration date

Sheet 3: Photo Reports

Column Type Description
Report_ID Text Unique ID
Report_Type Text Daily/Safety/Quality
Executor Text Who should submit
Date Date Report date
Time Time Deadline
Status Text Pending/Submitted
Photo_Link URL Drive folder link
Comment Text Worker comment

Step 3: Import n8n Workflow

// 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}}"
      }
    }
  ]
}

Step 4: Configure 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"

Worker Commands

Registration: /start

User: /start

Bot: πŸ‘‹ Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² систСму управлСния Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ!

ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡƒΠΊΠ°ΠΆΠΈΡ‚Π΅ вашС имя:

User: Иван ΠŸΠ΅Ρ‚Ρ€ΠΎΠ²

Bot: Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π²Π°ΡˆΡƒ Ρ€ΠΎΠ»ΡŒ:
[ΠŸΡ€ΠΎΡ€Π°Π±] [Π Π°Π±ΠΎΡ‡ΠΈΠΉ] [Бубподрядчик]

User: [ΠŸΡ€ΠΎΡ€Π°Π±]

Bot: βœ… РСгистрация Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π°!
Имя: Иван ΠŸΠ΅Ρ‚Ρ€ΠΎΠ²
Роль: ΠŸΡ€ΠΎΡ€Π°Π±
ID: 123456789

Π’Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ автоматичСски.
Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ /help для справки.

Receiving Task

Bot: πŸ“‹ *ЗАДАЧА #TASK-047*
━━━━━━━━━━━━━━━━━━━━━
πŸ“ ΠžΠ±ΡŠΠ΅ΠΊΡ‚: Π–Πš Π‘ΠΎΠ»Π½Π΅Ρ‡Π½Ρ‹ΠΉ, ΠšΠΎΡ€ΠΏΡƒΡ 2
πŸ— БСкция: 5 этаТ, ΠΊΠ². 51-55
πŸ“ Π—Π°Π΄Π°Ρ‡Π°: ΠœΠΎΠ½Ρ‚Π°ΠΆ элСктропроводки
⏰ Π‘Ρ€ΠΎΠΊ: 24.01.2026
πŸ”΄ ΠŸΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚: Высокий
━━━━━━━━━━━━━━━━━━━━━

ΠžΡ‚Π²Π΅Ρ‚ΡŒΡ‚Π΅ Π½Π° это сообщСниС для ΠΎΡ‚Ρ‡Π΅Ρ‚Π°:
β€’ ВСкст: статус + ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ
β€’ Π€ΠΎΡ‚ΠΎ: ΠΏΡ€ΠΈΠΊΡ€Π΅ΠΏΠΈΡ‚Π΅ Ρ„ΠΎΡ‚ΠΎ Ρ€Π°Π±ΠΎΡ‚
β€’ GPS: ΠΎΡ‚ΠΏΡ€Π°Π²ΡŒΡ‚Π΅ Π³Π΅ΠΎΠ»ΠΎΠΊΠ°Ρ†ΠΈΡŽ

Task Response

User: (reply to task message)
Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ
ΠŸΡ€ΠΎΠ²ΠΎΠ΄ΠΊΠ° смонтирована ΠΏΠΎ всСм ΠΊΠ²Π°Ρ€Ρ‚ΠΈΡ€Π°ΠΌ, ΠΆΠ΄Π΅ΠΌ ΠΏΡ€ΠΈΠ΅ΠΌΠΊΡƒ

Bot: βœ… ΠžΡ‚Ρ‡Π΅Ρ‚ принят!
━━━━━━━━━━━━━━━━━━━━━
πŸ“‹ Π—Π°Π΄Π°Ρ‡Π°: #TASK-047
πŸ“Š Бтатус: Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ
πŸ’¬ ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ: ΠŸΡ€ΠΎΠ²ΠΎΠ΄ΠΊΠ° смонтирована...
⏰ ВрСмя: 24.01.2026 14:35
━━━━━━━━━━━━━━━━━━━━━

Photo Report

User: (sends photo as reply to task)
[Photo of completed electrical work]
Caption: ΠœΠΎΠ½Ρ‚Π°ΠΆ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½, Π³ΠΎΡ‚ΠΎΠ²ΠΎ ΠΊ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅

Bot: πŸ“· Π€ΠΎΡ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ ΠΈ сохранСно!
━━━━━━━━━━━━━━━━━━━━━
πŸ“‹ Π—Π°Π΄Π°Ρ‡Π°: #TASK-047
πŸ”— Π€ΠΎΡ‚ΠΎ: [Бсылка Π½Π° Google Drive]
πŸ’¬ ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ: ΠœΠΎΠ½Ρ‚Π°ΠΆ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½...
⏰ ВрСмя: 24.01.2026 14:38
━━━━━━━━━━━━━━━━━━━━━

GPS Location

User: (sends location)
πŸ“ [Location: 55.7558, 37.6173]

Bot: πŸ“ ГСолокация ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°!
━━━━━━━━━━━━━━━━━━━━━
πŸ“‹ Π—Π°Π΄Π°Ρ‡Π°: #TASK-047
πŸ—Ί ΠšΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹: 55.7558, 37.6173
πŸ”— ΠšΠ°Ρ€Ρ‚Π°: [Google Maps Link]
⏰ ВрСмя: 24.01.2026 14:40
━━━━━━━━━━━━━━━━━━━━━

Manager Dashboard

Google Sheets View

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 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 Integration

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 Workflow Templates

Template 1: Morning Task Distribution

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}}

        ΠžΡ‚Π²Π΅Ρ‚ΡŒΡ‚Π΅ Π½Π° ΠΊΠ°ΠΆΠ΄ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ выполнСния.

Template 2: Photo Report Collection

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}}"}]

Template 3: End of Day Summary

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}})

Best Practices

Task Design

  1. Keep tasks atomic (1 task = 1 action)
  2. Include clear location (Object + Section)
  3. Set realistic deadlines
  4. Use priority wisely (not everything is πŸ”΄High)

Photo Reports

  1. Request photos at milestones, not continuously
  2. Use Google Drive folders per project/date
  3. Include location verification (GPS)
  4. Set clear expectations (what should be in photo)

Worker Engagement

  1. Acknowledge all responses quickly
  2. Provide daily feedback
  3. Recognize high performers
  4. Keep bot messages concise

Resources


"Automation is not about replacing people, it's about freeing them to do what only people can do."

Install via CLI
npx skills add https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill n8n-project-management
Repository Details
star Stars 161
call_split Forks 49
navigation Branch main
article Path SKILL.md
More from Creator
datadrivenconstruction
datadrivenconstruction Explore all skills →