n8n-project-management

n8n Project Management System for Construction

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "n8n-project-management" with this command: npx skills add datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/datadrivenconstruction-ddc-skills-for-ai-agents-in-construction-n8n-project-management

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

  • Keep tasks atomic (1 task = 1 action)

  • Include clear location (Object + Section)

  • Set realistic deadlines

  • Use priority wisely (not everything is 🔴High)

Photo Reports

  • Request photos at milestones, not continuously

  • Use Google Drive folders per project/date

  • Include location verification (GPS)

  • Set clear expectations (what should be in photo)

Worker Engagement

  • Acknowledge all responses quickly

  • Provide daily feedback

  • Recognize high performers

  • Keep bot messages concise

Resources

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

drawing-analyzer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cad-to-data

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dwg-to-excel

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cost-estimation-resource

No summary provided by upstream source.

Repository SourceNeeds Review