@bash-app/bash-common 30.284.0 → 30.285.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/definitions.d.ts +3 -2
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +3 -2
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +15 -5
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/icebreakerPrompts.d.ts +9 -0
- package/dist/icebreakerPrompts.d.ts.map +1 -0
- package/dist/icebreakerPrompts.js +77 -0
- package/dist/icebreakerPrompts.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mirroredPrismaEnums.d.ts +14 -0
- package/dist/mirroredPrismaEnums.d.ts.map +1 -1
- package/dist/mirroredPrismaEnums.js +13 -0
- package/dist/mirroredPrismaEnums.js.map +1 -1
- package/dist/venueMatch.d.ts +165 -0
- package/dist/venueMatch.d.ts.map +1 -0
- package/dist/venueMatch.js +68 -0
- package/dist/venueMatch.js.map +1 -0
- package/package.json +1 -1
- package/prisma/schema.prisma +248 -13
- package/src/definitions.ts +2 -2
- package/src/extendedSchemas.ts +25 -11
- package/src/icebreakerPrompts.ts +75 -0
- package/src/index.ts +2 -0
- package/src/mirroredPrismaEnums.ts +16 -0
- package/src/venueMatch.ts +202 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared shapes for the Venue Match pipeline (retrieve → score → explain).
|
|
3
|
+
*
|
|
4
|
+
* The api worker owns the Zod runtime validation (api/src/services/venueMatch/);
|
|
5
|
+
* this file is the type-only source of truth read by both the api and bash-app
|
|
6
|
+
* (host suggestion cards + admin supply-leads pipeline).
|
|
7
|
+
*
|
|
8
|
+
* Persisted JSON columns map exactly to these interfaces:
|
|
9
|
+
* - `VenueMatchRun.intent` → `VenueMatchIntent`
|
|
10
|
+
* - `VenueMatchCandidate.scoreBreakdown` → `VenueMatchScoreBreakdown`
|
|
11
|
+
* - `VenueMatchCandidate.reasons` → `string[]` (host-facing copy)
|
|
12
|
+
* - `VenueMatchCandidate.displaySnapshot` → `VenueCandidateDisplay`
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** Where a candidate came from. Mirrors prisma enum `VenueMatchCandidateSource`. */
|
|
16
|
+
export const VENUE_MATCH_SOURCES = {
|
|
17
|
+
Marketplace: "Marketplace",
|
|
18
|
+
GooglePlaces: "GooglePlaces",
|
|
19
|
+
} as const;
|
|
20
|
+
export type VenueMatchCandidateSource =
|
|
21
|
+
(typeof VENUE_MATCH_SOURCES)[keyof typeof VENUE_MATCH_SOURCES];
|
|
22
|
+
|
|
23
|
+
/** Host interaction with a surfaced candidate. Mirrors prisma enum `VenueMatchHostAction`. */
|
|
24
|
+
export const VENUE_MATCH_HOST_ACTIONS = {
|
|
25
|
+
None: "None",
|
|
26
|
+
Viewed: "Viewed",
|
|
27
|
+
Accepted: "Accepted",
|
|
28
|
+
AcceptedOffPlatform: "AcceptedOffPlatform",
|
|
29
|
+
Dismissed: "Dismissed",
|
|
30
|
+
CalledPhone: "CalledPhone",
|
|
31
|
+
InvitedVenue: "InvitedVenue",
|
|
32
|
+
} as const;
|
|
33
|
+
export type VenueMatchHostAction =
|
|
34
|
+
(typeof VENUE_MATCH_HOST_ACTIONS)[keyof typeof VENUE_MATCH_HOST_ACTIONS];
|
|
35
|
+
|
|
36
|
+
/** Sales pipeline stage. Mirrors prisma enum `VenueSupplyLeadStage`. */
|
|
37
|
+
export const VENUE_SUPPLY_LEAD_STAGES = {
|
|
38
|
+
Surfaced: "Surfaced",
|
|
39
|
+
Prioritized: "Prioritized",
|
|
40
|
+
Queued: "Queued",
|
|
41
|
+
Contacted: "Contacted",
|
|
42
|
+
Interested: "Interested",
|
|
43
|
+
DemoScheduled: "DemoScheduled",
|
|
44
|
+
Listed: "Listed",
|
|
45
|
+
Declined: "Declined",
|
|
46
|
+
DoNotContact: "DoNotContact",
|
|
47
|
+
} as const;
|
|
48
|
+
export type VenueSupplyLeadStage =
|
|
49
|
+
(typeof VENUE_SUPPLY_LEAD_STAGES)[keyof typeof VENUE_SUPPLY_LEAD_STAGES];
|
|
50
|
+
|
|
51
|
+
/** Admin display labels — single source for the pipeline UI + CSV export. */
|
|
52
|
+
export const VenueSupplyLeadStageLabel: Record<VenueSupplyLeadStage, string> = {
|
|
53
|
+
Surfaced: "Surfaced",
|
|
54
|
+
Prioritized: "Hot lead",
|
|
55
|
+
Queued: "Queued for outreach",
|
|
56
|
+
Contacted: "Contacted",
|
|
57
|
+
Interested: "Interested",
|
|
58
|
+
DemoScheduled: "Demo scheduled",
|
|
59
|
+
Listed: "Listed on Bash",
|
|
60
|
+
Declined: "Declined",
|
|
61
|
+
DoNotContact: "Do not contact",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Stages a rep can manually transition to from the admin UI. */
|
|
65
|
+
export const VENUE_SUPPLY_LEAD_REP_STAGES: VenueSupplyLeadStage[] = [
|
|
66
|
+
"Queued",
|
|
67
|
+
"Contacted",
|
|
68
|
+
"Interested",
|
|
69
|
+
"DemoScheduled",
|
|
70
|
+
"Declined",
|
|
71
|
+
"DoNotContact",
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Structured intent extracted from the host's prompt + current event fields.
|
|
76
|
+
* Persisted as `VenueMatchRun.intent` (Json column).
|
|
77
|
+
* All fields nullable — the scorer omits weights for missing signals.
|
|
78
|
+
*/
|
|
79
|
+
export interface VenueMatchIntent {
|
|
80
|
+
/** e.g. "bachelor party", "baby shower" — free text, lowercased */
|
|
81
|
+
occasion: string | null;
|
|
82
|
+
/** From amountOfGuests.expected or parsed from prompt */
|
|
83
|
+
guestCount: number | null;
|
|
84
|
+
city: string | null;
|
|
85
|
+
state: string | null;
|
|
86
|
+
/** Geocoded anchor for distance scoring (host geo → profile city → event city) */
|
|
87
|
+
anchorLat: number | null;
|
|
88
|
+
anchorLng: number | null;
|
|
89
|
+
/** e.g. "upscale", "casual" */
|
|
90
|
+
vibe: string | null;
|
|
91
|
+
/** Total budget in cents if the host mentioned one */
|
|
92
|
+
budgetCents: number | null;
|
|
93
|
+
/** BashEvent.eventType at run time */
|
|
94
|
+
eventType: string | null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Per-factor contribution. `weight` is the normalized weight actually applied (0..1). */
|
|
98
|
+
export interface VenueMatchFactorScore {
|
|
99
|
+
/** Raw factor score 0..100 before weighting */
|
|
100
|
+
score: number;
|
|
101
|
+
weight: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Persisted as `VenueMatchCandidate.scoreBreakdown` (Json).
|
|
106
|
+
* A factor is null when its signal was unavailable and its weight
|
|
107
|
+
* was re-distributed across the others.
|
|
108
|
+
*/
|
|
109
|
+
export interface VenueMatchScoreBreakdown {
|
|
110
|
+
distance: VenueMatchFactorScore | null;
|
|
111
|
+
capacity: VenueMatchFactorScore | null;
|
|
112
|
+
occasion: VenueMatchFactorScore | null;
|
|
113
|
+
rating: VenueMatchFactorScore | null;
|
|
114
|
+
price: VenueMatchFactorScore | null;
|
|
115
|
+
platformQuality: VenueMatchFactorScore | null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Snapshot of everything the host card needs, captured at run time so
|
|
120
|
+
* `GET /venue-match` never re-hits Google. Persisted as
|
|
121
|
+
* `VenueMatchCandidate.displaySnapshot` (Json).
|
|
122
|
+
*/
|
|
123
|
+
export interface VenueCandidateDisplay {
|
|
124
|
+
name: string;
|
|
125
|
+
photoUrl: string | null;
|
|
126
|
+
formattedAddress: string | null;
|
|
127
|
+
city: string | null;
|
|
128
|
+
state: string | null;
|
|
129
|
+
/** Bash rating for marketplace, Google rating for off-platform */
|
|
130
|
+
rating: number | null;
|
|
131
|
+
reviewCount: number | null;
|
|
132
|
+
capacity: number | null;
|
|
133
|
+
distanceMiles: number | null;
|
|
134
|
+
phone: string | null;
|
|
135
|
+
/** Marketplace only — deep link target */
|
|
136
|
+
serviceDetailPath: string | null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** One candidate as served to the host UI. */
|
|
140
|
+
export interface VenueMatchCandidateView {
|
|
141
|
+
id: string;
|
|
142
|
+
rank: number;
|
|
143
|
+
score: number;
|
|
144
|
+
source: VenueMatchCandidateSource;
|
|
145
|
+
serviceId: string | null;
|
|
146
|
+
/** Venue model id (for bashEvent.venueId) when marketplace */
|
|
147
|
+
venueId: string | null;
|
|
148
|
+
googlePlaceId: string | null;
|
|
149
|
+
reasons: string[];
|
|
150
|
+
scoreBreakdown: VenueMatchScoreBreakdown;
|
|
151
|
+
display: VenueCandidateDisplay;
|
|
152
|
+
hostAction: VenueMatchHostAction;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Response of `GET /event/:id/venue-match`. */
|
|
156
|
+
export interface VenueMatchRunView {
|
|
157
|
+
runId: string;
|
|
158
|
+
createdAt: string;
|
|
159
|
+
intent: VenueMatchIntent;
|
|
160
|
+
candidates: VenueMatchCandidateView[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Row shape for the admin supply-leads table + CSV export. */
|
|
164
|
+
export interface VenueSupplyLeadRow {
|
|
165
|
+
id: string;
|
|
166
|
+
name: string;
|
|
167
|
+
phoneE164: string | null;
|
|
168
|
+
city: string | null;
|
|
169
|
+
state: string | null;
|
|
170
|
+
fullAddress: string | null;
|
|
171
|
+
rating: number | null;
|
|
172
|
+
reviewCount: number | null;
|
|
173
|
+
category: string | null;
|
|
174
|
+
website: string | null;
|
|
175
|
+
googlePlaceId: string | null;
|
|
176
|
+
distinctEventCount: number;
|
|
177
|
+
topOccasions: string[];
|
|
178
|
+
firstSurfacedAt: string;
|
|
179
|
+
lastSurfacedAt: string;
|
|
180
|
+
stage: VenueSupplyLeadStage;
|
|
181
|
+
assignedToUserId: string | null;
|
|
182
|
+
assignedToName: string | null;
|
|
183
|
+
notes: string | null;
|
|
184
|
+
/** Set once the venue lists on Bash (conversion) */
|
|
185
|
+
serviceId: string | null;
|
|
186
|
+
catalogSource: string | null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface VenueSupplyLeadStats {
|
|
190
|
+
byStage: Record<VenueSupplyLeadStage, number>;
|
|
191
|
+
total: number;
|
|
192
|
+
hotLeads: number;
|
|
193
|
+
convertedTotal: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Feature flag values for `VENUE_MATCH_MODE`. */
|
|
197
|
+
export const VENUE_MATCH_MODES = [
|
|
198
|
+
"off",
|
|
199
|
+
"marketplace_only",
|
|
200
|
+
"marketplace_and_google",
|
|
201
|
+
] as const;
|
|
202
|
+
export type VenueMatchMode = (typeof VENUE_MATCH_MODES)[number];
|