| 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":"[Truncated]"}}} |
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
import requests
BOT_TOKEN = "YOUR_BOT_TOKEN"
response = requests.get(f"https://api.telegram.org/bot{BOT_TOKEN}/getMe")
print(response.json())
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
{
"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"
Step 4: Configure Webhook
curl -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" \
-d "url=https://your-n8n-instance.com/webhook/telegram-project-manager"
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')
all_tasks = tasks_sheet.get_all_records()
task_num = len(all_tasks) + 1
task_id = f"TASK-{task_num:04d}"
row = [
task_id,
task.get('project', ''),
task.get('object', ''),
task.get('section', ''),
task.get('description', ),
task.get(, ),
task.get(, ),
task.get(, datetime.now().strftime()),
task.get(, ),
task.get(, ),
,
,
,
,
,
]
tasks_sheet.append_row(row)
task_id
() -> :
task_ids = []
task tasks:
task_id = .create_task(task)
task_ids.append(task_id)
task_ids
() -> :
tasks_sheet = .spreadsheet.worksheet()
all_tasks = tasks_sheet.get_all_records()
today = datetime.now().strftime()
today_tasks = [t t all_tasks t[] == today]
{
: (today_tasks),
: ([t t today_tasks t[] == ]),
: ([t t today_tasks t[] == ]),
: ([t t today_tasks t[] == ]),
: ([t t today_tasks t[]])
}
() -> :
tasks_sheet = .spreadsheet.worksheet()
all_tasks = tasks_sheet.get_all_records()
cutoff_date = datetime.now() - timedelta(days=days)
worker_tasks = [
t t all_tasks
t[] == worker_name
datetime.strptime(t[], ) >= cutoff_date
]
worker_tasks:
{: }
completed = ([t t worker_tasks t[] == ])
total = (worker_tasks)
{
: worker_name,
: days,
: total,
: completed,
: (completed / total * , ),
: ([t t worker_tasks t[]]),
: ([t t worker_tasks t[]])
}
__name__ == :
manager = ProjectTaskManager(
,
)
weekly_tasks = [
{
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
},
{
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
}
]
task_ids = manager.create_bulk_tasks(weekly_tasks)
()
summary = manager.get_today_summary()
()
n8n Workflow Templates
Template 1: Morning Task Distribution
name: Morning Task Distribution
trigger:
type: cron
expression: "0 8 * * 1-6"
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: |
🌅 *Доброе утро! Ваши задачи на сегодня:*
{{
━━━━━━━━━━━━━━━━━━━━━
{{priority}} *{{Task}}
{{}} {{}}
{{}}
{{}}
Template 2: Photo Report Collection
name: Scheduled Photo Reports
trigger:
type: cron
expression: "0 12,17 * * 1-6"
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"
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}}
✅ Выполнено: {{}}
{{}}
{{}}
{{}}
{{}}
[ ]
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."