أتمتة تقرير Notion للمهام المتأخرة قبل ما تتدفن
مستوى القارئ: متوسط
هتكسب تقرير يومي واضح للمهام المتأخرة في Notion بدل ما تبدأ صباحك بفتح قاعدة بيانات وفرز يدوي.
المشكلة باختصار
لو عندك فريق صغير بيستخدم Notion كـ task tracker، اللي بيحصل فعلاً إن المهام المتأخرة مش بتظهر في لحظة القرار. المدير يفتح Notion، يفلتر Due Date، يراجع Status، وبعدها يبعت رسالة للفريق. العملية دي ممكن تاخد 20 دقيقة يوميًا. مع 5 أيام عمل، أنت بتصرف حوالي 100 دقيقة في الأسبوع على متابعة قابلة للأتمتة.
الافتراض هنا إن عندك Data Source في Notion فيها خصائص: Name، Status، Due، وOwner. لو الأسماء مختلفة، هتغيرها في السكربت فقط.
الفكرة بمثال بسيط
ركز في المثال ده: عندك 120 مهمة مفتوحة. كل صباح فيه 9 إلى 15 مهمة متأخرة. بدل ما شخص يدخل ويعمل filter، سكربت Node.js يسأل Notion: هات المهام التي لم تنتهِ وحقل Due بتاعها قبل أو يساوي تاريخ اليوم. بعد كده يرتبها حسب المالك ويرسل بريد واحد للفريق.
المفهوم العلمي هنا بسيط: أنت لا تؤتمت القرار. أنت تؤتمت جمع الإشارات. القرار يفضل عند الإنسان، لكن البيانات بتوصله في وقت ثابت وبصيغة ثابتة. الـ trade-off هنا إن التقرير ممكن يزعج الفريق لو اتبعت لكل صغيرة. المكسب إن التأخير الحقيقي يظهر بدري.
السكربت التنفيذي
أفضل طريقة هنا هي سكربت صغير، مش workflow ضخم. استخدم Notion API لجلب البيانات، وResend لإرسال البريد. Notion يشرح Query Data Source والفلاتر في توثيقه الرسمي، وResend يوفر endpoint بسيط لإرسال Email API.
npm init -y
npm install @notionhq/client resend
# Linux/macOS
export NOTION_TOKEN="secret_xxx"
export NOTION_DATA_SOURCE_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export RESEND_API_KEY="re_xxx"
export REPORT_TO="team@example.com"
export REPORT_FROM="ops@example.com"
node overdue-report.jsimport { Client } from "@notionhq/client";
import { Resend } from "resend";
const notion = new Client({ auth: process.env.NOTION_TOKEN });
const resend = new Resend(process.env.RESEND_API_KEY);
const today = new Date().toISOString().slice(0, 10);
const response = await notion.dataSources.query({
data_source_id: process.env.NOTION_DATA_SOURCE_ID,
filter: {
and: [
{ property: "Status", status: { does_not_equal: "Done" } },
{ property: "Due", date: { on_or_before: today } }
]
},
sorts: [{ property: "Due", direction: "ascending" }]
});
const rows = response.results.map((page) => {
const p = page.properties;
return {
title: p.Name?.title?.[0]?.plain_text ?? "Untitled",
due: p.Due?.date?.start ?? "no date",
owner: p.Owner?.people?.[0]?.name ?? "Unassigned"
};
});
const html = rows.length
? ``
: ``;
await resend.emails.send({
from: process.env.REPORT_FROM,
to: process.env.REPORT_TO,
subject: `Notion overdue tasks - ${today}`,
html
});
console.log(`sent ${rows.length} overdue tasks`);