שילוב KeystoneJS CMS לניהול תוכן

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

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
שילוב KeystoneJS CMS לניהול תוכן
בינוני
~3-5 ימים

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

שאלות נפוצות

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

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

שילוב KeystoneJS CMS

אנו משלבים את KeystoneJS 6 באתר או באפליקציה שלך, ומגדירים סכמות נתונים, GraphQL API, אימות וממשק ניהול. הצוות שלנו מחבר את KeystoneJS לפרונטאנד של Next.js או React, מטפל בהתקנת PostgreSQL, ומספק CMS headless עובד תוך שישה עד שנים עשר ימים. שילבנו את KeystoneJS עבור צוותי עריכה, קטלוגי מוצרים ואתרי תיעוד. הלקוחות שלנו מקבלים שליטה מלאה על סכמת התוכן שלהם ללא נעילת ספק (vendor lock-in) ועם TypeScript API מהיום הראשון.

KeystoneJS משלב CMS headless ומסגרת אפליקציות. סכמת הנתונים כתובה ב-TypeScript ומייצרת אוטומטית GraphQL API, נקודות קצה דמויות REST וממשק ניהול. עבור צוותים שרוצים שליטה מלאה על מודל התוכן וה-API שלהם ללא ניהול backend נפרד, KeystoneJS מספק בסיס חזק.

מה כלול בשירות שילוב KeystoneJS שלנו

אנו מספקים את שילוב ה-CMS המלא כפרויקט מפתח מלא. ההיקף כולל:

  • עיצוב סכמת נתונים עבור סוגי התוכן שלך: פוסטים, עמודים, מוצרים, מחברים וישויות מותאמות אישית
  • התקנה והגדרה של KeystoneJS עם PostgreSQL או SQLite
  • הגדרת ממשק ניהול עם כללי בקרת גישה לעורכים, מחברים ומנהלים
  • GraphQL API עם שאילתות, מוטציות, פילטרים ודפדוף (pagination) מתוייקים
  • הגדרת אחסון תמונות וקבצים: דיסק מקומי או אחסון ענן עם S3
  • שילוב לקוח Next.js עם GraphQL SDK מתוייק באמצעות graphql-codegen
  • Webhooks ו-hooks של שדות מותאמים אישית ללוגיקה עסקית בעת יצירה, עדכון ומחיקה
  • כלי עזר ליצירת דפים סטטיים עבור // keystone.ts import { config, list } from '@keystone-6/core' import { allowAll, denyAll, isSignedIn } from '@keystone-6/core/access' import { text, relationship, password, timestamp, select, checkbox, image, document } from '@keystone-6/core/fields' import { document as documentField } from '@keystone-6/fields-document' export default config({ db: { provider: 'postgresql', url: process.env.DATABASE_URL!, idField: { kind: 'cuid' }, }, lists: { Post: list({ access: { operation: { query: allowAll, create: isSignedIn, update: isSignedIn, delete: isSignedIn, }, }, fields: { title: text({ validation: { isRequired: true } }), slug: text({ isIndexed: 'unique' }), content: documentField({ formatting: true, dividers: true, links: true, layouts: [[1, 1], [1, 2, 1]], }), publishedAt: timestamp(), status: select({ options: ['draft', 'published', 'archived'], defaultValue: 'draft', ui: { displayMode: 'segmented-control' }, }), author: relationship({ ref: 'User.posts' }), tags: relationship({ ref: 'Tag.posts', many: true }), cover: image({ storage: 'local_images' }), }, hooks: { resolveInput: async ({ resolvedData, operation }) => { if (operation === 'create' && !resolvedData.slug) { resolvedData.slug = resolvedData.title ?.toLowerCase() .replace(/\s+/g, '-') .replace(/[^a-z0-9-]/g, '') } return resolvedData }, }, }), Tag: list({ access: allowAll, fields: { name: text({ isIndexed: 'unique' }), posts: relationship({ ref: 'Post.tags', many: true }), }, }), User: list({ access: { operation: { query: isSignedIn, create: ({ session }) => session?.data?.role === 'admin', update: isSignedIn, delete: ({ session }) => session?.data?.role === 'admin', }, }, fields: { name: text({ validation: { isRequired: true } }), email: text({ isIndexed: 'unique', validation: { isRequired: true } }), password: password({ validation: { isRequired: true } }), role: select({ options: ['admin', 'editor', 'author'], defaultValue: 'author' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), }, session: statelessSessions({ secret: process.env.SESSION_SECRET!, maxAge: 60 * 60 * 24 * 30, }), storage: { local_images: { kind: 'local', type: 'image', generateUrl: (path) => `${process.env.ASSET_BASE_URL}/images${path}`, serverRoute: { path: '/images' }, storagePath: 'public/images', }, }, }) ו-ISR revalidation

למה KeystoneJS ל-CMS headless?

KeystoneJS מייצר סכמת GraphQL מלאה ממודל הנתונים שלך ב-TypeScript. טיפוסים, מוטציות, פילטרים ומטפלי דפדוף מופיעים אוטומטית. זה מבטל את הצורך בכתיבת ותחזוקת קוד API boilerplate שכל CMS headless דורש.

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

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

דוגמת סכמת נתונים

// keystone.ts
import { config, list } from '@keystone-6/core'
import { allowAll, denyAll, isSignedIn } from '@keystone-6/core/access'
import { text, relationship, password, timestamp, select, checkbox, image, document } from '@keystone-6/core/fields'
import { document as documentField } from '@keystone-6/fields-document'

