{
  "id": "crm",
  "slug": "crm",
  "title": "Sales CRM Backend",
  "description": "Verified CRM schema for companies, contacts, deals, activities, tasks, products, and quotes. Preview the schema, APIs, permissions, and SDK examples, then clone into Apito Console.",
  "version": "1.0.0",
  "checksum": "sha256:crm-v1-2026-07-24",
  "status": "verified",
  "edition": "both",
  "project_type": "general",
  "database_intent": "sqlite",
  "source": "console projectTemplates crm + Apito Engineering review",
  "reviewed_at": "2026-07-24",
  "architecture_notes": "Pipeline-centric CRM. Companies own contacts; deals hang off company+contact; activities and tasks attach to deals; quotes reference deal line products.",
  "models": [
    {
      "name": "company",
      "label": "Company",
      "description": "Account / organization in the pipeline",
      "scope": "general",
      "fields": [
        { "identifier": "name", "label": "Name", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "website", "label": "Website", "field_type": "text", "input_type": "string" },
        { "identifier": "industry", "label": "Industry", "field_type": "text", "input_type": "string" },
        { "identifier": "size", "label": "Company Size", "field_type": "list", "input_type": "string", "options": ["1-10", "11-50", "51-200", "201-1000", "1000+"] },
        { "identifier": "notes", "label": "Notes", "field_type": "multiline", "input_type": "string" }
      ]
    },
    {
      "name": "contact",
      "label": "Contact",
      "description": "Person at a company",
      "scope": "general",
      "fields": [
        { "identifier": "first_name", "label": "First Name", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "last_name", "label": "Last Name", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "email", "label": "Email", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "phone", "label": "Phone", "field_type": "text", "input_type": "string" },
        { "identifier": "title", "label": "Job Title", "field_type": "text", "input_type": "string" }
      ]
    },
    {
      "name": "deal",
      "label": "Deal",
      "description": "Opportunity in the sales pipeline",
      "scope": "general",
      "fields": [
        { "identifier": "title", "label": "Title", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "amount", "label": "Amount", "field_type": "number", "input_type": "double", "required": true },
        { "identifier": "stage", "label": "Stage", "field_type": "list", "input_type": "string", "options": ["lead", "qualified", "proposal", "negotiation", "won", "lost"], "required": true },
        { "identifier": "close_date", "label": "Expected Close", "field_type": "date", "input_type": "string" },
        { "identifier": "probability", "label": "Win Probability", "field_type": "number", "input_type": "int" }
      ]
    },
    {
      "name": "activity",
      "label": "Activity",
      "description": "Call, meeting, or email log",
      "scope": "general",
      "fields": [
        { "identifier": "type", "label": "Type", "field_type": "list", "input_type": "string", "options": ["call", "meeting", "email", "note"], "required": true },
        { "identifier": "subject", "label": "Subject", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "body", "label": "Body", "field_type": "multiline", "input_type": "string" },
        { "identifier": "occurred_at", "label": "Occurred At", "field_type": "date", "input_type": "string", "required": true }
      ]
    },
    {
      "name": "task",
      "label": "Task",
      "description": "Follow-up work item",
      "scope": "general",
      "fields": [
        { "identifier": "title", "label": "Title", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "status", "label": "Status", "field_type": "list", "input_type": "string", "options": ["todo", "in_progress", "done"], "required": true },
        { "identifier": "due_date", "label": "Due Date", "field_type": "date", "input_type": "string" },
        { "identifier": "priority", "label": "Priority", "field_type": "list", "input_type": "string", "options": ["low", "medium", "high"] }
      ]
    },
    {
      "name": "product",
      "label": "Product",
      "description": "Sellable catalog item",
      "scope": "general",
      "fields": [
        { "identifier": "name", "label": "Name", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "sku", "label": "SKU", "field_type": "text", "input_type": "string" },
        { "identifier": "unit_price", "label": "Unit Price", "field_type": "number", "input_type": "double", "required": true },
        { "identifier": "description", "label": "Description", "field_type": "multiline", "input_type": "string" }
      ]
    },
    {
      "name": "quote",
      "label": "Quote",
      "description": "Commercial quote for a deal",
      "scope": "general",
      "fields": [
        { "identifier": "number", "label": "Quote Number", "field_type": "text", "input_type": "string", "required": true },
        { "identifier": "status", "label": "Status", "field_type": "list", "input_type": "string", "options": ["draft", "sent", "accepted", "rejected"], "required": true },
        { "identifier": "total", "label": "Total", "field_type": "number", "input_type": "double" },
        { "identifier": "valid_until", "label": "Valid Until", "field_type": "date", "input_type": "string" },
        {
          "identifier": "line_items",
          "label": "Line Items",
          "field_type": "repeated",
          "input_type": "repeated",
          "nested": [
            { "identifier": "quantity", "label": "Quantity", "field_type": "number" },
            { "identifier": "unit_price", "label": "Unit Price", "field_type": "number" },
            { "identifier": "description", "label": "Description", "field_type": "text" }
          ]
        }
      ]
    }
  ],
  "relations": [
    { "from": "company", "to": "contact", "forward": "has_many", "reverse": "has_one" },
    { "from": "company", "to": "deal", "forward": "has_many", "reverse": "has_one" },
    { "from": "contact", "to": "deal", "forward": "has_many", "reverse": "has_one" },
    { "from": "deal", "to": "activity", "forward": "has_many", "reverse": "has_one" },
    { "from": "deal", "to": "task", "forward": "has_many", "reverse": "has_one" },
    { "from": "deal", "to": "quote", "forward": "has_many", "reverse": "has_one" },
    { "from": "contact", "to": "quote", "forward": "has_many", "reverse": "has_one" },
    { "from": "quote", "to": "product", "forward": "has_many", "reverse": "has_many", "known_as": "products" }
  ],
  "roles": [
    {
      "name": "admin",
      "description": "Full CRM access",
      "is_admin": true,
      "permissions": ["company:*", "contact:*", "deal:*", "activity:*", "task:*", "product:*", "quote:*"]
    },
    {
      "name": "sales",
      "description": "Create and update pipeline records",
      "permissions": ["company:read", "company:create", "company:update", "contact:*", "deal:*", "activity:*", "task:*", "product:read", "quote:*"]
    },
    {
      "name": "viewer",
      "description": "Read-only pipeline access",
      "permissions": ["company:read", "contact:read", "deal:read", "activity:read", "task:read", "product:read", "quote:read"]
    }
  ],
  "graphql_operations": [
    {
      "name": "companyList",
      "type": "query",
      "model": "company",
      "description": "List companies with optional filters",
      "example": "query { companyList(limit: 20) { id data { name industry } } }"
    },
    {
      "name": "createCompany",
      "type": "mutation",
      "model": "company",
      "description": "Create a company",
      "example": "mutation($payload: JSON!) { createCompany(payload: $payload) { id } }"
    },
    {
      "name": "dealList",
      "type": "query",
      "model": "deal",
      "description": "List deals by stage",
      "example": "query { dealList(where: { stage: { eq: \"proposal\" } }) { id data { title amount stage } } }"
    },
    {
      "name": "createDeal",
      "type": "mutation",
      "model": "deal",
      "description": "Create a deal linked to company and contact",
      "example": "mutation($payload: JSON!, $connect: JSON) { createDeal(payload: $payload, connect: $connect) { id } }"
    },
    {
      "name": "contactList",
      "type": "query",
      "model": "contact",
      "description": "List contacts",
      "example": "query { contactList(limit: 50) { id data { first_name last_name email } } }"
    }
  ],
  "rest_endpoints": [
    { "method": "GET", "path": "/secured/rest/company", "description": "List companies" },
    { "method": "POST", "path": "/secured/rest/company", "description": "Create company" },
    { "method": "GET", "path": "/secured/rest/deal", "description": "List deals" },
    { "method": "POST", "path": "/secured/rest/deal", "description": "Create deal" },
    { "method": "GET", "path": "/secured/rest/contact", "description": "List contacts" }
  ],
  "sdk_examples": [
    {
      "language": "javascript",
      "title": "List deals with js-admin-sdk",
      "code": "import { ApitoClient } from '@apito-io/js-admin-sdk';\n\nconst client = new ApitoClient({\n  endpoint: process.env.APITO_GRAPHQL_URL,\n  token: process.env.APITO_TOKEN,\n});\n\nconst deals = await client.query(`\n  query { dealList(limit: 20) { id data { title amount stage } } }\n`);\nconsole.log(deals);"
    },
    {
      "language": "flutter",
      "title": "Fetch companies",
      "code": "final client = ApitoClient(\n  endpoint: dotenv.env['APITO_GRAPHQL_URL']!,\n  token: dotenv.env['APITO_TOKEN']!,\n);\n\nfinal result = await client.query('''\n  query { companyList(limit: 20) { id data { name industry } } }\n''');\nprint(result);"
    },
    {
      "language": "go",
      "title": "Create a contact",
      "code": "client := apito.NewClient(endpoint, token)\npayload := map[string]any{\n  \"first_name\": \"Ada\",\n  \"last_name\": \"Lovelace\",\n  \"email\": \"ada@example.com\",\n}\nid, err := client.Create(\"contact\", payload)\nif err != nil { log.Fatal(err) }\nfmt.Println(id)"
    }
  ],
  "limitations": [
    "Public playground is a static verified preview — not a live shared sandbox.",
    "Clone stages a reviewable draft in Console; publish stays a human action.",
    "AI customization is available after clone, not as silent mutation of this manifest."
  ],
  "clone_requirements": [
    "Apito Console account",
    "Project create permission",
    "Compatible Engine with schema versioning (Pro) or immediate apply (open-core)"
  ],
  "smoke_tests": [
    "companyList returns created company",
    "createDeal connects company and contact",
    "sales role cannot delete company when restricted"
  ],
  "experience": {
    "experience_type": "playground",
    "preview_modules": ["overview", "schema", "erd", "graphql", "rest", "permissions", "sdk", "download"],
    "cta_label": "Clone this backend",
    "handoff_policy": "signed_preview"
  }
}
