ארכיטקטורת הרשאות ומגבלות הרחבות
המצב היום
| רובד | מה יש | מה חסר |
|---|
| ExtensionAccess | usageCount, usageLimit, expiresAt, isActive | הקפאה+הודעה, תאריך שימוש אחרון |
| ExtensionData | key-value חופשי לנתוני ההרחבה | מבנה, קשר ל-user ספציפי |
| Extension | limitDescription, limitValue | — (כבר קיים) |
מה צריך להוסיף — 3 שדות ב-ExtensionAccess
model ExtensionAccess {
// ... קיים ...
lastUsedAt DateTime? // מתי המשתמש/חברה השתמשו לאחרונה
frozenAt DateTime? // מתי הוקפא (null = לא מוקפא)
frozenReason String? // הודעת הקפאה מהאדמין: "חשבון לא שילם" וכו'
}
Migration SQL:
ALTER TABLE "ExtensionAccess" ADD COLUMN IF NOT EXISTS "lastUsedAt" TIMESTAMP;
ALTER TABLE "ExtensionAccess" ADD COLUMN IF NOT EXISTS "frozenAt" TIMESTAMP;
ALTER TABLE "ExtensionAccess" ADD COLUMN IF NOT EXISTS "frozenReason" TEXT;
מפת כל המגבלות — איפה כל דבר חי
| מגבלה | שדה | טבלה | מי מעדכן | ההרחבה רואה |
|---|
| כמה נוצרו (שימושים) | usageCount | ExtensionAccess | REPORT_USAGE אוטומטי | usageCount בתגובה |
| מקסימום שימושים | usageLimit | ExtensionAccess | אדמין / מועתק מ-Extension.limitValue | usageLimit בתגובה |
| מה סופרים (תיאור) | limitDescription | Extension | אדמין | limitDescription בתגובה |
| תוקף עד תאריך | expiresAt | ExtensionAccess | אדמין / רכישה | expiresAt או error: "EXPIRED" |
| הקפאה | frozenAt | ExtensionAccess | אדמין | error: "FROZEN" |
| הודעת הקפאה | frozenReason | ExtensionAccess | אדמין | reason: "..." |
| שימוש אחרון | lastUsedAt | ExtensionAccess | REPORT_USAGE אוטומטי | — (רק אדמין רואה) |
| נתוני ההרחבה עצמה | key-value | ExtensionData | ההרחבה דרך STORE | ההרחבה קוראת |
זרימה — מה קורה כשהרחבה נטענת
הרחבה נטענת → mount()
↓
Bridge: GET_ACCESS_STATUS (פקודה חדשה)
↓
API בודק ExtensionAccess:
├─ frozenAt != null? → { status: "frozen", reason: "חשבון לא שילם" }
├─ expiresAt < now? → { status: "expired", expiredAt: "14/03/2026" }
├─ usageCount >= limit? → { status: "limit_reached", count: 50, limit: 50, limitDescription: "אנשי קשר" }
└─ הכל טוב → { status: "active", count: 7, limit: 50, limitDescription: "אנשי קשר" }
זרימה — מה קורה כשהרחבה מוסיפה ישות
bridge.send({ type: "REPORT_USAGE", amount: 1 })
↓
API בודק:
├─ frozen? → error: "FROZEN", reason: "..."
├─ expired? → error: "EXPIRED"
├─ limit reached? → error: "LIMIT_REACHED"
└─ OK → usageCount++, lastUsedAt = now()
return { ok: true, usageCount: 8, usageLimit: 50 }
זרימה — אדמין מקפיא
Admin UI → PATCH /api/admin/extensions/{id}/access/{accessId}
body: { frozen: true, frozenReason: "חשבון לא שילם" }
→ frozenAt = now(), frozenReason = "חשבון לא שילם"
בפעם הבאה שההרחבה קוראת GET_ACCESS_STATUS:
→ { status: "frozen", reason: "חשבון לא שילם" }
ההרחבה מציגה: "ההרחבה מושעה: חשבון לא שילם. פנה למנהל."
Bridge command חדש: GET_ACCESS_STATUS
דוגמת שימוש בהרחבה:
bridge.on("GET_ACCESS_STATUS_RESPONSE", function(data) {
if (data.status === "frozen") {
root.innerHTML = "<div class='error'>ההרחבה מושעה: " + data.reason + "</div>";
return;
}
if (data.status === "expired") {
root.innerHTML = "<div class='error'>התוקף פג ב-" + data.expiredAt + "</div>";
return;
}
if (data.status === "limit_reached") {
root.innerHTML = "<div class='error'>הגבלה: " + data.count + "/" + data.limit + " " + data.limitDescription + "</div>";
return;
}
// status === "active" — הכל טוב
initApp(data);
});
bridge.send({ type: "GET_ACCESS_STATUS" });
Response schema:
// active
{ "status": "active", "count": 7, "limit": 50, "limitDescription": "אנשי קשר", "expiresAt": null }
// frozen
{ "status": "frozen", "reason": "חשבון לא שילם" }
// expired
{ "status": "expired", "expiredAt": "14/03/2026" }
// limit_reached
{ "status": "limit_reached", "count": 50, "limit": 50, "limitDescription": "אנשי קשר" }
Admin UI — תצוגת כרטיס הרשאה
┌─────────────────────────────────────────────┐
│ הרחבה: מנהל אנשי קשר │
│ חברה: אלפא בע"מ │
│ │
│ מגבלת שימוש: 7 / 50 אנשי קשר │
│ שימוש אחרון: 14/03/2026 │
│ תוקף: 31/12/2026 │
│ │
│ [🔒 הקפא] [הודעה: ___________] [💀 בטל] │
└─────────────────────────────────────────────┘
רשימת משימות ליישום
| # | פריט | סוג | מאמץ |
|---|
| 1 | 3 שדות ב-ExtensionAccess (lastUsedAt, frozenAt, frozenReason) | Migration | קטן |
| 2 | עדכון REPORT_USAGE — לבדוק frozen/expired + לעדכן lastUsedAt | שינוי route קיים | בינוני |
| 3 | Bridge command GET_ACCESS_STATUS — route חדש + handler ב-iframe | API + Frontend | בינוני |
| 4 | עדכון buildPlatformPrompt.ts להסביר GET_ACCESS_STATUS | Prompt | קטן |
| 5 | Admin UI — כפתור הקפאה, שדה הודעה, תצוגת lastUsedAt | Admin page | בינוני |
| 6 | הוספת GET_ACCESS_STATUS ל-extensionPermissions.ts | Config | קטן |
סה"כ: אין טבלה חדשה. אין שינוי מבני. רק 3 שדות + Bridge command אחד.