Add category field

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-05-27 11:57:33 -07:00
parent 5e138b7d8e
commit 1254487eb4
17 changed files with 915 additions and 237 deletions

View File

@@ -84,11 +84,7 @@ func (i *BusinessImpact) UnmarshalJSON(data []byte) error {
}
func (i *BusinessImpact) UnmarshalText(text []byte) error {
var s string
if err := json.Unmarshal(text, &s); err != nil {
return err
}
s := string(text)
switch s {
case "LOW":
*i = BusinessImpactLow

View File

@@ -0,0 +1,84 @@
CREATE TYPE vendor_category AS ENUM (
'ANALYTICS',
'CLOUD_MONITORING',
'CLOUD_PROVIDER',
'COLLABORATION',
'CUSTOMER_SUPPORT',
'DATA_STORAGE_AND_PROCESSING',
'DOCUMENT_MANAGEMENT',
'EMPLOYEE_MANAGEMENT',
'ENGINEERING',
'FINANCE',
'IDENTITY_PROVIDER',
'IT',
'MARKETING',
'OFFICE_OPERATIONS',
'OTHER',
'PASSWORD_MANAGEMENT',
'PRODUCT_AND_DESIGN',
'PROFESSIONAL_SERVICES',
'RECRUITING',
'SALES',
'SECURITY',
'VERSION_CONTROL'
);
ALTER TABLE vendors DROP COLUMN IF EXISTS category;
ALTER TABLE vendors ADD COLUMN category vendor_category NOT NULL DEFAULT 'OTHER';
-- Update categories based on the vendor data.json mappings
UPDATE vendors SET category = 'ANALYTICS' WHERE name IN ('Segment', 'Plausible Analytics', 'PostHog');
UPDATE vendors SET category = 'CLOUD_MONITORING' WHERE name IN ('Datadog', 'New Relic', 'Better Stack');
UPDATE vendors SET category = 'CLOUD_PROVIDER' WHERE name IN (
'Amazon Web Services (AWS)', 'Microsoft Azure', 'Google Cloud Platform', 'Cloudflare',
'Vercel', 'Fly.io', 'Latitude.sh', 'Google', 'Heroku', 'Porter', 'OVHcloud global',
'OVHcloud US', 'bunny.net'
);
UPDATE vendors SET category = 'COLLABORATION' WHERE name IN (
'Slack', 'Microsoft 365', 'Cal.com', 'Zoom', 'Sendgrid', 'Google Workspace',
'Signal', 'monday.com', 'Calendly', 'Twilio', 'Otter.ai', 'Claap', 'ClickUp'
);
UPDATE vendors SET category = 'CUSTOMER_SUPPORT' WHERE name = 'Pylon';
UPDATE vendors SET category = 'DATA_STORAGE_AND_PROCESSING' WHERE name IN (
'Supabase', 'PlanetScale', 'ClickHouse', 'Airtable', 'Upstash'
);
UPDATE vendors SET category = 'DOCUMENT_MANAGEMENT' WHERE name = 'Notion';
UPDATE vendors SET category = 'EMPLOYEE_MANAGEMENT' WHERE name IN ('Gusto', 'Checkr', 'Rippling');
UPDATE vendors SET category = 'ENGINEERING' WHERE name IN (
'Sentry', 'npm', 'Atlassian', 'Algolia', 'Mintlify', 'Linear', 'Langfuse',
'OpenAI', 'Anthropic', 'Cursor', 'Together AI', 'Docker', 'jsDelivr'
);
UPDATE vendors SET category = 'FINANCE' WHERE name IN (
'Stripe', 'Pulley', 'Mercury', 'Brex', 'Ramp', 'Carta', 'Qonto', 'Spendesk', 'Puzzle', 'Vouch'
);
UPDATE vendors SET category = 'IDENTITY_PROVIDER' WHERE name IN ('Auth0', 'Clerk');
UPDATE vendors SET category = 'IT' WHERE name IN ('Namecheap', 'Plesk');
UPDATE vendors SET category = 'MARKETING' WHERE name IN (
'Hubspot', 'Mailchimp', 'Resend', 'Brevo', 'Loops', 'Perplexity'
);
UPDATE vendors SET category = 'PASSWORD_MANAGEMENT' WHERE name IN ('1Password', 'Bitwarden');
UPDATE vendors SET category = 'PRODUCT_AND_DESIGN' WHERE name IN (
'Framer', 'Figma', 'Webflow', 'Pitch'
);
UPDATE vendors SET category = 'RECRUITING' WHERE name = 'Lever';
UPDATE vendors SET category = 'SALES' WHERE name IN ('Apollo.io', 'Pipedrive', 'folk');
UPDATE vendors SET category = 'SECURITY' WHERE name IN ('Tailscale', 'Probo');
UPDATE vendors SET category = 'VERSION_CONTROL' WHERE name = 'Github';

View File

@@ -28,26 +28,26 @@ import (
type (
Vendor struct {
ID gid.GID `db:"id"`
OrganizationID gid.GID `db:"organization_id"`
Name string `db:"name"`
Description *string `db:"description"`
Category string `db:"category"`
HeadquarterAddress *string `db:"headquarter_address"`
LegalName *string `db:"legal_name"`
WebsiteURL *string `db:"website_url"`
PrivacyPolicyURL *string `db:"privacy_policy_url"`
ServiceLevelAgreementURL *string `db:"service_level_agreement_url"`
DataProcessingAgreementURL *string `db:"data_processing_agreement_url"`
Certifications []string `db:"certifications"`
BusinessOwnerID *gid.GID `db:"business_owner_id"`
SecurityOwnerID *gid.GID `db:"security_owner_id"`
StatusPageURL *string `db:"status_page_url"`
TermsOfServiceURL *string `db:"terms_of_service_url"`
SecurityPageURL *string `db:"security_page_url"`
TrustPageURL *string `db:"trust_page_url"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID gid.GID `db:"id"`
OrganizationID gid.GID `db:"organization_id"`
Name string `db:"name"`
Description *string `db:"description"`
Category VendorCategory `db:"category"`
HeadquarterAddress *string `db:"headquarter_address"`
LegalName *string `db:"legal_name"`
WebsiteURL *string `db:"website_url"`
PrivacyPolicyURL *string `db:"privacy_policy_url"`
ServiceLevelAgreementURL *string `db:"service_level_agreement_url"`
DataProcessingAgreementURL *string `db:"data_processing_agreement_url"`
Certifications []string `db:"certifications"`
BusinessOwnerID *gid.GID `db:"business_owner_id"`
SecurityOwnerID *gid.GID `db:"security_owner_id"`
StatusPageURL *string `db:"status_page_url"`
TermsOfServiceURL *string `db:"terms_of_service_url"`
SecurityPageURL *string `db:"security_page_url"`
TrustPageURL *string `db:"trust_page_url"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
Vendors []*Vendor

View File

@@ -0,0 +1,228 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package coredata
import (
"database/sql/driver"
"encoding/json"
"fmt"
)
type VendorCategory string
const (
VendorCategoryAnalytics VendorCategory = "ANALYTICS"
VendorCategoryCloudMonitoring VendorCategory = "CLOUD_MONITORING"
VendorCategoryCloudProvider VendorCategory = "CLOUD_PROVIDER"
VendorCategoryCollaboration VendorCategory = "COLLABORATION"
VendorCategoryCustomerSupport VendorCategory = "CUSTOMER_SUPPORT"
VendorCategoryDataStorageAndProcessing VendorCategory = "DATA_STORAGE_AND_PROCESSING"
VendorCategoryDocumentManagement VendorCategory = "DOCUMENT_MANAGEMENT"
VendorCategoryEmployeeManagement VendorCategory = "EMPLOYEE_MANAGEMENT"
VendorCategoryEngineering VendorCategory = "ENGINEERING"
VendorCategoryFinance VendorCategory = "FINANCE"
VendorCategoryIdentityProvider VendorCategory = "IDENTITY_PROVIDER"
VendorCategoryIT VendorCategory = "IT"
VendorCategoryMarketing VendorCategory = "MARKETING"
VendorCategoryOfficeOperations VendorCategory = "OFFICE_OPERATIONS"
VendorCategoryOther VendorCategory = "OTHER"
VendorCategoryPasswordManagement VendorCategory = "PASSWORD_MANAGEMENT"
VendorCategoryProductAndDesign VendorCategory = "PRODUCT_AND_DESIGN"
VendorCategoryProfessionalServices VendorCategory = "PROFESSIONAL_SERVICES"
VendorCategoryRecruiting VendorCategory = "RECRUITING"
VendorCategorySales VendorCategory = "SALES"
VendorCategorySecurity VendorCategory = "SECURITY"
VendorCategoryVersionControl VendorCategory = "VERSION_CONTROL"
)
func (i VendorCategory) String() string {
return string(i)
}
func (i *VendorCategory) Scan(value interface{}) error {
switch v := value.(type) {
case string:
switch v {
case "ANALYTICS":
*i = VendorCategoryAnalytics
case "CLOUD_MONITORING":
*i = VendorCategoryCloudMonitoring
case "CLOUD_PROVIDER":
*i = VendorCategoryCloudProvider
case "COLLABORATION":
*i = VendorCategoryCollaboration
case "CUSTOMER_SUPPORT":
*i = VendorCategoryCustomerSupport
case "DATA_STORAGE_AND_PROCESSING":
*i = VendorCategoryDataStorageAndProcessing
case "DOCUMENT_MANAGEMENT":
*i = VendorCategoryDocumentManagement
case "EMPLOYEE_MANAGEMENT":
*i = VendorCategoryEmployeeManagement
case "ENGINEERING":
*i = VendorCategoryEngineering
case "FINANCE":
*i = VendorCategoryFinance
case "IDENTITY_PROVIDER":
*i = VendorCategoryIdentityProvider
case "IT":
*i = VendorCategoryIT
case "MARKETING":
*i = VendorCategoryMarketing
case "OFFICE_OPERATIONS":
*i = VendorCategoryOfficeOperations
case "OTHER":
*i = VendorCategoryOther
case "PASSWORD_MANAGEMENT":
*i = VendorCategoryPasswordManagement
case "PRODUCT_AND_DESIGN":
*i = VendorCategoryProductAndDesign
case "PROFESSIONAL_SERVICES":
*i = VendorCategoryProfessionalServices
case "RECRUITING":
*i = VendorCategoryRecruiting
case "SALES":
*i = VendorCategorySales
case "SECURITY":
*i = VendorCategorySecurity
case "VERSION_CONTROL":
*i = VendorCategoryVersionControl
default:
return fmt.Errorf("invalid VendorCategory value: %q", v)
}
default:
return fmt.Errorf("unsupported type for VendorCategory: %T", value)
}
return nil
}
func (i VendorCategory) Value() (driver.Value, error) {
return i.String(), nil
}
func (i VendorCategory) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
func (i *VendorCategory) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
switch s {
case "ANALYTICS":
*i = VendorCategoryAnalytics
case "CLOUD_MONITORING":
*i = VendorCategoryCloudMonitoring
case "CLOUD_PROVIDER":
*i = VendorCategoryCloudProvider
case "COLLABORATION":
*i = VendorCategoryCollaboration
case "CUSTOMER_SUPPORT":
*i = VendorCategoryCustomerSupport
case "DATA_STORAGE_AND_PROCESSING":
*i = VendorCategoryDataStorageAndProcessing
case "DOCUMENT_MANAGEMENT":
*i = VendorCategoryDocumentManagement
case "EMPLOYEE_MANAGEMENT":
*i = VendorCategoryEmployeeManagement
case "ENGINEERING":
*i = VendorCategoryEngineering
case "FINANCE":
*i = VendorCategoryFinance
case "IDENTITY_PROVIDER":
*i = VendorCategoryIdentityProvider
case "IT":
*i = VendorCategoryIT
case "MARKETING":
*i = VendorCategoryMarketing
case "OFFICE_OPERATIONS":
*i = VendorCategoryOfficeOperations
case "OTHER":
*i = VendorCategoryOther
case "PASSWORD_MANAGEMENT":
*i = VendorCategoryPasswordManagement
case "PRODUCT_AND_DESIGN":
*i = VendorCategoryProductAndDesign
case "PROFESSIONAL_SERVICES":
*i = VendorCategoryProfessionalServices
case "RECRUITING":
*i = VendorCategoryRecruiting
case "SALES":
*i = VendorCategorySales
case "SECURITY":
*i = VendorCategorySecurity
case "VERSION_CONTROL":
*i = VendorCategoryVersionControl
default:
return fmt.Errorf("invalid VendorCategory value: %q", s)
}
return nil
}
func (i *VendorCategory) UnmarshalText(text []byte) error {
s := string(text)
switch s {
case "ANALYTICS":
*i = VendorCategoryAnalytics
case "CLOUD_MONITORING":
*i = VendorCategoryCloudMonitoring
case "CLOUD_PROVIDER":
*i = VendorCategoryCloudProvider
case "COLLABORATION":
*i = VendorCategoryCollaboration
case "CUSTOMER_SUPPORT":
*i = VendorCategoryCustomerSupport
case "DATA_STORAGE_AND_PROCESSING":
*i = VendorCategoryDataStorageAndProcessing
case "DOCUMENT_MANAGEMENT":
*i = VendorCategoryDocumentManagement
case "EMPLOYEE_MANAGEMENT":
*i = VendorCategoryEmployeeManagement
case "ENGINEERING":
*i = VendorCategoryEngineering
case "FINANCE":
*i = VendorCategoryFinance
case "IDENTITY_PROVIDER":
*i = VendorCategoryIdentityProvider
case "IT":
*i = VendorCategoryIT
case "MARKETING":
*i = VendorCategoryMarketing
case "OFFICE_OPERATIONS":
*i = VendorCategoryOfficeOperations
case "OTHER":
*i = VendorCategoryOther
case "PASSWORD_MANAGEMENT":
*i = VendorCategoryPasswordManagement
case "PRODUCT_AND_DESIGN":
*i = VendorCategoryProductAndDesign
case "PROFESSIONAL_SERVICES":
*i = VendorCategoryProfessionalServices
case "RECRUITING":
*i = VendorCategoryRecruiting
case "SALES":
*i = VendorCategorySales
case "SECURITY":
*i = VendorCategorySecurity
case "VERSION_CONTROL":
*i = VendorCategoryVersionControl
default:
return fmt.Errorf("invalid VendorCategory value: %q", s)
}
return nil
}