פורסם

כלי למעקב תקציב באירוח עצמי: קוד פתוח, Docker ו-Postgres

הפעילו מקומית כלי בקוד פתוח למעקב אחר הוצאות ותקציב באמצעות Docker ו-Postgres, והבינו איך לנהל גיבויים, היכן עוברים גבולות הפרטיות ומתי עדיף להשתמש בשירות מתארח.

Docker Compose אינו מצליח לעבד את התצורה הנוכחית עד שתבחרו מצב אימות. להתקנה מקומית ללא התחברות, צריך לציין את המצב במפורש בפקודה:

AUTH_MODE=none make up

הפרט הקטן הזה מלמד הרבה על אירוח עצמי של תוכנה לפיננסים אישיים. קל להפעיל את הקונטיינרים. העבודה האמיתית מתחילה בהחלטות: מי יכול לגשת אליהם, היכן יישמרו הגיבויים ואילו שירותים אופציונליים רשאים לקבל נתונים פיננסיים.

Expense Budget Tracker הוא כלי בקוד פתוח למעקב אחר תקציב, ברישיון MIT, שנבנה עם Next.js ו-Postgres. המדריך הזה מתאר את המאגר כפי שהוא פועל כעת: התקנה מקומית ב-Docker למשתמש טכני יחיד, נתיב מתועד לפריסה לייצור באמצעות AWS/CDK ונקודות קצה מנוהלות ונפרדות לממשק הווב המתארח, לשירות MCP ול-Agent API.

אדם מתחזק מערכת עצמאית לאיסוף מי גשם לצד מכל גיבוי וצינור מנותק

קודם כול, החליטו היכן עובר הגבול מבחינתכם

המונח ״אירוח עצמי״ עשוי לתאר כמה תצורות שונות מאוד. אין להתייחס אליהן כאילו הן שקולות זו לזו.

תצורה היכן נשמרים הנתונים הפיננסיים על מה אתם אחראים למי זה מתאים
Docker Compose מקומי Postgres ב-volume של Docker במחשב שלכם קונטיינרים, עדכונים, גישה מקומית וגיבויים משתמש טכני יחיד שרוצה בעיקר את ממשק הווב במחשב אחד
חשבון AWS שלכם עם מחסנית ה-CDK המתועדת RDS ושירותי האפליקציה בחשבון AWS שלכם AWS,‏ Cloudflare, דומיינים, תעודות, שליחת אימיילים, סודות, ניטור וגיבויים פריסה ציבורית או מרובת משתמשים שבה אתם מוכנים לקחת על עצמכם את עבודת התשתית
אפליקציית ווב מנוהלת הסביבה המתארחת של Expense Budget Tracker החשבון שלכם ותהליך הזנת הנתונים מי שרוצה ממשק משתמש בלי להפעיל שרתים
מחבר MCP מתארח סביבת העבודה המתארחת, דרך שירות ה-MCP מתן הסכמה להרשאות OAuth וחיבור הלקוח סוכן שתומך ב-MCP וזקוק לגישת קריאה או כתיבה בהיקף הרשאה מוגדר
Agent API מתארח סביבת העבודה המתארחת, דרך שירות ה-API ApiKey לטווח ארוך, בחירת סביבת עבודה ושאילתות SQL לאחר בדיקה סקריפטים וסוכנים שפועלים מהמסוף ויכולים לפנות ישירות ב-HTTP

פקודת ה-Compose המקומית אינה יוצרת את api.your-domain.com או את mcp.your-domain.com. ממשקי הגישה למכונות שייכים לארכיטקטורת AWS ולשירות המנוהל. הפניית לקוח מתארח אל https://mcp.expense-budget-tracker.com/mcp פירושה שימוש בסביבת העבודה המתארחת, ולא גישה לקונטיינר Postgres שבמחשב הנייד שלכם.

זו ההחלטה הראשונה שצריך לקבל כשבוחנים כלי למעקב תקציב באירוח עצמי: האם אתם רוצים שליטה מקומית באפליקציית הווב ובמסד הנתונים, או אינטגרציות מרוחקות שמחייבות פריסה רחבה יותר?

הפעילו מקומית את כלי המעקב אחר ההוצאות באמצעות Docker

