יומנים וראיות
“הלקוח טוען שמישהו מחק לו את הסטטוס.” “הטריגר לא רץ.” “ההודעה לא יצאה.” שלוש שאלות, שלושה יומנים שונים. אין יומן אחד שעונה על כולן, ואין יומן הודעות מאוחד.
העמוד הזה ממפה שאלה → יומן → שאילתה.
מפת היומנים
Section titled “מפת היומנים”| היומן | מה נרשם בו | עונה על |
|---|---|---|
_Timeline |
יצירה / עדכון / מחיקה של רשומות | “מי שינה מה ומתי” |
_syslogTriggers |
ריצות טריגרים, כולל שגיאות | “האם האוטומציה בכלל רצה” |
_syslogSMS |
יומן ספק ה‑SMS, כולל מחיר | “האם ה‑SMS נשלח, ומה הוא עלה” |
_syslogCampaignSMS · _syslogCampaignWA · _syslogCampaignEmails |
שליחות מ‑MyCampaigns, לפי ערוץ | “מה יצא בדיוור” |
SMS |
הודעות SMS יוצאות עם הקשר עסקי | “אילו הודעות נשלחו ללקוח הזה” |
ConversationMessages |
הודעות בשיחה (כולל WhatsApp) | “האם ההודעה יצאה, והאם נכשלה” |
CallRecords |
פירוט שיחות מהמרכזייה | “מי דיבר עם הלקוח, כמה זמן, והאם יש הקלטה” |
_Notification |
פעמון ההתראות בממשק | “האם המשתמש בכלל קיבל התראה” |
כולם נשלפים כמו כל טבלה — שאילתות — בכפוף להרשאות.
_Timeline — יומן שינויי הרשומות
Section titled “_Timeline — יומן שינויי הרשומות”הטבלה שמאחורי ציר הזמן בכרטיס הרשומה.
שדות המפתח
Section titled “שדות המפתח”| שדה | משמעות |
|---|---|
event |
"create" · "update" · "delete" |
objectClass |
הטבלה של הרשומה שהשתנתה |
objectIdValue |
ה‑objectId של הרשומה שהשתנתה |
data |
מטען הכתיבה — רק השדות שנשלחו בפועל. שימו לב: הממשק שולח את כל הטופס, ולכן בעריכה מהדפדפן data כולל גם שדות שלא השתנו (מחרוזות ריקות, false) |
user |
מי עשה את זה. משתמש אמיתי בעריכה מהממשק (אומת: objectId של ה‑owner); משתמש הדמה Master בכתיבות API/MCP ובכתיבות טריגר |
createdBy · updatedBy |
תמיד Master — הם מתארים מי כתב את שורת היומן. לשיוך השתמשו ב‑user |
Referer |
מקור השינוי. null בכתיבות REST/MCP; כתובת העמוד המלאה כשאדם ערך בדפדפן (אומת: https://<sub>.mbapps.co.il/apps/MyBusiness/Account?oid=…&cls=Accounts); ו‑"server-side-code:<functionName>" כשפונקציית שרת (למשל web2table) כתבה את הרשומה — בחלק מהשורות הנקודתיים מקודדות כ‑: (api-c-04), אז חפשו ב‑$regex על server-side-code בלבד |
Last |
מסמן את השורה החדשה ביותר לאותה רשומה |
מתכון · “מי שינה את הרשומה הזו ומתי”
Section titled “מתכון · “מי שינה את הרשומה הזו ומתי””curl -sS -G "https://api.mbapps.co.il/parse/classes/_Timeline" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"objectClass":"Sales","objectIdValue":"YEkT85jX3K"}' \ --data-urlencode 'order=-createdAt' \ --data-urlencode 'limit=50'const params = new URLSearchParams({ where: JSON.stringify({ objectClass: 'Sales', objectIdValue: 'YEkT85jX3K' }), order: '-createdAt', limit: '50',});const res = await fetch(`https://api.mbapps.co.il/parse/classes/_Timeline?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY, },});import json, requests
res = requests.get( "https://api.mbapps.co.il/parse/classes/_Timeline", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY, }, params={ "where": json.dumps({"objectClass": "Sales", "objectIdValue": "YEkT85jX3K"}), "order": "-createdAt", "limit": 50, }, timeout=30,)<?php$params = http_build_query([ 'where' => json_encode(['objectClass' => 'Sales', 'objectIdValue' => 'YEkT85jX3K']), 'order' => '-createdAt', 'limit' => 50,]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_Timeline?$params");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'X-Parse-Application-Id: ' . $appId, 'X-Parse-Master-Key: ' . $masterKey, ],]);$response = curl_exec($ch);curl_close($ch);קראו את data (מה השתנה), את user (מי) ואת createdAt (מתי).
מתכון · “כל מה שקרה ללקוח הזה”
Section titled “מתכון · “כל מה שקרה ללקוח הזה””תלוי בעמודות ה‑index שהוגדרו לאותה מערכת. הדפוס המקובל הוא עמודת AccountId משותפת לכל הטבלאות שמצביעות על לקוח:
curl -sS -G "https://api.mbapps.co.il/parse/classes/_Timeline" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"AccountId":{"__type":"Pointer","className":"Accounts","objectId":"xK9mP2qRsT"}}' \ --data-urlencode 'order=-createdAt' --data-urlencode 'limit=50'const params = new URLSearchParams({ where: JSON.stringify({ AccountId: { __type: 'Pointer', className: 'Accounts', objectId: 'xK9mP2qRsT' }, }), order: '-createdAt', limit: '50',});const res = await fetch(`https://api.mbapps.co.il/parse/classes/_Timeline?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY, },});import json, requests
res = requests.get( "https://api.mbapps.co.il/parse/classes/_Timeline", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY, }, params={ "where": json.dumps({ "AccountId": {"__type": "Pointer", "className": "Accounts", "objectId": "xK9mP2qRsT"}, }), "order": "-createdAt", "limit": 50, }, timeout=30,)<?php$params = http_build_query([ 'where' => json_encode([ 'AccountId' => ['__type' => 'Pointer', 'className' => 'Accounts', 'objectId' => 'xK9mP2qRsT'], ]), 'order' => '-createdAt', 'limit' => 50,]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_Timeline?$params");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'X-Parse-Application-Id: ' . $appId, 'X-Parse-Master-Key: ' . $masterKey, ],]);$response = curl_exec($ch);curl_close($ch);שלוש מגבלות שחייבים להכיר לפני שמבטיחים ביקורת
Section titled “שלוש מגבלות שחייבים להכיר לפני שמבטיחים ביקורת”1 · שורת מחיקה כמעט ריקה — ואינה מופיעה בכרטיס.
delete כותב שורה מצומצמת: event, objectClass, objectIdValue, user וחותמות זמן. בלי data, בלי מצביעי index, בלי ערכי תצוגה.
שתי השלכות: מחיקה לעולם לא תופיע בציר הזמן של הכרטיס (הכרטיס מסנן לפי מצביע index, ולשורת המחיקה אין — אומת בממשק: איש קשר שנוצר ונמחק תחת לקוח אינו מופיע בציר הזמן של הלקוח), והיומן אינו שומר מה נמחק — רק “מישהו מחק אובייקט X ממחלקה Y בזמן T”.
מחיקות נמצאות רק כך:
curl -sS -G "https://api.mbapps.co.il/parse/classes/_Timeline" \ -H "X-Parse-Application-Id: $APP_ID" -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"event":"delete","objectClass":"Sales"}' \ --data-urlencode 'order=-createdAt' --data-urlencode 'limit=100'const params = new URLSearchParams({ where: JSON.stringify({ event: 'delete', objectClass: 'Sales' }), order: '-createdAt', limit: '100',});const res = await fetch(`https://api.mbapps.co.il/parse/classes/_Timeline?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY, },});import json, requests
res = requests.get( "https://api.mbapps.co.il/parse/classes/_Timeline", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY, }, params={ "where": json.dumps({"event": "delete", "objectClass": "Sales"}), "order": "-createdAt", "limit": 100, }, timeout=30,)<?php$params = http_build_query([ 'where' => json_encode(['event' => 'delete', 'objectClass' => 'Sales']), 'order' => '-createdAt', 'limit' => 100,]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_Timeline?$params");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'X-Parse-Application-Id: ' . $appId, 'X-Parse-Master-Key: ' . $masterKey, ],]);$response = curl_exec($ch);curl_close($ch);2 · Last אינו אמין בכתיבות מקבילות — לסירוגין.
בכתיבות עוקבות המנגנון מדויק. בכתיבות במקביל — לא תמיד: בהרצת אימות אחת, שישה עדכונים בו‑זמנית לאותה רשומה השאירו שש שורות עם Last: true (והמצב לא תוקן גם כדקה וחצי אחר כך); ב‑25 הרצות אחרות של אותו דפוס התוצאה הייתה תקינה. אותו דפוס מופיע בנתוני לקוח בכל מקום ששני טריגרים כותבים במרווח של אלפיות שנייה. ראו api-c-03.
מי ששולף מצב נוכחי לפי Last = true חייב לצפות לכפילויות, ולנפול חזרה ל‑order: "-createdAt".
3 · _Timeline אינה מוגנת מפני Master Key.
בשכבות המוצר ובשכבת ה‑MCP הטבלה נעולה לכתיבה. ב‑REST עם Master Key — וגם עם API Key — לעומת זאת, POST מחזיר 201 והשורה נשמרת, וגם DELETE עובד (אומת שוב).
המשמעות לחקירה: ציר הזמן הוא ראיה טובה מול משתמשי המערכת, אבל אינו ראיה מול מי שמחזיק את ה‑Master Key. אל תבטיחו ללקוח “יומן שאי אפשר לגעת בו”. ראו core-api-08.
_syslogTriggers — האם האוטומציה רצה
Section titled “_syslogTriggers — האם האוטומציה רצה”| שדה | משמעות |
|---|---|
triggerId |
מזהה הגדרת הטריגר — 10 תווים כמו objectId (למשל Cs8PxstHJO), וזהה ל‑_id שמחזיר Get-Triggers ב‑MCP ול‑updatedByTrigger ב‑_Timeline.data. (24‑hex שמורים לעמודים ולתפריטים בלבד) |
actionId |
מזהה הפעולה של הטריגר שרצה (10 תווים; null בשורת “הטריגר הופעל”, מלא בשורת “הפעולה רצה” — כל הפעלה כותבת שתי שורות) |
event |
האירוע שהפעיל |
objectIdValue |
הרשומה שעליה רץ |
data |
מטען הקשר — מחרוזת JSON, לא אובייקט |
error |
טקסט השגיאה כשהפעולה נכשלה — התחנה הראשונה. גם כאן מחרוזת JSON |
מתכון · “הטריגר לא רץ”
Section titled “מתכון · “הטריגר לא רץ””# מה קרה לרשומה הזוcurl -sS -G "https://api.mbapps.co.il/parse/classes/_syslogTriggers" \ -H "X-Parse-Application-Id: $APP_ID" -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"objectIdValue":"YEkT85jX3K"}' \ --data-urlencode 'order=-createdAt'
# כל הכשלים האחרונים במערכתcurl -sS -G "https://api.mbapps.co.il/parse/classes/_syslogTriggers" \ -H "X-Parse-Application-Id: $APP_ID" -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"error":{"$exists":true}}' \ --data-urlencode 'order=-createdAt' --data-urlencode 'limit=50'const headers = { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY,};
// מה קרה לרשומה הזוconst p1 = new URLSearchParams({ where: JSON.stringify({ objectIdValue: 'YEkT85jX3K' }), order: '-createdAt',});const res1 = await fetch(`https://api.mbapps.co.il/parse/classes/_syslogTriggers?${p1}`, { headers });
// כל הכשלים האחרונים במערכתconst p2 = new URLSearchParams({ where: JSON.stringify({ error: { $exists: true } }), order: '-createdAt', limit: '50',});const res2 = await fetch(`https://api.mbapps.co.il/parse/classes/_syslogTriggers?${p2}`, { headers });import json, requests
headers = { "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY,}
# מה קרה לרשומה הזוres1 = requests.get( "https://api.mbapps.co.il/parse/classes/_syslogTriggers", headers=headers, params={ "where": json.dumps({"objectIdValue": "YEkT85jX3K"}), "order": "-createdAt", }, timeout=30,)
# כל הכשלים האחרונים במערכתres2 = requests.get( "https://api.mbapps.co.il/parse/classes/_syslogTriggers", headers=headers, params={ "where": json.dumps({"error": {"$exists": True}}), "order": "-createdAt", "limit": 50, }, timeout=30,)<?php$headers = [ 'X-Parse-Application-Id: ' . $appId, 'X-Parse-Master-Key: ' . $masterKey,];
// מה קרה לרשומה הזו$p1 = http_build_query([ 'where' => json_encode(['objectIdValue' => 'YEkT85jX3K']), 'order' => '-createdAt',]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_syslogTriggers?$p1");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers,]);$response1 = curl_exec($ch);curl_close($ch);
// כל הכשלים האחרונים במערכת$p2 = http_build_query([ 'where' => json_encode(['error' => ['$exists' => true]]), 'order' => '-createdAt', 'limit' => 50,]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_syslogTriggers?$p2");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers,]);$response2 = curl_exec($ch);curl_close($ch);עוד סימן שכדאי לחפש: חריגה מעומק שרשרת נרשמת ב‑error כ‑blocked! trigger step is to deep -3. source trigger: <triggerId> (כך, עם שגיאת הכתיב — הטקסט “Max trigger depth reached” אינו קיים במערכת). המגבלה היא 3 רמות: בשרשרת בת חמש טבלאות שכל אחת יוצרת שורה בבאה, נוצרו שלוש הרמות הראשונות והטריגר של הרביעית נחסם (אומת).
_RequestLog — מי פנה ל‑API
Section titled “_RequestLog — מי פנה ל‑API”היומן הזה עונה על שתי שאלות: האם הכתיבה שלי הגיעה לשרת, ואיזה קוד סטטוס היא קיבלה. השדות (אומתו מהסכימה): path · method · ip · country · referer · userAgent · user · usingMK · internal · trustedIP · duration · statusCode · contentLength · service · retries · installationId. הטבלה נקראת עם Master Key בלבד (CLP סגור לגמרי — גם API Key וגם Session Token נחסמים).
curl -sS -G "https://api.mbapps.co.il/parse/classes/_RequestLog" \ -H "X-Parse-Application-Id: $APP_ID" -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"usingMK":true,"statusCode":{"$gte":400}}' \ --data-urlencode 'order=-createdAt' --data-urlencode 'limit=50'const params = new URLSearchParams({ where: JSON.stringify({ usingMK: true, statusCode: { $gte: 400 } }), order: '-createdAt', limit: '50',});const res = await fetch(`https://api.mbapps.co.il/parse/classes/_RequestLog?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY, },});import json, requests
res = requests.get( "https://api.mbapps.co.il/parse/classes/_RequestLog", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY, }, params={ "where": json.dumps({"usingMK": True, "statusCode": {"$gte": 400}}), "order": "-createdAt", "limit": 50, }, timeout=30,)<?php$params = http_build_query([ 'where' => json_encode(['usingMK' => true, 'statusCode' => ['$gte' => 400]]), 'order' => '-createdAt', 'limit' => 50,]);$ch = curl_init("https://api.mbapps.co.il/parse/classes/_RequestLog?$params");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'X-Parse-Application-Id: ' . $appId, 'X-Parse-Master-Key: ' . $masterKey, ],]);$response = curl_exec($ch);curl_close($ch);מה שכן זמין לשאלה “מה קרה” בנתונים עצמם: _Timeline (אם הטבלה מנוטרת) ו‑_syslogTriggers.
יומני הערוצים — אין יומן הודעות אחד
Section titled “יומני הערוצים — אין יומן הודעות אחד”| הערוץ | איפה מחפשים | מה יש שם |
|---|---|---|
| WhatsApp (בתוך שיחה) | Conversations + ConversationMessages |
ב‑ConversationMessages: Message, Direction, failed, failedAt, errors, IsErrorRead + ConversationId. ב‑Conversations רק מצב השיחה (StatusId, StateId, LastMessageAt, UnreadCount…) |
| WhatsApp — דיוור | _syslogCampaignWA |
שליחות מ‑MyCampaigns (במערכת חדשה המחלקה קיימת בלי שדות — הם נוצרים בשליחה הראשונה) |
| SMS — הרמה העסקית | SMS |
From, To, Content, Status, TemplateId + מצביעי הקשר (AccountId, SaleId, CaseId, TaskId, ActivityId, ContactId) |
| SMS — רמת הספק | _syslogSMS |
במערכת חדשה המחלקה קיימת בלי שדות. השדות המתועדים מסביבות פעילות (State, ToNumber, Error, Price) לא אומתו כאן — בדקו מול GET /parse/schemas/_syslogSMS במערכת שלכם |
| מייל | Emails |
MailFrom, MailTo, CC, BCC, Subject, SendAt, SendStatus, ErrorMessage, MessageId, ConversationId + מצביעי הקשר |
| דיוור | CampaignSentLog |
לכל נמען: Status, delivered/deliveredAt, opened/openedAt, clicked/clickedAt, failed/failedAt, unsubscribed, Error + CampaignId, AccountId. (_syslogCampaignEmails / _syslogCampaignSMS — קיימות בלי שדות במערכת חדשה) |
| טלפוניה | CallRecords |
time, caller, type, status, representative_name, duration, record (URL הקלטה), AccountId |
| התראה בממשק | _Notification |
User, Content, Date, Icon, objectClass + objectIdValue, updatedByTrigger |
(טבלת _syslogWA מוזכרת בתיעוד ותיק אך אינה קיימת במערכת חדשה — אומת: Class _syslogWA does not exist. התחילו מ‑ConversationMessages.)
מתכון · “ההודעה לא הגיעה ללקוח”
Section titled “מתכון · “ההודעה לא הגיעה ללקוח””- מה הערוץ? בלי זה אין יומן.
- ברמה העסקית — האם בכלל נוצרה שורה? (
SMS/Emails/ConversationMessages) אם לא — הטריגר לא רץ. עברו ל‑_syslogTriggers. - ברמת הספק — האם יצאה החוצה? (
_syslogSMS.Error,ConversationMessages.errors,Emails.ErrorMessage) - בצד הלקוח — האם הרשומה מסומנת בהסרה מדיוור? שדות ההסרה אינם אחידים בין טננטים: בטננט הדמו
Accountsמכיל רקdontSendWhatsApp, ו‑Contactsלא מכיל אף אחד משדות ה‑dontSend*(אומת מולGET /parse/schemas). בדקו בסכימה שלכם אילו שדות קיימים לפני שאתם שואלים עליהם. - הגדרות המערכת — בלי חשבון SMTP מוגדר, מיילים כלל אינם יוצאים.
שלוש חקירות שלמות
Section titled “שלוש חקירות שלמות”“מי שינה את השדה ומתי”
Section titled ““מי שינה את השדה ומתי””- שלפו
_TimelineלפיobjectClass+objectIdValue, במיון-createdAt. - אין שורות? הטבלה אינה מנוטרת, או שהתקופה קודמת להפעלה. אין נתונים — וזו תשובה לגיטימית.
- יש שורות? קראו את
data(מה השתנה) ואתuser(מי). userאינוMaster? משתמש אמיתי.Refererמלא מאשר שזה נעשה בדפדפן.userהואMaster? כתיבת API, MCP או טריגר.updatedByTriggerבתוךdataמכריע בין השניים.
“האם הטריגר רץ”
Section titled ““האם הטריגר רץ””- שלפו את הרשומה עצמה — ודאו שזו הרשומה והתאריך שהלקוח מתכוון אליהם.
_Timelineעל הרשומה — מה קרה בפועל, לפי סדר._syslogTriggersעל הרשומה — שגיאות. היעדר ≠ הוכחה.- הגדרת הטריגר — האם הוא פעיל, מה התנאים, ואילו שדות מפעילים אותו. תנאי שלא התקיים בזמן האירוע הוא ההסבר הנפוץ ביותר.
- אם הפעולה היא
server-side-code— יש לקרוא את הפונקציה. ראו פונקציות צד שרת.
“האם ההודעה יצאה”
Section titled ““האם ההודעה יצאה””זרימה מלאה בטבלת המתכון שלמעלה. הכלל: התקדמו מהעסקי אל הספק, ולא הפוך.
הערות שכדאי לקרוא לפני שמריצים
Section titled “הערות שכדאי לקרוא לפני שמריצים”- טבלאות יומן צומחות מהר. ספרו לפני שאתם שולפים (
limit=0&count=1), ותמיד סננו ומיינו. סריקת טבלה מלאה על_Timelineבסביבת ייצור היא רעיון גרוע. - משתמש הדמה
Masterמופיע כמזהה מחרוזת מילולית — לא objectId בן 10 תווים. סננו אותו החוצה כשמדווחים על “פעילות אנושית”. _syslogEventsאינו קיים במערכת חדשה. הוא מתועד כיומן אירועי פלטפורמה (type,data,error), אבל המחלקה אינה מוגדרת (400 Class _syslogEvents does not exist) — אל תבנו עליו מתכון חקירה. מה שכן קיים ומאוכלס:_GeneralLogs(Type,Name,Value) — למשלType: "SendPriceQuoteEmail".triggerIdו‑objectIdValueהם שני מרחבים שונים גם אם שניהם בני 10 תווים — האחד מזהה הגדרת טריגר, השני רשומה. אל תשוו ביניהם. (24‑hex שמורים לעמודים, לתפריטים ולאתר.)- כתיבה ישירה ל‑
_syslog*, ל‑_Timelineאו ל‑_AutoIncrementValuesמשבשת ביקורת ומספור. הן לקריאה בלבד לפי מוסכמה בלבד — עם Master Key כולן ניתנות לכתיבה, אבל לא באופן סימטרי: ב‑_TimelineגםDELETEעובר (core-api-08), ואילו ב‑_syslogTriggersPOSTו‑PUTעוברים אבלDELETEנדחה ב‑Action is denied for system tables— שורה שנוספה בטעות נשארת לתמיד (api-c-05). ל‑_AutoIncrementValuesראוstart-b-02.
המשך מכאן
Section titled “המשך מכאן”- שגיאות ופתרון תקלות — אבחון לפי תסמין
- מפת הטבלאות — טבלאות המערכת בהקשר הרחב
- פונקציות צד שרת — כשהעקבות מובילות לקוד
- batch — למה טעינה המונית מייצרת סופת יומנים
- שאילתות — הכלים לשלוף את כל זה