Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/util/db-schema/crm.ts
Views: 687
/*1NOTES:23- right now the Table function types.ts also automatically does some4extra things for all crm_ tables to ensure safety, e.g., ensuring admin.56- do NOT use defaults for get.fields! Those are set by the frontend crm code when creating records.7Also, they are not compatible with null-ing fields.89*/1011import { FieldSpec, Table } from "./types";12import { blue, green, red, yellow } from "@ant-design/colors";1314export const NOTES: FieldSpec = {15type: "string",16desc: "Open ended text in markdown about this item.",17render: {18type: "markdown",19editable: true,20},21} as const;2223export const ID: FieldSpec = {24type: "integer",25desc: "Automatically generated sequential id that uniquely determines this row.",26pg_type: "SERIAL UNIQUE",27noCoerce: true,28} as const;2930const TAG_TYPE = `INTEGER[]`;3132const TAGS_FIELD: FieldSpec = {33type: "array",34pg_type: TAG_TYPE,35desc: "Tags applied to this record.",36render: { type: "tags", editable: true },37} as const;3839const PRORITIES_FIELD: FieldSpec = {40type: "string",41pg_type: "VARCHAR(30)",42desc: "Priority of this record",43render: {44type: "select",45editable: true,46options: ["low", "normal", "high", "urgent"],47colors: [yellow[5], blue[5], green[5], red[5]],48priority: true,49},50} as const;5152const STATUS_FIELD: FieldSpec = {53type: "string",54pg_type: "VARCHAR(30)",55desc: "Status of this record",56render: {57type: "select",58editable: true,59options: ["new", "open", "pending", "active", "solved"],60colors: [yellow[5], red[5], green[5], blue[5], "#888"],61},62} as const;6364export const CREATED: FieldSpec = {65type: "timestamp",66desc: "When the record was created.",67} as const;6869export const LAST_EDITED: FieldSpec = {70type: "timestamp",71desc: "When this record was last edited.",72} as const;7374const LAST_MODIFIED_BY: FieldSpec = {75type: "uuid",76desc: "Account that last modified this task.",77render: { type: "account" },78} as const;7980const ASSIGNEE: FieldSpec = {81type: "uuid",82desc: "Account that is responsible for resolving this.",83render: {84type: "assignee",85editable: true,86},87} as const;8889Table({90name: "crm_people",91fields: {92id: ID,93created: CREATED,94last_edited: LAST_EDITED,95name: {96type: "string",97pg_type: "VARCHAR(254)",98desc: "The name of this person.",99render: {100type: "text",101maxLength: 254,102editable: true,103},104},105email_addresses: {106type: "array",107pg_type: "VARCHAR(1000)",108desc: "Email addresses for this person, separated by commas",109render: {110type: "text",111maxLength: 1000,112editable: true,113},114},115account_ids: {116title: "Accounts",117type: "array",118pg_type: "UUID[]",119desc: "Array of 0 or more uuid's of CoCalc accounts that this person may have.",120render: {121type: "accounts",122editable: true,123},124},125deleted: {126type: "boolean",127desc: "True if the person has been deleted.",128},129notes: NOTES,130// https://stackoverflow.com/questions/13837258/what-is-an-appropriate-data-type-to-store-a-timezone131timezone: {132type: "string",133desc: "The person's time zone, e.g., 'Europe/Paris' or 'US/Pacific'.",134render: {135type: "text",136maxLength: 254,137editable: true,138},139},140tags: TAGS_FIELD,141},142rules: {143desc: "People",144primary_key: "id",145user_query: {146get: {147pg_where: [],148admin: true,149fields: {150id: null,151created: null,152last_edited: null,153email_addresses: null,154name: null,155account_ids: null,156deleted: null,157notes: null,158tags: null,159},160},161set: {162admin: true,163fields: {164id: true,165created: true,166last_edited: true,167name: true,168email_addresses: true,169account_ids: true,170deleted: true,171notes: true,172tags: null,173},174required_fields: {175last_edited: true, // TODO: make automatic on any set query176},177},178},179},180});181182const ORGANIZATIONS = {183type: "array",184pg_type: "INTEGER[]",185desc: "Zero or more organizations in the Organizations table",186render: {187type: "organizations",188editable: true,189},190} as FieldSpec;191192export const CREATED_BY = {193type: "uuid",194desc: "Account that created this record.",195render: { type: "account" },196} as FieldSpec;197198const PERSON = {199type: "integer",200desc: "One person in the People table",201render: {202type: "person",203editable: true,204},205} as FieldSpec;206207const PEOPLE = {208type: "array",209pg_type: "INTEGER[]",210desc: "Array of 0 or more people in the People table that are connected with this",211render: {212type: "people",213editable: true,214},215} as FieldSpec;216217// TODO: add image -- probably want to use blob table (?) but maybe do like with projects. Not sure.218Table({219name: "crm_organizations",220fields: {221id: ID,222created: CREATED,223last_edited: LAST_EDITED,224name: {225type: "string",226pg_type: "VARCHAR(254)",227desc: "The name of this organization.",228render: {229type: "text",230maxLength: 254,231editable: true,232},233},234people: PEOPLE,235organizations: {236title: "Related Organizations",237type: "array",238pg_type: "INTEGER[]",239desc: "Array of 0 or more organization that are connected with this organization",240render: {241type: "organizations",242editable: true,243},244},245deleted: {246type: "boolean",247desc: "True if this org has been deleted.",248},249notes: NOTES,250timezone: {251type: "string",252desc: "The organizations's time zone, e.g., 'Europe/Paris' or 'US/Pacific'.",253render: {254type: "text",255editable: true,256},257},258domain: {259type: "string",260pg_type: "VARCHAR(254)", // todo -- should this be an array of domain names?261desc: "Domain name of this org, e.g., math.washington.edu.",262render: {263type: "text",264editable: true,265maxLength: 254,266},267},268tags: TAGS_FIELD,269},270rules: {271desc: "Organizations",272primary_key: "id",273user_query: {274get: {275pg_where: [],276admin: true,277fields: {278id: null,279created: null,280last_edited: null,281name: null,282people: null,283organizations: null,284deleted: null,285notes: null,286domain: null,287tags: null,288},289},290set: {291admin: true,292fields: {293id: true,294created: true,295last_edited: true,296name: true,297people: true,298organizations: true,299deleted: true,300notes: true,301domain: true,302tags: true,303},304required_fields: {305last_edited: true, // TODO: make automatic on any set query306},307},308},309},310});311312Table({313name: "crm_support_tickets",314fields: {315id: ID,316subject: {317type: "string",318pg_type: "VARCHAR(254)",319desc: "Subject of the message. Must be short.",320render: {321type: "text",322maxLength: 254,323editable: true,324},325},326created: CREATED,327created_by: PERSON,328last_edited: LAST_EDITED,329last_modified_by: LAST_MODIFIED_BY,330assignee: ASSIGNEE,331tasks: {332title: "Tasks",333type: "array",334pg_type: "integer[]",335desc: "Tasks associated with this support ticket.",336},337cc: {338type: "array",339pg_type: "UUID[]",340desc: "Zero or more support accounts that care to be contacted about updates to this ticket.",341},342tags: TAGS_FIELD,343priority: PRORITIES_FIELD,344status: STATUS_FIELD,345type: {346type: "string",347pg_type: "VARCHAR(30)",348desc: "The type of this ticket: question, incident, problem, task, etc.",349render: { type: "text", editable: true, maxLength: 30 },350},351},352rules: {353desc: "Support Tickets",354primary_key: "id",355user_query: {356get: {357pg_where: [],358admin: true,359fields: {360id: null,361subject: null,362created: null,363created_by: null,364last_edited: null,365last_modified_by: null,366assignee: null,367tasks: null,368cc: null,369tags: null,370type: null,371priority: null,372status: null,373},374},375set: {376admin: true,377fields: {378id: true,379subject: true,380created: true,381last_edited: true,382last_modified_by: true,383created_by: true,384assignee: true,385tasks: true,386cc: true,387tags: true,388type: true,389priority: true,390status: true,391},392required_fields: {393last_edited: true, // TODO: make automatic on any set query394},395},396},397},398});399400Table({401name: "crm_support_messages",402fields: {403id: ID,404ticket_id: {405type: "integer",406desc: "Support ticket id that this message is connected to.",407},408created: {409type: "timestamp",410desc: "When the message was created. (We may save periodically before actually marking it sent.)",411},412last_edited: {413type: "timestamp",414desc: "When this message was actually sent.",415},416sent_by: PERSON,417body: {418type: "string",419desc: "Actual content of the message. This is interpretted as markdown.",420render: {421type: "markdown",422editable: true,423maxLength: 20000,424},425},426internal: {427type: "boolean",428desc: "If true, the message is internal and only visible to support staff.",429render: {430type: "boolean",431editable: true,432},433},434},435rules: {436desc: "Support Messages",437primary_key: "id",438user_query: {439get: {440pg_where: [],441admin: true,442fields: {443id: null,444ticket_id: null,445created: null,446last_edited: null,447sent_by: null,448body: null,449internal: null,450},451},452set: {453admin: true,454fields: {455id: true,456ticket_id: true,457created: true,458last_edited: true,459sent_by: true,460body: true,461internal: true,462},463required_fields: {464last_edited: true, // TODO: make automatic on any set query465},466},467},468},469});470471Table({472name: "crm_tasks",473fields: {474id: ID,475subject: {476type: "string",477pg_type: "VARCHAR(254)",478desc: "Short summary of this tasks.",479render: {480type: "text",481maxLength: 254,482editable: true,483},484},485due_date: {486title: "Due",487type: "timestamp",488desc: "When this task is due.",489render: {490type: "timestamp",491editable: true,492},493},494created: CREATED,495last_edited: LAST_EDITED,496closed: {497type: "timestamp",498title: "When closed",499desc: "When the task was marked as done.",500render: {501type: "timestamp",502editable: false,503},504},505done: {506type: "boolean",507desc: "The task is done.",508render: {509type: "boolean",510editable: true,511whenField: "closed",512},513},514status: STATUS_FIELD,515progress: {516type: "integer",517desc: "Progress on this task, as a number from 0 to 100.",518render: {519type: "percent",520editable: true,521steps: 5,522},523},524priority: PRORITIES_FIELD,525support_ticket: {526type: "integer",527desc: "Support ticket that this task is connected to, if any.",528},529people: PEOPLE,530organizations: ORGANIZATIONS,531created_by: CREATED_BY,532last_modified_by: LAST_MODIFIED_BY,533assignee: ASSIGNEE,534cc: {535type: "array",536pg_type: "UUID[]",537desc: "Zero or more accounts that care to be contacted/notified about updates to this task.",538},539tags: TAGS_FIELD,540description: {541type: "string",542desc: "Full markdown task description",543render: {544type: "markdown",545editable: true,546},547},548},549rules: {550desc: "Tasks",551primary_key: "id",552user_query: {553get: {554pg_where: [],555admin: true,556fields: {557id: null,558subject: null,559due_date: null,560created: null,561done: null,562closed: null,563last_edited: null,564status: null,565progress: null,566priority: null,567people: null,568organizations: null,569support_ticket: null,570created_by: null,571last_modified_by: null,572assignee: null,573cc: null,574tags: null,575description: null,576},577},578set: {579admin: true,580fields: {581id: true,582subject: true,583due_date: true,584created: true,585done: true,586closed: true,587last_edited: true,588status: true,589progress: true,590priority: true,591people: true,592organizations: null,593support_ticket: true,594created_by: true,595last_modified_by: true,596assignee: true,597cc: true,598tags: true,599description: true,600},601required_fields: {602last_edited: true, // TODO: make automatic on any set query603},604},605},606},607});608609// Table of all hashtags across our crm system. Note that these settings610// are very global. We may later make a similar table that is scoped to611// a project, file, user, etc...612Table({613name: "crm_tags",614fields: {615id: ID,616name: {617title: "Tag",618type: "string",619desc: "The name of the tag.",620pg_type: "VARCHAR(30)",621render: { type: "text", editable: true, maxLength: 30, tag: true },622unique: true,623},624icon: {625type: "string",626desc: "Name of icon to show with tag",627pg_type: "VARCHAR(100)", // ???628render: { type: "icon", editable: true },629},630description: {631type: "string",632desc: "Description of the tag.",633pg_type: "VARCHAR(254)",634render: { type: "markdown", editable: true },635},636color: {637type: "string",638desc: "color",639pg_type: "VARCHAR(30)",640render: { type: "color", editable: true },641},642notes: NOTES,643created: CREATED,644last_edited: LAST_EDITED,645last_modified_by: LAST_MODIFIED_BY,646},647rules: {648desc: "Table of all tags across our crm system.",649primary_key: "id",650user_query: {651get: {652admin: true,653pg_where: [],654fields: {655id: null,656name: null,657icon: null,658description: null,659notes: null,660color: null,661created: null,662last_edited: null,663last_modified_by: null,664},665},666set: {667admin: true,668fields: {669id: true,670name: true,671icon: true,672description: true,673notes: true,674color: true,675created: true,676last_edited: true,677last_modified_by: true,678},679required_fields: {680last_edited: true, // TODO: make automatic on any set query681},682},683},684},685});686687Table({688name: "crm_leads",689fields: {690id: ID,691created: CREATED,692last_edited: LAST_EDITED,693people: PEOPLE,694deleted: {695type: "boolean",696desc: "True if the lead has been deleted.",697},698notes: {699type: "string",700desc: "Open ended text in markdown about this lead.",701render: { type: "markdown", editable: true },702},703assignee: ASSIGNEE,704tags: TAGS_FIELD,705status: {706type: "string",707pg_type: "VARCHAR(30)",708desc: "Status of this lead",709render: {710type: "select",711editable: true,712options: [713"Contact in Future",714"Attempted to Contact",715"Contacted",716"Junk Lead",717"Lost Lead",718"Not Contacted",719"Pre Qualified",720"Not Qualified",721],722colors: [723yellow[5],724green[4],725green[5],726red[5],727red[6],728yellow[5],729blue[5],730blue[6],731],732},733},734rating: {735type: "string",736pg_type: "VARCHAR(30)",737desc: "Rating of this lead",738render: {739type: "select",740editable: true,741priority: true,742options: [743"-None-",744"Shut Down",745"Project Canceled",746"Market Failed",747"Active",748"Acquired",749],750colors: [yellow[5], red[4], red[5], red[6], green[5], blue[5]],751},752},753annual_revenue: {754type: "number",755desc: "Rough estimate of possible annual revenue that could result from this lead.",756render: { type: "number", editable: true, format: "money", min: 0 },757},758},759rules: {760desc: "CRM Leads",761primary_key: "id",762user_query: {763get: {764pg_where: [],765admin: true,766fields: {767id: null,768created: null,769last_edited: null,770people: null,771deleted: null,772notes: null,773tags: null,774assignee: null,775status: null,776rating: null,777annual_revenue: null,778},779},780set: {781admin: true,782fields: {783id: true,784created: true,785last_edited: true,786people: true,787deleted: true,788notes: true,789tags: true,790assignee: true,791status: true,792rating: true,793annual_revenue: true,794},795required_fields: {796last_edited: true,797},798},799},800},801});802803804