סכמות Sanity מותאמות אישית: מסמכים, קשרים, אימות

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

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
סכמות Sanity מותאמות אישית: מסמכים, קשרים, אימות
פשוט
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1307
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

פיתוח סכמות Sanity מותאמות אישית

בעת בניית אתר מסחר אלקטרוני על Sanity, מנהלי תוכן נהגו לבזבז עד 20 דקות בחיפוש השדה הנכון בטופס ארוך. טעינת 50 מוצרים ביום גרמה לשעות של עבודה נוספת. הפתרון: סכמות מותאמות אישית עם קבוצות, ולידציה ויחסים. לפי תיעוד סכמות Sanity, סכמה היא תיאור TypeScript של מבנה מסמך: שדות, טיפוסים, קבוצות, ולידציה. אנו מפתחים סכמות מותאמות אישית לכל עסק: ממסמכי מוצר וקטגוריה ועד אובייקטים מורכבים עם מערכים מקוננים. הניסיון שלנו: 5+ שנים בעבודה עם מערכות CMS ללא ראש, מעל 30 פרויקטים על Sanity, Strapi ו-Directus. אנו מבטיחים שהסכמה תהיה נוחה למנהלי תוכן ויעילה לפרונטאנד. Sanity Studio עם סכמה מותאמת אישית מאיץ את הזנת התוכן פי 3 בהשוואה לתצורה מבוססת ממשק. חיסכון בתקציב — עד 40% בשלב ניהול התוכן. עלות טיפוסית לפיתוח 4–6 סכמות מותאמות אישית נעה בין €1,200 ל-€3,000, תלוי במורכבות. עבור פרויקט מסחר אלקטרוני אחרון עם 5 סכמות, העלות הייתה €2,200. קבלו ייעוץ — אנו מעריכים את הפרויקט שלכם ביום אחד.

סכמות Sanity מותאמות אישית מאיצות פיתוח פי 3

סכמה מוכנה עם ולידציה ויחסים טובה פי 3 מאשר לוגיקת backend ידנית. אתם מקבלים מיד API עם נתונים מטיפוסים. אין צורך לכתוב בקרי CRUD נפרדים — Sanity Studio מייצר את טופס העריכה אוטומטית. זה חשוב במיוחד לפרויקטים עם ישויות רבות. לדוגמה, עבור חנות מסחר אלקטרוני פיתחנו 7 סכמות: מוצר, קטגוריה, יצרן, ביקורת, הגדרות אתר, דף תוכן ותפריט. תוצאה: עד 40% חיסכון בזמן בשלב ניהול התוכן. סכמות מותאמות אישית טובות פי 2-3 בגמישות מתבניות מוכנות — אתם שולטים בכל שדה ויחס. יתרה מכך, הסכמות המותאמות אישית שלנו טובות ב-50% בביצועי שאילתות מתבניות ברירת מחדל בטיפול בתוכן מקונן, הודות למבנה ולולידציה אופטימליים.

כדי ליצור סכמה מותאמת אישית:

  1. הגדירו את טיפוס המסמך באמצעות S.documentTypeListItem עם שם ייחודי, כותרת וטיפוס מסמך.
  2. הוסיפו הגדרות שדות עם schemaType, תוך ציון טיפוס, קבוצה, ולידציה ותצוגה מקדימה.
  3. הגדירו קבוצות שדות לארגון טופס העורך.
  4. רשמו את כל הסכמות בתצורת הסכמות של Studio.

יצירת מסמך Singleton ב-Sanity

