הערה: כאשר פאנל הניהול הסטנדרטי נוקשה מדי, ופיתוח מותאם אישית יקר מדי, AdminJS (ראו מאגר GitHub) מציע פתרון ביניים מושלם. אבל מחוץ לקופסה, הוא לרוב לא מכסה חוקים עסקיים מורכבים: פעולות מותאמות אישית, העלאת קבצים, גישת מבוססת תפקידים. פיתחנו פאנלי ניהול על AdminJS למסחר אלקטרוני, לוגיסטיקה ו-SaaS עם יותר מ-20 פרויקטים מאחורינו. פעם אחת, עבור רשת קמעונאית, יישמנו פעולה מותאמת אישית לשינוי מחירים בכמות גדולה — עיבוד 5,000 מוצרים ב-30 שניות. במאמר זה, נשתף כיצד להתאים את AdminJS, אילו כלים אנו משתמשים בהם, והיכן גבולות האפשרויות.
אילו בעיות AdminJS פותר?
AdminJS מייצר ממשק CRUD על בסיס מודלי נתונים. הוא מתאים להשקה מהירה של פאנל ניהול אך דורש עידון לתרחישים לא סטנדרטיים. הנה האתגרים המרכזיים שאנו מטפלים בהם:
- פעולות מותאמות אישית — שליחת דואר בכמות גדולה, הפקת דוחות, אינטגרציה עם APIs חיצוניים. לדוגמה, עבור סטארטאפ לוגיסטי, הוספנו פעולה ליצירת שטרי מטען אוטומטית, עיבוד 10,000 רשומות בדקה.
- העלאת קבצים — דרך
@adminjs/uploadעם S3 או אחסון מקומי. אנו תומכים ביצירת תצוגות מקדימות ותמונות ממוזערות אוטומטית לתמונות מוצר. - זכויות גישה — מבוססות תפקיד ופעולה (צפייה, עריכה, מחיקה). אנו מגדירים מודל תפקידים על בסיס
currentAdmin.roleעם הרשאות מדורגות. - רכיבים מותאמים אישית — החלפת שדות סטנדרטיים בווידג'טים של React: datepicker, autocomplete, עורכי WYSIWYG. עבור לקוח אחד, פיתחנו רכיב בחירת מחסן עם מיקום גיאוגרפי.
- ביצועים — אופטימיזציה של שאילתות לטבלאות עם 100k+ רשומות: הוספת אינדקסים, שימוש בסינון בצד השרת, חיבור Elasticsearch לחיפוש טקסט מלא.
כיצד להתאים את AdminJS לדרישות עסקיות?
טכנולוגיות: Node.js, TypeScript, React 18, AdminJS 7.x, TypeORM / Prisma. פריסה — Docker, Nginx, Vercel.
שקול דוגמה: חנות מקוונת עם מוצרים, הזמנות ולקוחות. הגדרת AdminJS בסיסית עם אימות והרשאות מותאמות אישית:
דוגמת קוד להגדרת AdminJS
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';
import { Database, Resource, getModelByName } from '@adminjs/typeorm';
AdminJS.registerAdapter({ Database, Resource });
const adminJs = new AdminJS({
resources: [
{
resource: getModelByName('User'),
options: {
properties: {
password: {
isVisible: {
list: false,
edit: false,
filter: false,
show: false
}
},
createdAt: {
isVisible: {
edit: false
}
}
},
actions: {
delete: {
isAccessible: ({ currentAdmin }) => currentAdmin?.role === 'superadmin'
}
}
}
},
{
resource: getModelByName('Order'),
options: {
listProperties: ['id', 'customer', 'status', 'total', 'createdAt'],
filterProperties: ['status', 'createdAt'],
sort: {
sortBy: 'createdAt',
direction: 'desc'
}
}
}
],
dashboard: {
component: AdminJS.bundle('./components/Dashboard')
},
branding: {
companyName: 'Мой Магазин',
logo: '/admin-logo.svg'
}
});
const router = AdminJSExpress.buildAuthenticatedRouter(adminJs, {
authenticate: async (email, password) => {
const admin = await Admin.findOne({ email });
if (admin && await bcrypt.compare(password, admin.passwordHash)) {
return admin;
}
return null;
},
cookiePassword: process.env.COOKIE_SECRET
});
רכיב מותאם אישית להצגת סטטוס הזמנה עם צבע:
import { BasePropertyProps } from 'adminjs';
const OrderStatusCell: React.FC<BasePropertyProps> = ({ record }) => {
const status = record.params.status;
const colors = {
pending: 'orange',
completed: 'green',
cancelled: 'red'
};
return <span style={{ color: colors[status] }}>{status}</span>;
};
export default OrderStatusCell;העלאת תמונות מוצר ל-S3 דרך import AdminJS from 'adminjs'; import AdminJSExpress from '@adminjs/express'; import { Database, Resource, getModelByName } from '@adminjs/typeorm'; AdminJS.registerAdapter({ Database, Resource }); const adminJs = new AdminJS({ resources: [ { resource: getModelByName('User'), options: { properties: { password: { isVisible: { list: false, edit: false, filter: false, show: false } }, createdAt: { isVisible: { edit: false } } }, actions: { delete: { isAccessible: ({ currentAdmin }) => currentAdmin?.role === 'superadmin' } } } }, { resource: getModelByName('Order'), options: { listProperties: ['id', 'customer', 'status', 'total', 'createdAt'], filterProperties: ['status', 'createdAt'], sort: { sortBy: 'createdAt', direction: 'desc' } } } ], dashboard: { component: AdminJS.bundle('./components/Dashboard') }, branding: { companyName: 'Мой Магазин', logo: '/admin-logo.svg' } }); const router = AdminJSExpress.buildAuthenticatedRouter(adminJs, { authenticate: async (email, password) => { const admin = await Admin.findOne({ email }); if (admin && await bcrypt.compare(password, admin.passwordHash)) { return admin; } return null; }, cookiePassword: process.env.COOKIE_SECRET }); :
import uploadFeature from '@adminjs/upload';
import { s3Client } from './s3-client';
{
resource: getModelByName('Product'),
features: [
uploadFeature({
provider: {
aws: {
bucket: 'my-bucket',
s3Client
}
},
properties: {
file: 'imageFile',
filePath: 'imageUrl',
filename: 'imageName',
mimeType: 'imageMimeType'
},
uploadPath: (record, filename) => `products/${record.id()}/${filename}`
})
]
} מדוע AdminJS חוסך עד 60% זמן ותקציב?
כתיבת פאנל ניהול מאפס על React ו-Express אורכת כ-3–4 שבועות עבור CRUD טיפוסי. AdminJS מקצר זאת ל-1–2 שבועות, שזה פי 2-3 מהר יותר. עבור פרויקטים עם 10+ ישויות, חיסכון בזמן מגיע ל-60%, ובהתאם חיסכון בתקציב. כאשר מוסיפים רכיבים מותאמים אישית, החיסכון נשאר ב-30–40%.
לפי התיעוד הרשמי של AdminJS, המסגרת תומכת בכל ה-ORMs הפופולריים ומאיצה פיתוח על ידי יצירת ממשק ממודלים. אבל חשוב להבין: הגרסה מחוץ לקופסה מספקת פונקציונליות בסיסית, והחיסכון האמיתי מגיע עם הגדרה והתאמה נכונה.
| ORM | מהירות פיתוח | מורכבות התאמה |
|---|---|---|
| TypeORM | גבוהה | נמוכה |
| Prisma | בינונית | בינונית |
| Mongoose | גבוהה | נמוכה |
| Sequelize | בינונית | בינונית |
מה לעשות אם ביצועי AdminJS לא מספקים?
עבור טבלאות עם 100k+ רשומות, מנגנונים סטנדרטיים עלולים להאט. אנו מיישמים מספר גישות. ראשית, סינון בצד השרת: כל הסינונים מבוצעים בצד מסד הנתונים, לא בצד הפרונטאנד. שנית, אינדוקס שדות שנשאלים לעתים קרובות. שלישית, הימנעות מ-import { BasePropertyProps } from 'adminjs'; const OrderStatusCell: React.FC<BasePropertyProps> = ({ record }) => { const status = record.params.status; const colors = { pending: 'orange', completed: 'green', cancelled: 'red' }; return <span style={{ color: colors[status] }}>{status}</span>; }; export default OrderStatusCell; עם טעינת כל הישויות הקשורות; אנו משתמשים ב-QueryBuilder עם select בלבד. במקרים קיצוניים, אנו מחברים Elasticsearch לחיפוש טקסט מלא.
דוגמת אופטימיזציה: בפרויקט אחד, טבלת הזמנות (200k רשומות) נפתחה ב-5 שניות. לאחר הוספת אינדקס מורכב על @adminjs/upload וסינון לפי סטטוס, זמן הטעינה ירד ל-200 אלפיות השנייה.
כיצד אנו מפתחים את פאנל הניהול?
| שלב | זמן (ימים) |
|---|---|
| אנליזה | 1 |
| עיצוב | 1-2 |
| יישום | 5-10 |
| בדיקות | 2-3 |
| פריסה | 1 |
- אנליזה — חקר מבנה הנתונים, תהליכים עסקיים, זכויות גישה. הערכת היקף ביום אחד.
- עיצוב — הגדרת משאבים, פעולות, רכיבים, תכנית הרשאות.
- יישום — הגדרת AdminJS, כתיבת רכיבים ופעולות מותאמים אישית, אינטגרציה עם שירותים חיצוניים.
- בדיקות — אימות תרחישים, בדיקות עומס (עד 10,000 בקשות).
- פריסה ותיעוד — פריסה על השרת שלך, מתן הוראות למנהלים.
מה כלול בתוצאה
- פאנל ניהול מלא על AdminJS עם אימות.
- רכיבים ופעולות מותאמים אישית לפי המפרט שלך.
- אינטגרציה עם העלאת קבצים (S3, MinIO).
- הפרדת זכויות גישה (תפקידים, פעולות).
- קוד מקור, תיעוד, הוראות פריסה.
- אחריות ל-6 חודשים על באגים שזוהו.
עבור פרויקטים פשוטים, AdminJS מקצר את זמן פיתוח פאנל הניהול ב-60% בהשוואה לכתיבה מאפס. צרו קשר כדי לדון בפרויקט שלכם — קבלו ייעוץ והערכה ראשונית תוך יום אחד. הזמינו פיתוח פאנל ניהול על AdminJS.







