בריפו אין קובץ .sql של הסכמה. מבנה המסד מתגבש משלוש דרכים שפועלות יחד: סנכרון מהשרת הראשי בכל עדכון גרסה, טבלאות שהקוד יוצר לעצמו כשצריך אותן, וכלי יצירה ידניים. הדף מסביר כל אחת, ונותן את הסדר המומלץ להקמת אתר חדש ואת ה-SQL המינימלי שחייבים להריץ בעצמכם.
בעמוד הזה system/ הוא תיקיית הליבה הפרוסה (= api/core בריפו) ו-{admin} הוא CONFIG::$admin_url של האתר.
דרך 1: סנכרון מבנה בעדכון גרסה#
wizzo_update.php::update_db() רצה כחלק מ"עדכון גרסה" בפאנל. היא מורידה מהשרת הראשי את מבנה המסד (https://wizzocms40.wizzo.co.il/system/check_version/db_structure) ומשווה אותו למסד המקומי:
| מצב | מה היא עושה |
|---|---|
| טבלה חסרה | CREATE TABLE בקידוד utf8mb4 ו-collation utf8mb4_general_ci |
| עמודה חסרה | ALTER TABLE ... ADD ומחיקת המטמון table_columns_<table> |
| עמודה קיימת עם סוג צר יותר | הרחבה (safe_widen) רק כשהיא בטוחה ואינה מאבדת נתונים |
| אינדקס חסר | נוסף לפי שם, או מדולג אם קיים כבר אינדקס על אותן עמודות |
| collation של המסד | ensure_db_collation() מעדכנת את ברירת המחדל של המסד ל-utf8mb4_general_ci |
הטבלאות שמוחרגות מהסנכרון: CRM_trg_*, CRM_users, CRM_buttons*, CRM_newsletter_*.
המבנה המיוצא כולל לכל עמודה COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT ו-EXTRA, אבל לא COLUMN_KEY. ה-PRIMARY KEY נוצר בשלב סנכרון האינדקסים (ALTER TABLE ADD PRIMARY KEY), וה-AUTO_INCREMENT נוסף אחריו ב-MODIFY אם חסר. טבלה שנוצרה בדרך הזאת עלולה להיות בלי PK עד שהשלב השני מסתיים.
שגיאות בשלב הזה לא עוצרות את העדכון: פקודה שנכשלה מחזירה false, מודפסת הודעה כמו Error creating table ..., והעדכון ממשיך לטבלה הבאה. בדקו את פלט העדכון.
update_db() לא יכולה ליצור את מה שעדיין לא קיים כדי להריץ את האתר עד לפאנל. לכן בהקמה ראשונה צריך להריץ ידנית לפחות את הטבלאות והשורות שבסעיף "הקמה ראשונה".
סנכרון משימות ה-cron#
באותו עדכון, update_cron_system() מסנכרנת משימות מערכת (קטגוריה id=1) מ-.../system/check_version/cron_system. ההתאמה היא לפי url|params, משימות שנעלמו מהשרת הראשי נמחקות מקומית, ו-last_run, next_run ו-runs_count נשמרים.
דרך 2: יצירה עצלה בקוד#
ספריות ופאנלים רבים בודקים בזמן ריצה אם הטבלה שלהם קיימת, ויוצרים אותה אם לא (ensure_* או CREATE TABLE IF NOT EXISTS). דוגמה אמיתית, CRM_adminPanel_sessions:
CREATE TABLE CRM_adminPanel_sessions (
id INT AUTO_INCREMENT PRIMARY KEY,
admin_id INT NOT NULL,
token VARCHAR(64) NOT NULL,
ip VARCHAR(45) NOT NULL DEFAULT '',
user_agent VARCHAR(255) NOT NULL DEFAULT '',
device_label VARCHAR(100) NOT NULL DEFAULT '',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_active_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME NOT NULL,
is_impersonated TINYINT(1) NOT NULL DEFAULT 0,
impersonated_by INT DEFAULT NULL,
UNIQUE KEY idx_token (token),
KEY idx_admin_id (admin_id),
KEY idx_expires (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
כך נוצרות בין השאר: adminPanel_sessions, wizzo_update_log, seo_*, ai_agents*, admin_chat ו-file_manager_log. היצירה העצלה דורשת שלמשתמש המסד יש הרשאות CREATE ו-ALTER, אחרת הכשל נרשם ב-error_log בלבד.
דרך 3: כלים ידניים#
| כלי | מה הוא עושה |
|---|---|
פאנל create_table | בונה טבלה CRM_<name> עם id INT AUTO_INCREMENT PRIMARY KEY ורושם אותה כפאנל ניהול |
פאנל safe_sql | מריץ רק CREATE TABLE, CREATE INDEX, CREATE UNIQUE INDEX ו-ALTER TABLE ... ADD. ראו מנהל מסד הנתונים |
פאנל db_manager | יצירת טבלאות, עמודות ואינדקסים בכל צורה, ללא הגבלה |
הקובץ api/core/admin/install_db_manager.php מנסה לרשום את הפאנל עם DB::insert("adminPanel_panels"), מתודה שלא קיימת. רישום פאנל נעשה בהוספת שורה ל-CRM_adminPanel_panels (ראו הדוגמה למטה, ו-בניית פאנל).
הקמה ראשונה: סדר פעולות#
- צרו מסד נתונים בקידוד
utf8mb4ומשתמש עם הרשאותCREATE,ALTER,INSERT,UPDATE,DELETE,SELECT,INDEX. - הגדירו את פרטי החיבור (
CONFIG). ראו תצורה. - צרו ידנית את הטבלאות הקריטיות והשורות הראשונות (למטה), או העתיקו מסד של אתר תבנית.
- היכנסו לאדמין והריצו עדכון גרסה (עדכוני גרסה). הוא משלים את שאר הטבלאות, העמודות והאינדקסים.
- נקו מטמון (ראו ניקוי ותחזוקה).
טבלאות מינימליות#
המבנים שלהלן נגזרו מהאופן שבו הקוד קורא את הטבלאות. סוגי העמודות ואורכיהן הם הצעה סבירה, לא העתק של מבנה השרת הראשי. אחרי עדכון גרסה ראשון, update_db() תרחיב ותשלים מה שחסר.
SET NAMES utf8mb4;
SET sql_mode = '';
CREATE TABLE `CRM_platforms` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain` VARCHAR(255) NOT NULL,
`allowed_domains` TEXT NULL,
`name` VARCHAR(100) NOT NULL DEFAULT '',
`direction` VARCHAR(3) NOT NULL DEFAULT 'rtl',
`ord` INT NOT NULL DEFAULT 0,
`seo_title` VARCHAR(255) NOT NULL DEFAULT '',
`seo_keywords` TEXT NULL,
`seo_description` TEXT NULL,
`deftheme` VARCHAR(50) NOT NULL DEFAULT 'default',
PRIMARY KEY (`id`),
UNIQUE KEY `uq_domain` (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `CRM_params` (
`id` INT NOT NULL AUTO_INCREMENT,
`sysName` VARCHAR(100) NOT NULL,
`value` TEXT NULL,
`description` TEXT NULL,
`perm_developer` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_sysname` (`sysName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ואחריהן שורות ההתחלה:
-- פלטפורמה ראשונה (= שפה 1). domain חייב להיות בדיוק SERVER_NAME
INSERT INTO CRM_platforms (id, domain, allowed_domains, name, direction, ord, seo_title, deftheme)
VALUES (1, 'www.example.com', '|example.com||localhost|', 'עברית', 'rtl', 1, 'האתר שלי', 'default');
-- פרמטרים שהליבה קוראת תמיד
INSERT INTO CRM_params (sysName, value, description, perm_developer) VALUES
('attaches_version', '1', 'cache-buster לנכסים', 1),
('log_sql', '0', '1 = לוג כל שאילתה', 1),
('cron_runner_token', REPLACE(UUID(),'-',''), 'טוקן לריצת cron_runner', 1);
deftheme יכול להכיל רק [A-Za-z0-9_], כי הוא הופך לשם מחלקה TEMPLATE_<deftheme>.
כניסה ראשונה לאדמין#
כדי להיכנס צריך גם קבוצה, מנהל ופאנלים. הדוגמה למטה ממחישה את הצורה (טבלאות האדמין נוצרות ב-update_db, או ידנית לפי כל הטבלאות). את ה-hash של הסיסמה מייצרים ב-bcrypt:
echo password_hash($plainPassword, PASSWORD_BCRYPT); // מתחיל ב-$2y$
INSERT INTO CRM_adminPanel_admins_groups (id, name, perms) VALUES (1, 'מנהלים ראשיים', '-1');
INSERT INTO CRM_adminPanel_admins (uname, password, name, email, group_id, skip_otp)
VALUES ('admin', '<BCRYPT_HASH>', 'Admin', 'admin@example.com', 1, 1);
INSERT INTO CRM_adminPanel_panels_categories (id, name, ord) VALUES (3, 'כלים למפתחים', 9);
INSERT INTO CRM_adminPanel_panels (category, panel_name, text, icon, ord, perm_developer)
VALUES (3, 'db_manager', 'מנהל מסד נתונים', '<i class="fa fa-database"></i>', 2, 1);
panel_name הוא שם הקובץ שבתיקיית הפאנלים (api/core/admin/<panel_name>.php, או application/admin/ באתר) והוא רגיש לאותיות גדולות וקטנות בלינוקס. skip_otp = 1 מדלג על קוד חד-פעמי במייל או SMS. כבו אותו אחרי הכניסה הראשונה.
אל תשמרו סיסמה גלויה במסד ואל תשאירו מנהל עם סיסמה ידועה מראש. החליפו אותה מיד אחרי הכניסה הראשונה.
אחרי יצירה ידנית: ניקוי מטמונים#
שלושה נתונים נשמרים במטמון ימים רבים, ושינוי ישיר ב-SQL לא יופיע עד שמוחקים אותם:
| מפתח | TTL | מתי למחוק |
|---|---|---|
platforms | 30 יום | הוספת דומיין או שינוי פלטפורמה |
params | 30 יום | שינוי ב-CRM_params |
table_list | 7 ימים | יצירת טבלה (כולל _content) |
cache_engine::remove("platforms");
cache_engine::remove("params");
cache_engine::remove("table_list");
או מהאדמין: ניקוי ותחזוקה.