תזדקקו ל-Git, ל-Docker ול-Docker Compose. שכפלו את המאגר והפעילו את המחסנית מתיקיית השורש שלו:

git clone https://github.com/kirill-markin/expense-budget-tracker.git
cd expense-budget-tracker
AUTH_MODE=none make up

לאחר מכן, פתחו את http://localhost:3000.

Compose דורש את המשתנה AUTH_MODE. אם לא העתקתם את .env.example אל .env, צריך להוסיף את הקידומת לכל פקודת Compose. הפקודות בהמשך עושות זאת במכוון.

make up הוא קיצור לפקודה:

AUTH_MODE=none docker compose -f infra/docker/compose.yml up -d

קובץ ה-Compose הנוכחי מגדיר Postgres 18, שירות חד-פעמי להרצת מיגרציות, את אפליקציית הווב ב-Next.js, את שירות האימות ואת שירות הרקע של שערי החליפין. כאשר AUTH_MODE=none, אפליקציית הווב משתמשת בזהות המקומית במקום לדרוש התחברות דרך Cognito. התייחסו למצב הזה כאל גישה לפיתוח מקומי, ולעולם לא כאל אימות לשרת ציבורי.

אפשר לבדוק את מצב הקונטיינרים ולעקוב אחר יומני האפליקציה באמצעות פקודות Compose רגילות:

AUTH_MODE=none docker compose -f infra/docker/compose.yml ps
AUTH_MODE=none docker compose -f infra/docker/compose.yml logs -f web

עצרו את המחסנית באמצעות:

AUTH_MODE=none make down

ב-Makefile, הפקודה הזו מפעילה את docker compose down ללא -v. נתוני Postgres נשארים ב-volume בשם pgdata, והמערכת משתמשת בהם שוב בהפעלה הבאה.

ההתמדה הזו נוחה, אך היא אינה גיבוי. תקלה במחשב המארח, השחתת נתונים בדיסק, מחיקה מקרית של ה-volume או הרצה מפורשת של docker compose down -v עדיין עלולות למחוק את העותק היחיד.

השאירו את התצורה הזו ברשת המקומית

תצורת Compose חושפת במחשב המארח את אפליקציית הווב ביציאה 3000, את Postgres ביציאה 5432 ואת שירות האימות ביציאה 8081. היא כוללת גם פרטי התחברות למסד נתונים המיועדים לפיתוח. אל תריצו את התצורה הזו על שרת שחשוף לאינטרנט מתוך הנחה ש-Docker הפך אותה לפרטית.

בהתקנה על תחנת עבודה:

  • השתמשו בחומת האש של המחשב כדי להגביל את הגישה ברשת;
  • אל תגדירו בנתב הפניית פורטים ליציאות 3000,‏ 5432 או 8081;
  • אל תחשפו את AUTH_MODE=none דרך reverse proxy ציבורי;
  • הרחיקו את המאגר, קובצי .env וקובצי dump של מסד הנתונים מתיקיות ציבוריות או משותפות בהיקף רחב.

המאגר מתעד את AWS/CDK כדרך הפריסה לסביבת ייצור. הוא אינו מבטיח הוראות לפריסה מוקשחת בכל VPS,‏ NAS, אשכול Kubernetes או שרת ביתי, גם אם מפעיל מנוסה יוכל להתאים את הקוד.

מה רץ ומה נשאר ב-Postgres

הארכיטקטורה המקומית קטנה מספיק כדי לבדוק אותה:

  • אפליקציית ווב ב-Next.js: מספקת את ממשקי התקציב, התנועות, היתרות, לוח המחוונים, ההדגמה והצ׳אט.
  • Postgres: מאחסן את פנקס התנועות, תוכניות התקציב, הגדרות סביבת העבודה, המטא-נתונים של החשבונות ומצב האפליקציה.
  • קונטיינר המיגרציה: מחיל את מיגרציות ה-SQL של המאגר לפני ששירות הווב מתחיל לפעול.
  • שירות רקע לשערי חליפין: מושך נתונים ציבוריים של שערי חליפין וכותב אותם באמצעות תפקיד מוגבל במסד הנתונים.
  • שירות האימות: תומך בארכיטקטורה של פריסה עם אימות; שימוש מקומי בווב עוקף את Cognito כאשר AUTH_MODE=none.

