بنقرة واحدة
grain-schema
Define Malli schemas for commands, events, and queries using defschemas
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Define Malli schemas for commands, events, and queries using defschemas
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Create scheduled background jobs that run on cron schedules
Build an ORC behavior tree workflow using the DSL
Set up LLM-as-judge evaluation for ORC workflows
Implement event-driven side effects that react to domain events
Implement command handlers that validate state and emit events using the Grain framework
Create a complete Grain domain service with schemas, read models, commands, queries, and tests
| name | grain-schema |
| description | Define Malli schemas for commands, events, and queries using defschemas |
(ns my.service.interface.schemas
(:require [ai.obney.grain.schema-util.interface :refer [defschemas]]))
Use defschemas to register named Malli schemas:
(defschemas schema-group-name
{:schema-key schema-definition
:another-key another-definition})
Naming: :namespace/action (verb form)
(defschemas commands
{;; Create command
:crm/create-contact
[:map
[:type-slug :string]
[:field-values [:map-of :keyword :any]]
[:contact-id {:optional true} :uuid]
[:tags {:optional true} [:set :string]]]
;; Update command
:crm/update-contact
[:map
[:contact-id :uuid]
[:changes [:map-of :keyword :any]]]
;; Action command
:advisor/start-meeting
[:map
[:student-id :uuid]
[:meeting-type [:enum :intake-interview :freeform]]]})
Naming: :namespace/entity-past-tense (what happened)
(defschemas events
{;; Created event
:crm/contact-created
[:map
[:contact-id :uuid]
[:type-id :uuid]
[:type-slug :string]
[:display-name :string]
[:field-values [:map-of :keyword :any]]
[:tags [:set :string]]]
;; Updated event
:crm/contact-updated
[:map
[:contact-id :uuid]
[:changes [:map-of :keyword :any]]]
;; Action completed event
:advisor/meeting-started
[:map
[:meeting-id :uuid]
[:student-id :uuid]
[:meeting-type [:enum :intake-interview :freeform]]
[:started-at :string]]})
Naming: :namespace/query-name (what to get)
(defschemas queries
{:crm/get-contact
[:map
[:contact-id :uuid]]
:crm/list-contacts
[:map
[:type-slug {:optional true} :string]
[:status {:optional true} [:enum :active :inactive :archived]]
[:limit {:optional true} :int]
[:offset {:optional true} :int]]
:advisor/meetings-screen
[:map
[:student-id :uuid]]})
:string ;; String
:int ;; Integer
:double ;; Float
:boolean ;; Boolean
:uuid ;; UUID
:keyword ;; Keyword
:any ;; Any value
[:enum :a :b :c] ;; Enum
[:set :string] ;; Set of strings
[:vector :uuid] ;; Vector of UUIDs
[:map-of :keyword :any] ;; Map with keyword keys
[:map ;; Map with specific keys
[:required-key :string]
[:optional-key {:optional true} :int]]
[:re #"^[a-z]+$"] ;; Regex pattern
(defschemas custom-types
{:email [:re #"^[^@\s]+@[^@\s]+\.[^@\s]+$"]
:phone [:re #"^\d{10,15}$"]
:encrypted [:map
[:ciphertext :string]
[:encrypted-key :string]
[:iv :string]]})
(def attribution-source
[:enum :application_form :intake_form :referral :manual_entry])
(def attribution
[:map
[:source attribution-source]
[:source-details {:optional true} :any]
[:referring-contact-id {:optional true} :uuid]
[:recorded-at :string]])
(defschemas events
{:crm/attribution-recorded
[:map
[:contact-id :uuid]
[:attribution attribution]]})
:namespace/verb (create, update, delete, start, etc.):namespace/entity-past-tense (created, updated, started):namespace/get-entity or :namespace/list-entities{:optional true} for optional fields->event producescomponents/user-service/src/ai/obney/workshop/user_service/interface/schemas.clj - User schemascomponents/crm-service/src/ai/obney/workshop/crm_service/interface/schemas.clj - CRM schemas with custom types