Singleton הוא מסמך שקיים בעותק יחיד, למשל הגדרות אתר. הוא נוצר כמסמך רגיל, אך בתוסף המבנה הוא מוצג דרך siteSettingsType עם אפשרות // sanity/schema.ts import { postType } from './schemas/postType' import { authorType } from './schemas/authorType' import { categoryType } from './schemas/categoryType' import { productType } from './schemas/productType' import { siteSettingsType } from './schemas/siteSettingsType' export const schema = { types: [postType, authorType, categoryType, productType, siteSettingsType], } . זה מאפשר למנהלי תוכן לערוך הגדרות גלובליות ללא סיכון ליצירת כפילויות. דוגמה למסמך כזה — // schemas/productType.ts import { defineType, defineField, defineArrayMember } from 'sanity' export const productType = defineType({ name: 'product', title: 'Товар', type: 'document', groups: [ { name: 'details', title: 'Данные', default: true }, { name: 'media', title: 'Медиа' }, { name: 'seo', title: 'SEO' }, ], fields: [ defineField({ name: 'name', title: 'Название', type: 'string', group: 'details', validation: rule => rule.required(), }), defineField({ name: 'slug', type: 'slug', group: 'details', options: { source: 'name' }, }), defineField({ name: 'price', type: 'number', group: 'details', validation: rule => rule.required().positive(), }), defineField({ name: 'compareAtPrice', title: 'Цена до скидки', type: 'number', group: 'details', validation: rule => rule.positive(), }), defineField({ name: 'categories', type: 'array', group: 'details', of: [defineArrayMember({ type: 'reference', to: [{ type: 'category' }] })], }), defineField({ name: 'specs', title: 'Характеристики', type: 'array', group: 'details', of: [ defineArrayMember({ type: 'object', fields: [ defineField({ name: 'name', type: 'string', title: 'Название' }), defineField({ name: 'value', type: 'string', title: 'Значение' }), defineField({ name: 'unit', type: 'string', title: 'Единица' }), ], preview: { select: { title: 'name', subtitle: 'value' }, }, }), ], }), defineField({ name: 'images', type: 'array', group: 'media', of: [ defineArrayMember({ type: 'image', options: { hotspot: true }, fields: [defineField({ name: 'alt', type: 'string' })], }), ], }), defineField({ name: 'description', type: 'blockContent', group: 'details', }), // SEO поля defineField({ name: 'seoTitle', title: 'SEO Title', type: 'string', group: 'seo', validation: rule => rule.max(60), }), defineField({ name: 'seoDescription', title: 'SEO Description', type: 'text', group: 'seo', validation: rule => rule.max(160), }), // Статус defineField({ name: 'status', type: 'string', options: { list: [ { title: 'Активен', value: 'active' }, { title: 'Архив', value: 'archived' }, { title: 'Черновик', value: 'draft' }, ], layout: 'radio', }, initialValue: 'active', }), ], }) בקטע הקוד למטה.

חשיבות ולידציית שדות בסכמות

ולידציה מבטיחה שלמות נתונים: שדות חובה, פורמטים (אימייל, URL), מגבלות אורך, slugs ייחודיים. שגיאות מוצגות ישירות ב-Studio, ומונעות תוכן לא תקין. ללא ולידציה, נתונים זבל נכנסים למסד הנתונים, מה שמוביל לשגיאות פרונטאנד ולניקוי ידני של נתונים. בניסיון שלנו, לאחר יישום סכמות מותאמות אישית עם ולידציה, מספר השגיאות ירד ב-90%.

כיצד אנו מתכננים סכמה: מקרה בוחן מסחר אלקטרוני

פרויקט ללקוח גדול: 7 סכמות, 45 שדות, 12 יחסים. להלן דוגמה לסכמת מוצר עם קבוצות שדות, מפרטים ובלוק SEO. לאחר היישום, מנהלי תוכן החלו למלא כרטיס מוצר ב-5 דקות במקום 20, ושגיאות הולידציה ירדו ב-90%. עלות הפרויקט מחושבת באופן פרטני, אך בממוצע, פיתוח 4-6 סכמות עם יחסים ו-Portable Text אורך 2-5 ימים.

דוגמאות סכמות עם קוד

טיפוסי מסמכים ורישום

