מערכת ניהול זמן וחיוב לפרילנסרים - ניהול לקוחות, פרויקטים, משימות ומעקב שעות עבודה.
- 👤 הרשמה והתחברות - מערכת משתמשים מאובטחת
- 👥 ניהול לקוחות - שם, כתובת, טלפון, פרטי בנק, ח.פ
- 📁 ניהול פרויקטים - מחיר קבוע או לפי שעה
- ✅ ניהול משימות - בתוך כל פרויקט עם סטטוסים
- ⏱️ טיימר עבודה - מעקב זמנים עם אינטרוולים
- 💰 תמחור מדורג - מחשבון → לקוח → פרויקט → משימה
- 🔗 שיתוף ללקוח - לינק לצפייה בסטטוס הפרויקטים
- 📊 סטטיסטיקות - בכל מסך מוצגים נתונים רלוונטיים
- Node.js + Express
- SQLite (better-sqlite3)
- JWT Authentication
- bcryptjs
- React 18 + Vite
- React Router v6
- Zustand (State Management)
- CSS מותאם אישית (RTL)
# התקנת כל התלויות (root + client + server + desktop)
npm run install:all
# יצירת קובץ הסביבה של השרת (חובה - השרת לא יעלה בלעדיו)
cp server/.env.example server/.env
printf 'JWT_SECRET=%s\nENCRYPTION_SECRET=%s\n' "$(openssl rand -hex 32)" "$(openssl rand -hex 32)" > server/.env
# הפעלת פיתוח (שרת + קליינט)
npm run devבריצה הראשונה השרת יוצר אוטומטית את server/clockwize.db עם כל הסכמה ומשתמש אדמין ברירת-מחדל.
- Frontend (פיתוח): http://localhost:5001 (Vite; פורט 5000 תפוס ב-macOS)
- Backend API: http://localhost:3000 (אם תפוס - הפורט הפנוי הבא, נשמר ב-
.server-port)
אפליקציה אמיתית עם חלון, אייקון ב-Dock, טיימר בשורת התפריט, ווידג'ט למרכז העדכונים ו-Control ל-Control Center / שורת התפריט.
npm run desktop:install # בונה ומתקין את /Applications/Clockwize.app (מגבה את ה-DB לפני כן)
npm run desktop # הרצת פיתוח, בפרופיל נפרד ("Clockwize Dev") ליד האפליקציה המותקנת- השרת רץ בתוך האפליקציה (Electron utilityProcess, ה-Node המובנה - אין צורך ב-Node במערכת), מתוך תיקיית הפרויקט, עם אותו
server/clockwize.db,server/.envו-uploads/. החלון טוען את ה-client הבנוי (client/dist) מאותו שרת - אחרי שינוי ב-client מספיקnpm run build. - שרת אחד לכל DB: קובץ נעילה (
clockwize.db.lock) מונע משני שרתים לדרוס זה את זה. אםnpm run devכבר רץ, האפליקציה מתחברת אליו; ו-npm run devשמופעל כשהאפליקציה פתוחה מודיע על כך, וה-client של הפיתוח עובד מול השרת של האפליקציה. - סגירת החלון לא מכבה את האפליקציה (הטיימר ממשיך); לחיצה על האייקון ב-Dock מחזירה אותו, ו-⌘Q יוצא ועוצר את השרת.
- שורת התפריט: לחיצה על השעון פותחת חלונית עם הטיימר החי, השהה/המשך/עצור, סיכום היום והשבוע והפעלה מהירה של עבודה אחרונה. קליק ימני - תפריט קצר.
- ווידג'ט ו-Control (
desktop/widget, WidgetKit): נבנים ונחתמים אוטומטית ב-desktop:installכשיש Xcode ותעודת חתימה במחזיק המפתחות; אחרת האפליקציה מותקנת בלעדיהם. הווידג'ט קורא את המצב מהאפליקציה דרך ערוץ מקומי (127.0.0.1) עם סוד שנוצר בכל התקנה, ולא מקבל את טוקן המשתמש. - Passkey: Electron לא יכול להציג את חלונית ה-Passkey של macOS, ולכן הכפתור באפליקציה פותח את ההתחברות בדפדפן; אחרי האישור שם האפליקציה מתחברת לבד.
- נשארים מחוברים: ההתחברות מתחדשת לבד (מתנתקים רק אחרי שנה בלי שימוש, או כשהסיסמה משתנה). אם השרת לא זמין לרגע, האפליקציה מנסה שוב במקום לנתק.
- נעילת Touch ID: בפתיחת האפליקציה היא מבקשת טביעת אצבע (תפריט Clockwize ← "נעילה עם Touch ID בפתיחה" כדי לכבות).
- לוג השרת:
~/Library/Logs/Clockwize/server.log(גם מהתפריט Clockwize ← "פתח את קובץ הלוג של השרת").
npm --prefix server test # vitest + supertest על DB בזיכרון (כולל בידוד בין workspaces)
npm --prefix client test # vitest + Testing Library (utils, store, api, קומפוננטות)
npm run build && npm run test:e2e # Playwright מול שרת זמני (דסקטופ + מובייל)
npm run test:desktop # Playwright מול אפליקציית ה-Electron עצמה
npm test # שרת + client + e2eהבדיקות לעולם לא נוגעות בנתונים האמיתיים: כל הנתיבים ניתנים להחלפה במשתני סביבה (CLOCKWIZE_DB_PATH, CLOCKWIZE_UPLOADS_DIR, CLOCKWIZE_BACKUP_DIR, CLOCKWIZE_PORT_FILE, CLOCKWIZE_SESSION_FILE, CLOCKWIZE_CLIENT_DIST - ראו server/paths.js). לנתוני דמו לעבודת UI: node server/scripts/seed-demo.js <url> מול שרת על DB זמני.
ה-CI (.github/workflows/ci.yml) מריץ בכל push: בדיקות שרת, בדיקות client ו-build, e2e ב-Playwright, ובדיקות אפליקציית ה-Desktop על macOS.
- JWT_SECRET — חובה ב-
server/.env, לפחות 32 תווים (openssl rand -hex 32). ללא הערך הזה השרת לא עולה. החלפתו מנתקת את כל המשתמשים. - ENCRYPTION_SECRET — חובה ב-
server/.env, לפחות 32 תווים (openssl rand -hex 32). ממנו נגזרים מפתחות ההצפנה של הסיסמאות ומפתחות ה-API של התוספים. בעלייה הראשונה עם ערך חדש השרת מצפין מחדש אוטומטית רשומות שהוצפנו עם המפתח המובנה הישן — מומלץ לגבות אתserver/clockwize.dbלפני כן. - משתמש אדמין — בריצה ראשונה נוצר משתמש
adminעם סיסמהadmin. שנו אותה מיד או מחקו את משתמש האדמין דרך הקוד והרשמו משתמש משלכם. - uploads/ — תיקייה זו לא נכללת ב-git. ודאו backup חיצוני בפרודקשן.
POST /api/auth/register- הרשמהPOST /api/auth/login- התחברותGET /api/auth/me- קבלת פרטי משתמשPUT /api/auth/profile- עדכון פרופילDELETE /api/auth/account- מחיקת חשבון
GET /api/clients- רשימת לקוחותGET /api/clients/:id- פרטי לקוחPOST /api/clients- יצירת לקוחPUT /api/clients/:id- עדכון לקוחDELETE /api/clients/:id- מחיקת לקוחPOST /api/clients/:id/share- יצירת לינק שיתוףDELETE /api/clients/:id/share- הסרת לינק שיתוףGET /api/clients/shared/:token- צפייה בלקוח משותף (ציבורי)
GET /api/projects- רשימת פרויקטיםGET /api/projects/:id- פרטי פרויקטPOST /api/projects- יצירת פרויקטPUT /api/projects/:id- עדכון פרויקטDELETE /api/projects/:id- מחיקת פרויקט
GET /api/tasks- רשימת משימותGET /api/tasks/:id- פרטי משימהPOST /api/tasks- יצירת משימהPUT /api/tasks/:id- עדכון משימהDELETE /api/tasks/:id- מחיקת משימה
GET /api/timer/active- טיימר פעילPOST /api/timer/start- התחלת טיימרPOST /api/timer/pause- השהיית טיימרPOST /api/timer/resume- המשך טיימרPOST /api/timer/stop- עצירה ושמירהDELETE /api/timer/discard- ביטול טיימרGET /api/timer/entries- רשומות זמן
GET /api/stats/dashboard- סטטיסטיקות דשבורדGET /api/stats/client/:id- סטטיסטיקות לקוחGET /api/stats/project/:id- סטטיסטיקות פרויקט
עקרון מרכזי במערכת: כל שינוי בנתונים חייב להשתקף מיידית בממשק המשתמש ללא צורך ברענון ידני של הדפדפן.
- אחרי כל פעולת CRUD (יצירה, עריכה, מחיקה) - קריאה מיידית לפונקציית
load*()לרענון הנתונים - סדר ביצוע:
- ביצוע הפעולה (API call)
- רענון הנתונים (
await loadData()) - הצגת הודעה למשתמש (אם קיימת)
// ✅ נכון - רענון מיידי לפני הודעה
const handleDelete = async (id) => {
await api.delete(id);
await loadData(); // Refresh immediately
alert('נמחק בהצלחה');
};
// ❌ שגוי - הודעה לפני רענון
const handleDelete = async (id) => {
await api.delete(id);
alert('נמחק בהצלחה'); // Blocks UI refresh
loadData();
};- ✅ Clients - יצירה, עריכה, מחיקה, שינוי מועדף
- ✅ Projects - יצירה, עריכה, מחיקה
- ✅ Tasks - יצירה, עריכה, מחיקה, שינוי סטטוס
- ✅ Time Entries - יצירה, עריכה, מחיקה
- ✅ Payments - יצירה, עריכה, מחיקה
- ✅ Admin Panel - כל פעולות ניהול משתמשים
clockwize/
├── client/ # React Frontend
│ ├── src/
│ │ ├── components/ # קומפוננטות משותפות
│ │ ├── pages/ # דפים ראשיים
│ │ ├── services/ # API calls
│ │ ├── store/ # Zustand store
│ │ ├── styles/ # Global CSS
│ │ └── utils/ # פונקציות עזר
│ └── public/
├── server/ # Node.js Backend
│ ├── routes/ # API routes
│ ├── middleware/ # Auth middleware
│ ├── tests/ # vitest + supertest
│ ├── app.js # Express app (createApp)
│ ├── database.js # SQLite setup (sql.js, כתיבה אטומית)
│ ├── paths.js # כל נתיבי הנתונים (ניתנים להחלפה ב-env)
│ └── index.js # הפעלה: נעילת DB + האזנה לפורט
├── desktop/ # אפליקציית macOS (Electron)
│ ├── lib/ # שרת, טיימר, שורת תפריט, ערוץ לווידג'ט
│ ├── widget/ # WidgetKit: ווידג'ט + Control
│ └── tests/ # Playwright מול האפליקציה
├── e2e/ # Playwright מול הדפדפן
└── package.json # Root package.json
MIT