Postgres הוא מקור האמת. לכן זו אפליקציית תקציב מעשית מבוססת Postgres למפתחים: אפשר לבדוק את המיגרציות, להבין את הקשרים בין הטבלאות, להריץ שאילתות על מסד הנתונים שלכם ולייצא אותו בכלים סטנדרטיים של Postgres. אבטחה ברמת השורה ותפקידי אפליקציה נפרדים עדיין חשובים בתוך האפליקציה, אך אינם מחליפים אבטחה של המחשב המארח או גיבויים.

שירות הרקע של שערי החליפין שולח בקשות יוצאות לקבלת נתוני שערים. הוא אינו צריך לשלוח את שורות פנקס התנועות שלכם כדי לבקש את השערים הציבוריים האלה. ליכולות ה-AI האופציונליות יש גבול אחר, שראוי לבדוק בנפרד.

צרו גיבוי אמיתי לפני שתחשבו שהנתונים מוגנים

במסד הנתונים המקומי שמוגדר כברירת מחדל ב-Compose, הפקודה הזו יוצרת במחשב המארח ארכיון Postgres דחוס:

AUTH_MODE=none docker compose -f infra/docker/compose.yml exec -T postgres \
  pg_dump -U tracker -d tracker --format=custom \
  > expense-budget-tracker.dump

טפלו בקובץ הזה כפי שהייתם מטפלים בדף חשבון בנק. הוא עשוי להכיל תיאורי תנועות, יתרות, קטגוריות, הערות ופרטים מזהים אחרים.

שגרת גיבוי מעשית מחייבת ארבע החלטות:

  1. תדירות: החליטו כמה עבודה מהתקופה האחרונה תוכלו להרשות לעצמכם לאבד.
  2. מיקום שני: העתיקו את קובץ ה-dump הרחק ממארח ה-Docker, כדי שכשל בדיסק יחיד לא ימחק את שני העותקים.
  3. הצפנה וגישה: הגנו על הארכיון בזמן האחסון והגבילו את הרשאים לקרוא אותו.
  4. בדיקת שחזור: שחזרו מדי פעם למופע Postgres תואם ונפרד, ואמתו את התנועות, התקציבים והיתרות.

לפני עדכון האפליקציה, צרו dump חדש. לאחר מכן משכו את הקוד החדש, בנו מחדש את קובצי ה-image של הקונטיינרים והפעילו שוב את המחסנית:

git pull
AUTH_MODE=none make build
AUTH_MODE=none make up

קונטיינר המיגרציה פועל בזמן ההפעלה. קראו את השינויים בכל גרסה לפני השדרוג, ושמרו את ה-dump מלפני השדרוג עד שתבדקו את האפליקציה ותשלימו תרגיל שחזור.

אירוח עצמי לא משאיר כל בייט במחשב באופן אוטומטי

ממשק הווב המקומי הראשי ומסד הנתונים Postgres יכולים לפעול במחשב שלכם. נתונים יוצאים מהסביבה המקומית כאשר אתם בוחרים ביכולת או בנקודת קצה ששולחת אותם למקום אחר.

צ׳אט AI מובנה

הצ׳אט המובנה משתמש ב-OPENAI_API_KEY. כשאתם משתמשים בו, פרומפטים, תוכן מצורף או תוכן שחולץ וההקשר הפיננסי שנדרש לקריאות למודל עשויים להגיע אל OpenAI. נתיב הבקשה הנוכחי מגדיר store: false, אך הספק עדיין צריך לעבד את הבקשה, ובקרות שמירה אחרות תלויות בארגון ה-API שלכם. לפני שליחת דפי חשבון בנק או פרטי פנקס תנועות, עיינו ב-בקרות הנתונים העדכניות של OpenAI ל-API.

מעקב באמצעות Langfuse הוא אופציונלי. הוא מופעל רק כאשר ערכי החיבור וערך שמזהה את הגרסה מוגדרים יחד. כשהוא פעיל, נתוני המעקב אחר הצ׳אט מיוצאים אל LANGFUSE_BASE_URL שבחרתם. כתובת Langfuse Cloud מוסיפה גורם חיצוני נוסף שמעבד נתונים; פריסת Langfuse באירוח עצמי מעבירה את היעד הזה לתשתית שאתם מפעילים.