export default config({
  db: {
    provider: 'postgresql',
    url: process.env.DATABASE_URL!,
    idField: { kind: 'cuid' },
  },
  lists: {
    Post: list({
      access: {
        operation: {
          query: allowAll,
          create: isSignedIn,
          update: isSignedIn,
          delete: isSignedIn,
        },
      },
      fields: {
        title: text({ validation: { isRequired: true } }),
        slug: text({ isIndexed: 'unique' }),
        content: documentField({
          formatting: true,
          dividers: true,
          links: true,
          layouts: [[1, 1], [1, 2, 1]],
        }),
        publishedAt: timestamp(),
        status: select({
          options: ['draft', 'published', 'archived'],
          defaultValue: 'draft',
          ui: { displayMode: 'segmented-control' },
        }),
        author: relationship({ ref: 'User.posts' }),
        tags: relationship({ ref: 'Tag.posts', many: true }),
        cover: image({ storage: 'local_images' }),
      },
      hooks: {
        resolveInput: async ({ resolvedData, operation }) => {
          if (operation === 'create' && !resolvedData.slug) {
            resolvedData.slug = resolvedData.title
              ?.toLowerCase()
              .replace(/\s+/g, '-')
              .replace(/[^a-z0-9-]/g, '')
          }
          return resolvedData
        },
      },
    }),
    Tag: list({
      access: allowAll,
      fields: {
        name: text({ isIndexed: 'unique' }),
        posts: relationship({ ref: 'Post.tags', many: true }),
      },
    }),
    User: list({
      access: {
        operation: {
          query: isSignedIn,
          create: ({ session }) => session?.data?.role === 'admin',
          update: isSignedIn,
          delete: ({ session }) => session?.data?.role === 'admin',
        },
      },
      fields: {
        name: text({ validation: { isRequired: true } }),
        email: text({ isIndexed: 'unique', validation: { isRequired: true } }),
        password: password({ validation: { isRequired: true } }),
        role: select({
          options: ['admin', 'editor', 'author'],
          defaultValue: 'author'
        }),
        posts: relationship({ ref: 'Post.author', many: true }),
      },
    }),
  },
  session: statelessSessions({
    secret: process.env.SESSION_SECRET!,
    maxAge: 60 * 60 * 24 * 30,
  }),
  storage: {
    local_images: {
      kind: 'local',
      type: 'image',
      generateUrl: (path) => `${process.env.ASSET_BASE_URL}/images${path}`,
      serverRoute: { path: '/images' },
      storagePath: 'public/images',
    },
  },
})

GraphQL API ושילוב Next.js

לאחר הגדרת הסכמה, KeystoneJS חושף GraphQL API מלא. אנו מגדירים לקוח מתוייק באמצעות graphql-codegen כך שרכיבי הפרונטאנד שלך מקבלים בטיחות טיפוסים בזמן קומפילציה עבור כל השאילתות.

// lib/keystoneClient.ts
import { GraphQLClient } from 'graphql-request'

export const keystoneClient = new GraphQLClient(
  process.env.KEYSTONE_API_URL || 'http://localhost:3000/api/graphql',
  {
    headers: {
      'x-api-key': process.env.KEYSTONE_API_KEY!,
    },
  }
)

// Типизированные запросы через graphql-codegen
import { getSdk } from './__generated__/sdk'

export const cms = getSdk(keystoneClient)
// app/blog/[slug]/page.tsx
import { cms } from '@/lib/keystoneClient'

export default async function PostPage({ params }) {
  const { post } = await cms.getPostBySlug({ slug: params.slug })
  if (!post) notFound()
  return <ArticleLayout post={post} />
}

export async function generateStaticParams() {
  const { posts } = await cms.getAllPostSlugs()
  return posts.map(p => ({ slug: p.slug }))
}

שדה מסמך KeystoneJS

שדה המסמך המובנה מאחסן תוכן מובנה במקום HTML גולמי. זה נותן לעורכים חוויית עריכה עשירה ולמפתחים נתונים נקיים לעיבוד.

import { DocumentRenderer } from '@keystone-6/document-renderer'

function PostContent({ content }) {
  return (
    <DocumentRenderer
      document={content.document}
      renderers={{
        block: {
          paragraph: ({ children, textAlign }) => (
            <p style={{ textAlign }} className="mb-4">{children}</p>
          ),
          layout: ({ layout, children }) => (
            <div className={`grid grid-cols-${layout.join('-')}`}>
              {children}
            </div>
          ),
        },
        inline: {
          link: ({ children, href }) => (
            <a href={href} className="text-blue-600 underline">{children}</a>
          ),
        },
      }}
    />
  )
}

איך אנו מספקים את השילוב

  1. סקירת סוגי התוכן שלך והגדרת הסכמה יחד עם הצוות שלך
  2. הקמת KeystoneJS ומסד נתונים בסביבת פיתוח
  3. בנייה ובדיקה של הסכמה, ה-API וממשק הניהול
  4. שילוב לקוח ה-GraphQL בפרונטאנד שלך
  5. פריסה לסביבת הייצור שלך ומסירת תיעוד
היקף ציר זמן
3–4 סוגי תוכן עם אימות בסיסי 4–6 ימי עבודה
6–8 סוגי תוכן עם אחסון תמונות ו-codegen 6–8 ימי עבודה
שילוב מלא עם hooks מותאמים אישית ואחסון S3 8–12 ימי עבודה

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

איך אנו מספקים

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