// sanity/schema.ts
import { postType } from './schemas/postType'
import { authorType } from './schemas/authorType'
import { categoryType } from './schemas/categoryType'
import { productType } from './schemas/productType'
import { siteSettingsType } from './schemas/siteSettingsType'

export const schema = {
  types: [postType, authorType, categoryType, productType, siteSettingsType],
}

סכמת מוצר עם קבוצות וולידציה

// schemas/productType.ts
import { defineType, defineField, defineArrayMember } from 'sanity'

export const productType = defineType({
  name: 'product',
  title: 'Товар',
  type: 'document',
  groups: [
    { name: 'details', title: 'Данные', default: true },
    { name: 'media', title: 'Медиа' },
    { name: 'seo', title: 'SEO' },
  ],
  fields: [
    defineField({
      name: 'name',
      title: 'Название',
      type: 'string',
      group: 'details',
      validation: rule => rule.required(),
    }),
    defineField({
      name: 'slug',
      type: 'slug',
      group: 'details',
      options: { source: 'name' },
    }),
    defineField({
      name: 'price',
      type: 'number',
      group: 'details',
      validation: rule => rule.required().positive(),
    }),
    defineField({
      name: 'compareAtPrice',
      title: 'Цена до скидки',
      type: 'number',
      group: 'details',
      validation: rule => rule.positive(),
    }),
    defineField({
      name: 'categories',
      type: 'array',
      group: 'details',
      of: [defineArrayMember({ type: 'reference', to: [{ type: 'category' }] })],
    }),
    defineField({
      name: 'specs',
      title: 'Характеристики',
      type: 'array',
      group: 'details',
      of: [
        defineArrayMember({
          type: 'object',
          fields: [
            defineField({ name: 'name', type: 'string', title: 'Название' }),
            defineField({ name: 'value', type: 'string', title: 'Значение' }),
            defineField({ name: 'unit', type: 'string', title: 'Единица' }),
          ],
          preview: {
            select: {
              title: 'name',
              subtitle: 'value',
            },
          },
        }),
      ],
    }),
    defineField({
      name: 'images',
      type: 'array',
      group: 'media',
      of: [
        defineArrayMember({
          type: 'image',
          options: { hotspot: true },
          fields: [defineField({ name: 'alt', type: 'string' })],
        }),
      ],
    }),
    defineField({
      name: 'description',
      type: 'blockContent',
      group: 'details',
    }),
    // SEO поля
    defineField({
      name: 'seoTitle',
      title: 'SEO Title',
      type: 'string',
      group: 'seo',
      validation: rule => rule.max(60),
    }),
    defineField({
      name: 'seoDescription',
      title: 'SEO Description',
      type: 'text',
      group: 'seo',
      validation: rule => rule.max(160),
    }),
    // Статус
    defineField({
      name: 'status',
      type: 'string',
      options: {
        list: [
          { title: 'Активен', value: 'active' },
          { title: 'Архив', value: 'archived' },
          { title: 'Черновик', value: 'draft' },
        ],
        layout: 'radio',
      },
      initialValue: 'active',
    }),
  ],
})

Portable Text עם בלוקים מותאמים אישית

// schemas/blockContent.ts
import { defineType, defineArrayMember } from 'sanity'

export const blockContentType = defineType({
  name: 'blockContent',
  title: 'Block Content',
  type: 'array',
  of: [
    defineArrayMember({
      type: 'block',
      styles: [
        { title: 'Normal', value: 'normal' },
        { title: 'H2', value: 'h2' },
        { title: 'H3', value: 'h3' },
        { title: 'Quote', value: 'blockquote' },
      ],
      marks: {
        decorators: [
          { title: 'Bold', value: 'strong' },
          { title: 'Italic', value: 'em' },
          { title: 'Code', value: 'code' },
        ],
        annotations: [
          {
            name: 'link',
            type: 'object',
            fields: [
              defineField({ name: 'href', type: 'url' }),
              defineField({ name: 'blank', type: 'boolean', title: 'Open in new tab' }),
            ],
          },
        ],
      },
    }),
    // Встроенные изображения
    defineArrayMember({
      type: 'image',
      options: { hotspot: true },
      fields: [
        defineField({ name: 'alt', type: 'string' }),
        defineField({ name: 'caption', type: 'string' }),
      ],
    }),
    // Кастомный блок — цитата с автором
    defineArrayMember({
      type: 'object',
      name: 'callout',
      title: 'Callout',
      fields: [
        defineField({ name: 'text', type: 'text' }),
        defineField({
          name: 'type',
          type: 'string',
          options: {
            list: ['info', 'warning', 'tip'],
            layout: 'radio',
          },
        }),
      ],
    }),
  ],
})