אם הדרישה שלכם היא ״שורות פיננסיות לעולם לא נשלחות לספק LLM״, אל תגדירו את אינטגרציית ה-AI ואל תשתמשו בצ׳אט. אירוח עצמי של מסד הנתונים אינו מונע בקשה יוצאת למודל שהפעלתם במכוון.

פריסת AWS משלכם

פריסת AWS המתועדת מציבה את שירותי האפליקציה ואת RDS בחשבון AWS שלכם. היא מוסיפה גם מערכות נוספות וגורמים נוספים שצריך לתת בהם אמון: Cloudflare ל-DNS ולתעבורה בקצה הרשת, Cognito לאימות, Resend לשליחת אימיילים להתחברות, תעודות לדומיינים ציבוריים, Secrets Manager, ניטור וחיבורים אופציונליים ל-OpenAI ול-Langfuse.

מחסנית ה-CDK כוללת תשתית מנוהלת לגיבוי מסד הנתונים. אתם עדיין מחליטים אם תקופת השמירה שלה עונה על הצרכים שלכם, מנטרים תקלות, בודקים שחזורים, מחליפים סודות, מתקינים עדכונים ומגיבים לתקריות. ״חשבון AWS שלי״ הוא תחום שליטה שימושי, אך אינו זהה ל״ללא צדדים שלישיים״.

ממשק מנוהל, MCP מתארח ו-Agent API מתארח

הממשק המנוהל מתחיל ב-app.expense-budget-tracker.com. זו האפשרות שדורשת הכי מעט עבודת תפעול, אך הנתונים אינם נשארים רק אצלכם: מפעיל השירות וספקי האירוח הם חלק מהמערכת שמטפלת בהם. קראו את מדיניות הפרטיות לפני שתזינו שם נתונים פיננסיים אמיתיים.

לקוח שתומך ב-MCP יכול להתחבר אל:

https://mcp.expense-budget-tracker.com/mcp

מחבר ה-MCP המתארח משתמש ב-OAuth דרך הדפדפן. היקף ההרשאה הנדרש expenses:read מאפשר לגלות סביבות עבודה, לבדוק את סכמת מסד הנתונים ולהריץ שאילתות קריאה. expenses:write הוא היקף נפרד שנדרש עבור sql_execute. התחילו בגישה לקריאה בלבד, אלא אם הלקוח באמת צריך ליצור רשומות פיננסיות, לשנות אותן או למחוק אותן. גם לקוח ה-MCP יכול לקבל את הנתונים שהכלים מחזירים, ולכן מדיניות הפרטיות שלו חשובה. לתהליך המלא, עיינו ב-המדריך למחבר MCP.

ה-Agent API המתארח הוא ממשק אחר עם פרטי הזדהות אחרים. התחילו בפקודה:

curl --fail --silent --show-error \
  https://api.expense-budget-tracker.com/v1/

אחרי שתהליך ההצטרפות באמצעות קוד באימייל מחזיר מפתח לטווח ארוך, בקשות ישירות משתמשות ב:

Authorization: ApiKey <key>

נקודות הקצה העיקריות ל-SQL מפרידות במכוון בין פעולת קריאה אחת לפעולת כתיבה מאושרת אחת:

  • POST /v1/sql/query מקבלת שאילתת SELECT מוגבלת אחת או שאילתת WITH ... SELECT מוגבלת אחת.
  • POST /v1/sql/execute מקבלת פקודת INSERT,‏ UPDATE או DELETE מאושרת אחת.

בחירת סביבת העבודה והאבטחה ברמת השורה של Postgres חלות בשרת. הן אינן הופכות בקשה אל השירות המתארח לבקשה אל מערכת באירוח עצמי, וה-ApiKey אינו מתקבל בנקודת הקצה של MCP שמבוססת על OAuth. תיעוד ה-API מפרט את תהליך הגילוי, בחירת סביבת העבודה, בדיקת סכמת מסד הנתונים, מגבלות הבקשות ומדיניות ה-SQL המדויקת. המדריך ל-API למעקב אחר הוצאות מעמיק יותר באישור ובהתאמה החשבונאית.

האחריות שאתם מקבלים על עצמכם באירוח עצמי