מסמך הגדרות Singleton

// schemas/siteSettingsType.ts
export const siteSettingsType = defineType({
  name: 'siteSettings',
  title: 'Настройки сайта',
  type: 'document',
  fields: [
    defineField({
      name: 'siteName',
      type: 'string',
      validation: r => r.required()
    }),
    defineField({
      name: 'logo',
      type: 'image'
    }),
    defineField({
      name: 'favicon',
      type: 'image'
    }),
    defineField({
      name: 'socialLinks',
      type: 'array',
      of: [
        defineArrayMember({
          type: 'object',
          fields: [
            defineField({
              name: 'platform',
              type: 'string'
            }),
            defineField({
              name: 'url',
              type: 'url'
            }),
          ],
        })
      ],
    }),
  ],
  preview: {
    select: {
      title: 'siteName',
      media: 'logo'
    }
  },
})

השוואה: סכמות מותאמות אישית מול תבניות מוכנות

קריטריון סכמות מותאמות אישית תבניות מוכנות
מהירות פיתוח 2–5 ימים עבור 4–6 סכמות 1–2 ימים להתאמה
גמישות שליטה מלאה פונקציונליות מוגבלת
ביצועים מותאם לסטאק שלכם יכול להיות מוגזם

סכמות מותאמות אישית מנצחות בגמישות פי 2-3 ועוזרות להימנע משאילתות N+1, דבר קריטי לביצועים. תבניות מוכנות חוסכות זמן בתחילה אך דורשות התאמה אישית למשימות אמיתיות.

מה כלול

  • תיעוד: תיאור של כל הסכמות, קבוצות השדות והיחסים עם דיאגרמות.
  • קוד מקור: קבצי TypeScript עם ולידציה מלאה ותצוגה מקדימה.
  • גישה: תצורת Sanity Studio, תפקידים ואסימוני API.
  • הדרכה: הוראות למנהלי תוכן כיצד להשתמש ב-Studio.
  • תמיכה: שבועיים של שינויים חינם לאחר המסירה.
  • תיאורי סכמות מפורטים עם תיעוד ברמת שדה.

תהליך עבודה

שלב מה אנו עושים תוצאה
ניתוח זיהוי טיפוסי תוכן, יחסים, דרישות ולידציה מסמך עם רשימת סכמות
עיצוב שרטוט גרף מסמכים ויחסים דיאגרמת ER
פיתוח כתיבת סכמות TypeScript, הגדרת קבוצות ותצוגה מקדימה 4–6 סכמות עם ולידציה
בדיקות בדיקת Studio, API, אינטגרציית פרונטאנד רשימת בדיקות שעברו
פריסה פריסת תצורה, הענקת גישה Studio עובד

לוח זמנים משוער

פיתוח 4–6 סכמות עם Portable Text, יחסים וולידציה — בין 2 ל-5 ימים. העלות מחושבת באופן פרטני לאחר ניתוח הדרישות שלכם. עלות טיפוסית לפיתוח 4–6 סכמות מותאמות אישית נעה בין €1,200 ל-€3,000, תלוי במורכבות. צרו קשר לייעוץ — אנו מעריכים את הפרויקט שלכם ביום אחד.

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