מנקודת המבט של האפליקציה, ניהול פיננסים אישיים למפתחים עשוי להיראות פשוט למדי: מאגר אחד, פקודת Compose אחת ומסד נתונים אחד. עבודת התפעול אינה מסתיימת אחרי שהעמוד הראשון נטען בהצלחה.

ב-Docker מקומי, אתם אחראים על:

  • עדכונים ל-Docker ולמערכת ההפעלה של המחשב המארח;
  • עדכוני האפליקציה ובדיקת המיגרציות;
  • קובצי dump של מסד הנתונים, עותקים מוצפנים מחוץ למחשב, משך שמירה ובדיקות שחזור;
  • קיבולת הדיסק ותקינות הקונטיינרים;
  • כללי חומת האש והגישה הפיזית למחשב;
  • הגנה על קובצי .env, מפתחות API, מפתחות למודלים וגיבויים.

בפריסה ציבורית, הוסיפו גם:

  • דומיין והגדרת DNS;
  • תעודות TLS ותהליכי חידוש;
  • גישה מאומתת במקום AUTH_MODE=none;
  • משלוח קודי אימות חד-פעמיים באימייל ופרטי הגישה הנדרשים לכך;
  • ניטור מסד הנתונים והשירותים;
  • טיפול בהתראות, תגובה לתקריות ושחזור;
  • עלויות ענן ואבטחת חשבונות אצל הספקים.

המדריך לאירוח עצמי הוא מדריך ההקמה הקצר. תיעוד הפריסה במאגר קוד המקור הוא המקור הקובע לארכיטקטורת AWS הנתמכת.

רשימת בדיקה מעשית לקבלת החלטה

כלי באירוח עצמי למעקב אחר הוצאות מתאים לכם אם רוב המשפטים האלה נכונים:

  • נוח לכם לקחת אחריות שוטפת על Docker ועל Postgres, ולא רק להפעיל אותם פעם אחת.
  • תבצעו גיבויים אוטומטיים ותבדקו שחזור, ולא רק תסמכו על ה-volume.
  • אתם רוצים גישה ישירה למסד נתונים סטנדרטי ולקוד מקור שתוכלו לבדוק או לשנות.
  • גישה מקומית בדפדפן מספיקה לכם, או שאתם מוכנים להפעיל את מחסנית AWS המתועדת.
  • אתם יכולים להבטיח ש-AUTH_MODE=none לא יהיה חשוף לרשתות ציבוריות.
  • תבדקו כל נתיב יוצא אופציונלי, ובמיוחד צ׳אט AI וטלמטריה.

השתמשו באפליקציה המנוהלת או באפשרות מתארחת אחרת אם המשפטים הבאים מדויקים יותר עבורכם:

  • אתם רוצים להזין ולבדוק נתונים פיננסיים בלי לתחזק תשתית.
  • אתם זקוקים לגישה מרחוק אמינה, אך אינכם רוצים לנהל דומיינים, TLS, אימות, אימייל, סודות וניטור.
  • לא סביר שתבחינו בגיבוי שנכשל או בעדכון אבטחה שהתעכב.
  • MCP עם היקפי הרשאה ב-OAuth או ה-Agent API המתארח עונים על צורכי האינטגרציה שלכם בלי להפעיל את המחסנית כולה.

יש גם אפשרות ביניים שימושית: הפעילו את המערכת המקומית ללא מפתחות AI, השאירו אותה מחוץ לאינטרנט הציבורי וייצאו גיבויי Postgres מוצפנים לאחסון שבשליטתכם. כך תקבלו את היתרון המרכזי של כלי למעקב תקציב באירוח עצמי, בלי להתייחס לקובץ Compose במחשב נייד כאילו הוא פלטפורמת ייצור.

התחילו ב-AUTH_MODE=none make up, הזינו כמה תנועות בדיקה שאינן רגישות, עצרו והפעילו מחדש את המחסנית, ואז צרו ואמתו dump של מסד הנתונים. אם מחזור התפעול הקטן הזה נראה לכם סביר, העבירו אל המערכת נתונים אמיתיים. אם הוא כבר מרגיש כמו מטלה, כנראה נכון יותר לבחור ב-אפשרות המנוהלת.

להמשך קריאה