@pylonsync/create-pylon 0.11.1 → 0.11.3
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/bin/create-pylon.js +1 -1
- package/package.json +1 -1
- package/templates/_root/AGENTS.md +1 -1
- package/templates/agency/AGENTS.md +1 -1
- package/templates/agency/app/(marketing)/contact-form.tsx +22 -32
- package/templates/agency/app/(marketing)/layout.tsx +36 -64
- package/templates/agency/app/(marketing)/not-found.tsx +6 -8
- package/templates/agency/app/(marketing)/page.tsx +93 -144
- package/templates/agency/app/(marketing)/work/[slug]/page.tsx +69 -71
- package/templates/agency/app/(marketing)/work/page.tsx +20 -17
- package/templates/agency/app/globals.css +15 -6
- package/templates/agency/app.ts +10 -0
- package/templates/agency/components/marketing.tsx +40 -104
- package/templates/agency/lib/site.config.ts +34 -52
- package/templates/agency/public/images/hero.jpg +0 -0
- package/templates/agency/public/images/team/claire-donovan.jpg +0 -0
- package/templates/agency/public/images/team/dana-okafor.jpg +0 -0
- package/templates/agency/public/images/team/marcus-lee.jpg +0 -0
- package/templates/agency/public/images/work/atlas-health.jpg +0 -0
- package/templates/agency/public/images/work/cohort.jpg +0 -0
- package/templates/agency/public/images/work/ledger.jpg +0 -0
- package/templates/agency/public/images/work/vela.jpg +0 -0
- package/templates/ai-chat/AGENTS.md +1 -1
- package/templates/ai-studio/AGENTS.md +1 -1
- package/templates/barebones/AGENTS.md +1 -1
- package/templates/chat/AGENTS.md +1 -1
- package/templates/consumer/AGENTS.md +1 -1
- package/templates/consumer/README.md +39 -23
- package/templates/consumer/app/(app)/explore/page.tsx +13 -0
- package/templates/consumer/app/(app)/layout.tsx +17 -0
- package/templates/consumer/app/(app)/p/[id]/page.tsx +13 -0
- package/templates/consumer/app/(app)/page.tsx +15 -0
- package/templates/consumer/app/(app)/u/[username]/page.tsx +14 -0
- package/templates/consumer/app/error.tsx +1 -1
- package/templates/consumer/app/globals.css +25 -0
- package/templates/consumer/app/layout.tsx +3 -10
- package/templates/consumer/app/llms.ts +10 -10
- package/templates/consumer/app/not-found.tsx +9 -22
- package/templates/consumer/app/robots.ts +3 -4
- package/templates/consumer/app/sitemap.ts +7 -21
- package/templates/consumer/app.ts +152 -33
- package/templates/consumer/components/social/app-chrome.tsx +109 -0
- package/templates/consumer/components/social/avatar.tsx +50 -0
- package/templates/consumer/components/social/comment-form.tsx +51 -0
- package/templates/consumer/components/social/create-post.tsx +155 -0
- package/templates/consumer/components/social/edit-profile.tsx +103 -0
- package/templates/consumer/components/social/explore-screen.tsx +23 -0
- package/templates/consumer/components/social/home-screen.tsx +161 -0
- package/templates/consumer/components/social/post-card.tsx +77 -0
- package/templates/consumer/components/social/post-grid.tsx +46 -0
- package/templates/consumer/components/social/post-parts.tsx +146 -0
- package/templates/consumer/components/social/post-screen.tsx +173 -0
- package/templates/consumer/components/social/profile-screen.tsx +146 -0
- package/templates/consumer/components/social/rich-text.tsx +22 -0
- package/templates/consumer/components/social/session.tsx +43 -0
- package/templates/consumer/components/social/use-social.ts +86 -0
- package/templates/consumer/functions/addComment.ts +27 -0
- package/templates/consumer/functions/createPost.ts +39 -0
- package/templates/consumer/functions/ensureProfile.ts +39 -0
- package/templates/consumer/functions/seedFeed.ts +38 -0
- package/templates/consumer/functions/updateProfile.ts +61 -0
- package/templates/consumer/lib/seed.ts +192 -0
- package/templates/consumer/lib/site.ts +6 -0
- package/templates/consumer/lib/social.ts +245 -0
- package/templates/consumer/tests/social.test.ts +157 -0
- package/templates/creator/AGENTS.md +1 -1
- package/templates/creator/app/(marketing)/layout.tsx +35 -69
- package/templates/creator/app/(marketing)/newsletter-signup.tsx +15 -26
- package/templates/creator/app/(marketing)/not-found.tsx +8 -6
- package/templates/creator/app/(marketing)/page.tsx +90 -106
- package/templates/creator/app/globals.css +14 -0
- package/templates/creator/app/layout.tsx +1 -0
- package/templates/creator/app.ts +10 -0
- package/templates/creator/components/marketing.tsx +28 -89
- package/templates/creator/lib/site.config.ts +51 -29
- package/templates/creator/public/images/headshot.jpg +0 -0
- package/templates/crm/AGENTS.md +1 -1
- package/templates/crm/lib/seed.ts +153 -21
- package/templates/directory/AGENTS.md +1 -1
- package/templates/directory/app/(marketing)/directory-browse.tsx +99 -137
- package/templates/directory/app/(marketing)/layout.tsx +37 -88
- package/templates/directory/app/(marketing)/not-found.tsx +11 -10
- package/templates/directory/app/(marketing)/page.tsx +12 -33
- package/templates/directory/app/(marketing)/submit/page.tsx +9 -10
- package/templates/directory/app/(marketing)/submit-form.tsx +26 -26
- package/templates/directory/app/globals.css +15 -4
- package/templates/directory/app.ts +10 -0
- package/templates/directory/components/marketing.tsx +27 -91
- package/templates/directory/lib/site.config.ts +13 -24
- package/templates/helpdesk/AGENTS.md +1 -1
- package/templates/helpdesk/lib/seed.ts +188 -104
- package/templates/inventory/AGENTS.md +1 -1
- package/templates/inventory/lib/seed.ts +175 -44
- package/templates/invoices/AGENTS.md +1 -1
- package/templates/invoices/lib/seed.ts +74 -89
- package/templates/local-service/AGENTS.md +1 -1
- package/templates/local-service/app/(marketing)/booking-widget.tsx +31 -31
- package/templates/local-service/app/(marketing)/layout.tsx +25 -37
- package/templates/local-service/app/(marketing)/not-found.tsx +4 -4
- package/templates/local-service/app/(marketing)/page.tsx +145 -139
- package/templates/local-service/app/globals.css +11 -0
- package/templates/local-service/app/layout.tsx +2 -0
- package/templates/local-service/app.ts +9 -0
- package/templates/local-service/components/marketing.tsx +14 -39
- package/templates/local-service/lib/site.config.ts +16 -23
- package/templates/local-service/public/images/hero.jpg +0 -0
- package/templates/marketplace/AGENTS.md +1 -1
- package/templates/marketplace/client/SellForm.tsx +2 -0
- package/templates/projects/AGENTS.md +1 -1
- package/templates/projects/lib/seed.ts +103 -32
- package/templates/restaurant/AGENTS.md +1 -1
- package/templates/restaurant/app/(marketing)/layout.tsx +26 -48
- package/templates/restaurant/app/(marketing)/page.tsx +146 -123
- package/templates/restaurant/app/globals.css +11 -0
- package/templates/restaurant/app/layout.tsx +1 -0
- package/templates/restaurant/app.ts +10 -0
- package/templates/restaurant/components/marketing.tsx +10 -0
- package/templates/restaurant/lib/site.config.ts +16 -14
- package/templates/restaurant/public/images/bar.jpg +0 -0
- package/templates/restaurant/public/images/branzino.jpg +0 -0
- package/templates/restaurant/public/images/hearth.jpg +0 -0
- package/templates/restaurant/public/images/hero.jpg +0 -0
- package/templates/saas/AGENTS.md +1 -1
- package/templates/shop/AGENTS.md +1 -1
- package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
- package/templates/shop/public/images/products/linen.jpg +0 -0
- package/templates/todo/AGENTS.md +1 -1
- package/templates/waitlist/AGENTS.md +1 -1
- package/templates/waitlist/app/(marketing)/layout.tsx +39 -85
- package/templates/waitlist/app/(marketing)/not-found.tsx +8 -9
- package/templates/waitlist/app/(marketing)/page.tsx +51 -86
- package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +43 -83
- package/templates/waitlist/app/globals.css +23 -0
- package/templates/waitlist/app/layout.tsx +1 -0
- package/templates/waitlist/app.ts +18 -0
- package/templates/waitlist/components/marketing.tsx +67 -81
- package/templates/waitlist/lib/site.config.ts +52 -59
- package/templates/consumer/app/feed-client.tsx +0 -159
- package/templates/consumer/app/page.tsx +0 -27
- package/templates/consumer/functions/_keep.ts +0 -13
- package/templates/consumer/functions/seedPosts.ts +0 -56
- package/templates/consumer/tests/example.test.ts +0 -12
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Demo data for a brand-new helpdesk.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// first-response window, so the breach state is
|
|
3
|
+
// The first sign-in seeds a working queue: twenty customers, forty tickets
|
|
4
|
+
// across every status and priority, and a message thread on each. Two open
|
|
5
|
+
// tickets are already past their first-response window, so the breach state is
|
|
6
|
+
// visible rather than theoretical.
|
|
6
7
|
//
|
|
7
8
|
// Pure data + pure shaping; `functions/seedWorkspace.ts` stays a thin wrapper.
|
|
8
9
|
|
|
@@ -36,114 +37,191 @@ export interface SeedMessage {
|
|
|
36
37
|
|
|
37
38
|
export const SEED_CUSTOMERS: SeedCustomer[] = [
|
|
38
39
|
{ key: "dana", name: "Dana Whitfield", email: "dana@northwind.co", company: "Northwind Logistics" },
|
|
40
|
+
{ key: "marcus", name: "Marcus Iyer", email: "marcus@northwind.co", company: "Northwind Logistics" },
|
|
39
41
|
{ key: "tom", name: "Tom Alvarez", email: "tom@riverbed.coffee", company: "Riverbed Coffee" },
|
|
40
42
|
{ key: "priya", name: "Priya Raman", email: "priya@hallmarkdental.com", company: "Hallmark Dental" },
|
|
41
43
|
{ key: "ben", name: "Ben Osei", email: "ben@quarry.design", company: "Quarry Design Co" },
|
|
42
44
|
{ key: "lena", name: "Lena Fischer", email: "lena@beaconproperty.com", company: "Beacon Property" },
|
|
45
|
+
{ key: "kevin", name: "Kevin Doyle", email: "kdoyle@larkspurclinics.com", company: "Larkspur Clinics" },
|
|
46
|
+
{ key: "rachel", name: "Rachel Stone", email: "rstone@meridianfreight.com", company: "Meridian Freight" },
|
|
47
|
+
{ key: "mike", name: "Mike Brennan", email: "mike@copperline.beer", company: "Copperline Brewing" },
|
|
48
|
+
{ key: "sarah", name: "Sarah Lindqvist", email: "sarah@tidewatermarine.com", company: "Tidewater Marine" },
|
|
49
|
+
{ key: "isabel", name: "Isabel Moreau", email: "isabel@sableandfinch.com", company: "Sable & Finch" },
|
|
50
|
+
{ key: "david", name: "David Park", email: "dpark@orchardlearning.org", company: "Orchard Learning" },
|
|
51
|
+
{ key: "hannah", name: "Hannah Weiss", email: "hannah@granitepeak.com", company: "Granite Peak Outfitters" },
|
|
52
|
+
{ key: "james", name: "James Whitaker", email: "jwhitaker@kestrelaviation.com", company: "Kestrel Aviation Services" },
|
|
53
|
+
{ key: "elena", name: "Elena Vasquez", email: "elena@bluefin.io", company: "Bluefin Analytics" },
|
|
54
|
+
{ key: "robert", name: "Robert Chen", email: "rchen@harborpointhotels.com", company: "Harbor Point Hotels" },
|
|
55
|
+
{ key: "patricia", name: "Patricia Nguyen", email: "pnguyen@summitcu.org", company: "Summit Credit Union" },
|
|
56
|
+
{ key: "walt", name: "Walt Jensen", email: "walt@pinecrestfarms.com", company: "Pinecrest Farms" },
|
|
57
|
+
{ key: "anita", name: "Anita Rao", email: "anita@vantagesolar.com", company: "Vantage Solar" },
|
|
58
|
+
{ key: "tara", name: "Tara Singh", email: "tara@cobaltstaffing.com", company: "Cobalt Staffing" },
|
|
43
59
|
];
|
|
44
60
|
|
|
45
61
|
export const SEED_TICKETS: SeedTicket[] = [
|
|
46
|
-
//
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
customer: "dana",
|
|
95
|
-
subject: "Webhook retries are firing twice",
|
|
96
|
-
status: "closed",
|
|
97
|
-
priority: "high",
|
|
98
|
-
age: 300,
|
|
99
|
-
respondedAgo: 290,
|
|
100
|
-
},
|
|
62
|
+
// Open, unanswered. The first two are past their first-response target.
|
|
63
|
+
{ key: "export", customer: "dana", subject: "Export is timing out on large date ranges", status: "open", priority: "urgent", age: 3, respondedAgo: null },
|
|
64
|
+
{ key: "sso", customer: "ben", subject: "SSO with Google Workspace: is it supported?", status: "open", priority: "normal", age: 30, respondedAgo: null },
|
|
65
|
+
{ key: "login-loop", customer: "rachel", subject: "Login redirects back to the sign-in page", status: "open", priority: "high", age: 2, respondedAgo: null },
|
|
66
|
+
{ key: "csv-dates", customer: "walt", subject: "CSV import reads dates as US format", status: "open", priority: "normal", age: 5, respondedAgo: null },
|
|
67
|
+
{ key: "role-perms", customer: "patricia", subject: "Viewer role can still edit custom fields", status: "open", priority: "high", age: 1, respondedAgo: null },
|
|
68
|
+
{ key: "dark-mode", customer: "hannah", subject: "Any plans for a dark theme?", status: "open", priority: "low", age: 9, respondedAgo: null },
|
|
69
|
+
{ key: "api-limit", customer: "elena", subject: "Hitting 429s on the reports endpoint", status: "open", priority: "high", age: 4, respondedAgo: null },
|
|
70
|
+
{ key: "duplicate-contacts", customer: "tara", subject: "Duplicate contacts after ATS sync", status: "open", priority: "normal", age: 12, respondedAgo: null },
|
|
71
|
+
|
|
72
|
+
// Open, answered, still with us.
|
|
73
|
+
{ key: "invite", customer: "tom", subject: "Can't invite a second manager to the account", status: "open", priority: "high", age: 6, respondedAgo: 5 },
|
|
74
|
+
{ key: "pdf-fonts", customer: "priya", subject: "PDF statements render with the wrong font", status: "open", priority: "normal", age: 20, respondedAgo: 17 },
|
|
75
|
+
{ key: "webhook-order", customer: "marcus", subject: "Webhook events arrive out of order", status: "open", priority: "high", age: 28, respondedAgo: 26 },
|
|
76
|
+
{ key: "mobile-upload", customer: "anita", subject: "Photo upload fails from the field app on iOS", status: "open", priority: "urgent", age: 7, respondedAgo: 6.5 },
|
|
77
|
+
{ key: "search-accents", customer: "isabel", subject: "Search does not match names with accents", status: "open", priority: "normal", age: 40, respondedAgo: 36 },
|
|
78
|
+
{ key: "timezone", customer: "robert", subject: "Scheduled reports send at the wrong hour", status: "open", priority: "normal", age: 50, respondedAgo: 45 },
|
|
79
|
+
{ key: "bulk-delete", customer: "david", subject: "Bulk delete stops after 200 rows", status: "open", priority: "normal", age: 60, respondedAgo: 58 },
|
|
80
|
+
{ key: "audit-log", customer: "kevin", subject: "Audit log missing permission changes", status: "open", priority: "high", age: 33, respondedAgo: 31 },
|
|
81
|
+
|
|
82
|
+
// Pending on the customer.
|
|
83
|
+
{ key: "invoice", customer: "priya", subject: "Invoice shows last month's plan", status: "pending", priority: "normal", age: 26, respondedAgo: 24 },
|
|
84
|
+
{ key: "domain", customer: "mike", subject: "Custom domain stuck on pending", status: "pending", priority: "normal", age: 72, respondedAgo: 70 },
|
|
85
|
+
{ key: "seat-count", customer: "james", subject: "Seat count on the invoice is higher than our users", status: "pending", priority: "normal", age: 90, respondedAgo: 88 },
|
|
86
|
+
{ key: "ssl-warning", customer: "sarah", subject: "Browser shows a certificate warning on the portal", status: "pending", priority: "high", age: 48, respondedAgo: 47 },
|
|
87
|
+
{ key: "gdpr-export", customer: "lena", subject: "Need a full data export for a GDPR request", status: "pending", priority: "normal", age: 100, respondedAgo: 96 },
|
|
88
|
+
{ key: "calendar-sync", customer: "kevin", subject: "Outlook calendar sync creates duplicates", status: "pending", priority: "normal", age: 130, respondedAgo: 128 },
|
|
89
|
+
{ key: "training", customer: "patricia", subject: "Onboarding session for the new branch team", status: "pending", priority: "low", age: 150, respondedAgo: 140 },
|
|
90
|
+
|
|
91
|
+
// Solved.
|
|
92
|
+
{ key: "mobile", customer: "lena", subject: "Mobile layout cuts off the listing photos", status: "solved", priority: "low", age: 120, respondedAgo: 110 },
|
|
93
|
+
{ key: "password-reset", customer: "hannah", subject: "Password reset email never arrives", status: "solved", priority: "high", age: 200, respondedAgo: 199 },
|
|
94
|
+
{ key: "report-totals", customer: "elena", subject: "Monthly report total does not match the dashboard", status: "solved", priority: "normal", age: 240, respondedAgo: 230 },
|
|
95
|
+
{ key: "slack", customer: "tara", subject: "Slack notifications stopped after the workspace rename", status: "solved", priority: "normal", age: 260, respondedAgo: 255 },
|
|
96
|
+
{ key: "print", customer: "walt", subject: "Printing a pick list cuts off the last column", status: "solved", priority: "low", age: 300, respondedAgo: 280 },
|
|
97
|
+
{ key: "two-factor", customer: "robert", subject: "Lost authenticator device, need 2FA reset", status: "solved", priority: "urgent", age: 320, respondedAgo: 319.5 },
|
|
98
|
+
{ key: "currency", customer: "sarah", subject: "Show amounts in SEK instead of USD", status: "solved", priority: "normal", age: 360, respondedAgo: 350 },
|
|
99
|
+
{ key: "attachment-size", customer: "david", subject: "Cannot attach files over 10 MB", status: "solved", priority: "normal", age: 400, respondedAgo: 390 },
|
|
100
|
+
|
|
101
|
+
// Closed.
|
|
102
|
+
{ key: "webhook", customer: "dana", subject: "Webhook retries are firing twice", status: "closed", priority: "high", age: 500, respondedAgo: 490 },
|
|
103
|
+
{ key: "billing-address", customer: "mike", subject: "Update the billing address on our account", status: "closed", priority: "low", age: 520, respondedAgo: 515 },
|
|
104
|
+
{ key: "old-import", customer: "tom", subject: "Import from the old system dropped some notes", status: "closed", priority: "normal", age: 600, respondedAgo: 590 },
|
|
105
|
+
{ key: "api-key", customer: "marcus", subject: "Rotate the API key for the warehouse integration", status: "closed", priority: "high", age: 650, respondedAgo: 648 },
|
|
106
|
+
{ key: "welcome", customer: "isabel", subject: "Where do I change the welcome email text?", status: "closed", priority: "low", age: 700, respondedAgo: 690 },
|
|
107
|
+
{ key: "rename-workspace", customer: "james", subject: "Rename our workspace", status: "closed", priority: "low", age: 720, respondedAgo: 715 },
|
|
108
|
+
{ key: "downtime", customer: "rachel", subject: "Portal was unreachable for 20 minutes this morning", status: "closed", priority: "urgent", age: 800, respondedAgo: 799.5 },
|
|
109
|
+
{ key: "cancel-trial", customer: "anita", subject: "Cancel the second trial workspace we created by mistake", status: "closed", priority: "normal", age: 900, respondedAgo: 880 },
|
|
101
110
|
];
|
|
102
111
|
|
|
103
112
|
export const SEED_MESSAGES: SeedMessage[] = [
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
},
|
|
113
|
+
{ ticket: "export", body: "Pulling a 90-day export just spins and eventually errors. 30 days is fine. This is blocking our month-end reporting.", fromCustomer: true, age: 3 },
|
|
114
|
+
{ ticket: "sso", body: "We are standardising on Google Workspace this quarter. Does your plan include SAML, or only OAuth sign-in?", fromCustomer: true, age: 30 },
|
|
115
|
+
{ ticket: "login-loop", body: "Since this morning, signing in sends me straight back to the login page. Cleared cookies, same thing. Two colleagues report the same.", fromCustomer: true, age: 2 },
|
|
116
|
+
{ ticket: "csv-dates", body: "Uploaded our delivery schedule and every date after the 12th of the month got rejected. We write dates day first.", fromCustomer: true, age: 5 },
|
|
117
|
+
{ ticket: "role-perms", body: "A user with the Viewer role changed the value of a custom field on a member record. That should not be possible. Please treat as urgent, we have an audit next week.", fromCustomer: true, age: 1 },
|
|
118
|
+
{ ticket: "dark-mode", body: "Our warehouse team uses the app at night and the white screens are hard on the eyes. Is a dark theme on the roadmap?", fromCustomer: true, age: 9 },
|
|
119
|
+
{ ticket: "api-limit", body: "Our nightly job started getting 429 responses on /reports around 02:00 UTC. We make about 1,200 calls in that window. Did the limit change?", fromCustomer: true, age: 4 },
|
|
120
|
+
{ ticket: "duplicate-contacts", body: "After enabling the ATS sync we now have two records for most candidates. One has the email in lowercase and one in mixed case.", fromCustomer: true, age: 12 },
|
|
121
|
+
|
|
122
|
+
{ ticket: "invite", body: "I added marcus@northwind.co but he never got the email and does not show in the members list.", fromCustomer: true, age: 6 },
|
|
123
|
+
{ ticket: "invite", body: "Thanks Tom. I can see the invite was created but the delivery bounced. Re-sending now and checking the domain's SPF record.", fromCustomer: false, age: 5 },
|
|
124
|
+
{ ticket: "invite", body: "Their MX is misconfigured. Flagging for the infra team rather than sending again blind.", fromCustomer: false, internal: true, age: 5 },
|
|
125
|
+
{ ticket: "invite", body: "Still nothing on his end. Can you add him manually?", fromCustomer: true, age: 2 },
|
|
126
|
+
|
|
127
|
+
{ ticket: "pdf-fonts", body: "The statements we send patients now render in a serif font instead of our configured one. Started this week.", fromCustomer: true, age: 20 },
|
|
128
|
+
{ ticket: "pdf-fonts", body: "Confirmed on our side. The font file on the CDN was replaced with a broken build on Monday. A fix is rolling out. Can you send one affected PDF so I can verify?", fromCustomer: false, age: 17 },
|
|
129
|
+
{ ticket: "pdf-fonts", body: "Attached. Also noticed the page numbers are off by one.", fromCustomer: true, age: 10 },
|
|
130
|
+
|
|
131
|
+
{ ticket: "webhook-order", body: "We receive order.updated before order.created for about 5% of orders. Our consumer rejects the update because the record does not exist yet.", fromCustomer: true, age: 28 },
|
|
132
|
+
{ ticket: "webhook-order", body: "Ordering is not guaranteed across retries. I have written up how to buffer on the sequence number in the payload. Would that work for your consumer?", fromCustomer: false, age: 26 },
|
|
133
|
+
{ ticket: "webhook-order", body: "Engineering is looking at per-resource ordering. No ETA yet.", fromCustomer: false, internal: true, age: 26 },
|
|
134
|
+
|
|
135
|
+
{ ticket: "mobile-upload", body: "Crews cannot upload site photos from the iOS app since the update this morning. The spinner runs then the photo disappears. Android is fine.", fromCustomer: true, age: 7 },
|
|
136
|
+
{ ticket: "mobile-upload", body: "Reproduced on iOS 18.6 with HEIC photos. JPEG works. We are shipping a hotfix. In the meantime, set the camera to Most Compatible in iOS settings.", fromCustomer: false, age: 6.5 },
|
|
137
|
+
{ ticket: "mobile-upload", body: "That works as a workaround. Please let me know when the fix ships.", fromCustomer: true, age: 4 },
|
|
138
|
+
|
|
139
|
+
{ ticket: "search-accents", body: "Searching for Moreau finds me but searching for Béatrice returns nothing. Half our customers have accented names.", fromCustomer: true, age: 40 },
|
|
140
|
+
{ ticket: "search-accents", body: "Search currently matches exact characters. I have logged this as a bug. Typing the accented character finds the record for now.", fromCustomer: false, age: 36 },
|
|
141
|
+
|
|
142
|
+
{ ticket: "timezone", body: "Our Monday report is scheduled for 07:00 but arrives at 03:00. We are in Boston.", fromCustomer: true, age: 50 },
|
|
143
|
+
{ ticket: "timezone", body: "The schedule is stored in UTC and your workspace timezone was unset. I set it to America/New_York. Next Monday's report should arrive at 07:00 local.", fromCustomer: false, age: 45 },
|
|
144
|
+
|
|
145
|
+
{ ticket: "bulk-delete", body: "Selected 850 old enrolment records and chose Delete. It removed 200 and stopped with no error.", fromCustomer: true, age: 60 },
|
|
146
|
+
{ ticket: "bulk-delete", body: "Bulk actions are capped at 200 per request. The UI should say so. I have raised it. You can run the delete four more times or I can run it for you.", fromCustomer: false, age: 58 },
|
|
147
|
+
{ ticket: "bulk-delete", body: "Please run it for me. Everything with status Withdrawn before 2025.", fromCustomer: true, age: 40 },
|
|
148
|
+
|
|
149
|
+
{ ticket: "audit-log", body: "We changed a user's role from Admin to Member last week and nothing appears in the audit log for it.", fromCustomer: true, age: 33 },
|
|
150
|
+
{ ticket: "audit-log", body: "Role changes made through the members page are logged. Changes made through SCIM are not, which looks like your case. Confirming with engineering.", fromCustomer: false, age: 31 },
|
|
151
|
+
|
|
152
|
+
{ ticket: "invoice", body: "We upgraded on the 3rd but the invoice still lists the old plan. Can you re-issue?", fromCustomer: true, age: 26 },
|
|
153
|
+
{ ticket: "invoice", body: "Re-issued and emailed. The proration lands on next month's invoice.", fromCustomer: false, age: 24 },
|
|
154
|
+
|
|
155
|
+
{ ticket: "domain", body: "Added portal.copperline.beer three days ago and it still says Pending.", fromCustomer: true, age: 72 },
|
|
156
|
+
{ ticket: "domain", body: "The CNAME is pointing at the old target. It needs to be custom.stack0.app. Once that propagates the certificate issues itself.", fromCustomer: false, age: 70 },
|
|
157
|
+
|
|
158
|
+
{ ticket: "seat-count", body: "The invoice bills 42 seats but we only have 35 people in the members list.", fromCustomer: true, age: 90 },
|
|
159
|
+
{ ticket: "seat-count", body: "Pending invites count as seats until they are revoked. You have 7 outstanding invites from March. Revoke them and the next invoice will show 35.", fromCustomer: false, age: 88 },
|
|
160
|
+
|
|
161
|
+
{ ticket: "ssl-warning", body: "Staff see a certificate warning when opening the portal from the factory network.", fromCustomer: true, age: 48 },
|
|
162
|
+
{ ticket: "ssl-warning", body: "Our certificate is valid. This is usually a TLS-inspecting proxy on the local network replacing it. Can you send the certificate details the browser shows?", fromCustomer: false, age: 47 },
|
|
163
|
+
|
|
164
|
+
{ ticket: "gdpr-export", body: "A former tenant has requested all data we hold on them. We need an export of every record referencing their email.", fromCustomer: true, age: 100 },
|
|
165
|
+
{ ticket: "gdpr-export", body: "I can produce that. Please confirm the email address and whether you also want attachments included.", fromCustomer: false, age: 96 },
|
|
166
|
+
|
|
167
|
+
{ ticket: "calendar-sync", body: "Every appointment now appears twice in Outlook. Once from the sync and once from the email invite.", fromCustomer: true, age: 130 },
|
|
168
|
+
{ ticket: "calendar-sync", body: "Both the sync and the invite are enabled on your account. Turn off Send calendar invites under Notifications and the duplicates stop.", fromCustomer: false, age: 128 },
|
|
169
|
+
|
|
170
|
+
{ ticket: "training", body: "We are opening a branch in Denver in October. Can we book an onboarding session for six new staff?", fromCustomer: true, age: 150 },
|
|
171
|
+
{ ticket: "training", body: "Yes. I have sent three slots in the first week of October. Pick whichever suits.", fromCustomer: false, age: 140 },
|
|
172
|
+
|
|
173
|
+
{ ticket: "mobile", body: "On phones the listing gallery clips the right-hand photo.", fromCustomer: true, age: 120 },
|
|
174
|
+
{ ticket: "mobile", body: "Fixed in this morning's release. Please refresh and check.", fromCustomer: false, age: 110 },
|
|
175
|
+
{ ticket: "mobile", body: "Looks right now. Thanks.", fromCustomer: true, age: 105 },
|
|
176
|
+
|
|
177
|
+
{ ticket: "password-reset", body: "Requested a reset three times. Nothing in inbox or spam.", fromCustomer: true, age: 200 },
|
|
178
|
+
{ ticket: "password-reset", body: "Your address was on our bounce list from an earlier hard bounce. I have cleared it. Please try again.", fromCustomer: false, age: 199 },
|
|
179
|
+
{ ticket: "password-reset", body: "Got it this time.", fromCustomer: true, age: 197 },
|
|
180
|
+
|
|
181
|
+
{ ticket: "report-totals", body: "The August report says 14,203 events but the dashboard says 14,210 for the same range.", fromCustomer: true, age: 240 },
|
|
182
|
+
{ ticket: "report-totals", body: "The report was generated at 23:58 on the 31st and 7 events arrived after that. Regenerating the report gives 14,210.", fromCustomer: false, age: 230 },
|
|
183
|
+
|
|
184
|
+
{ ticket: "slack", body: "We renamed our Slack workspace and notifications stopped.", fromCustomer: true, age: 260 },
|
|
185
|
+
{ ticket: "slack", body: "A rename revokes the old webhook. Reconnect Slack under Integrations and it will work again.", fromCustomer: false, age: 255 },
|
|
186
|
+
{ ticket: "slack", body: "Reconnected. Working.", fromCustomer: true, age: 250 },
|
|
187
|
+
|
|
188
|
+
{ ticket: "print", body: "Printing the pick list drops the Notes column off the right edge.", fromCustomer: true, age: 300 },
|
|
189
|
+
{ ticket: "print", body: "Print now uses landscape for tables with more than six columns. Released today.", fromCustomer: false, age: 280 },
|
|
190
|
+
|
|
191
|
+
{ ticket: "two-factor", body: "Lost my phone with the authenticator app. Locked out of the admin account.", fromCustomer: true, age: 320 },
|
|
192
|
+
{ ticket: "two-factor", body: "I have verified your identity against the billing contact and reset 2FA. You will be asked to set it up again at next login.", fromCustomer: false, age: 319.5 },
|
|
193
|
+
{ ticket: "two-factor", body: "Verified via callback to the number on file.", fromCustomer: false, internal: true, age: 319.5 },
|
|
194
|
+
|
|
195
|
+
{ ticket: "currency", body: "Our workspace shows USD but we invoice in SEK.", fromCustomer: true, age: 360 },
|
|
196
|
+
{ ticket: "currency", body: "Changed under Settings, Billing, Display currency. Existing amounts are not converted, only formatted.", fromCustomer: false, age: 350 },
|
|
197
|
+
|
|
198
|
+
{ ticket: "attachment-size", body: "Cannot attach the signed enrolment packs. They are around 14 MB each.", fromCustomer: true, age: 400 },
|
|
199
|
+
{ ticket: "attachment-size", body: "The limit is now 25 MB per file for your plan.", fromCustomer: false, age: 390 },
|
|
200
|
+
|
|
201
|
+
{ ticket: "webhook", body: "Every webhook is delivered twice, about 30 seconds apart.", fromCustomer: true, age: 500 },
|
|
202
|
+
{ ticket: "webhook", body: "Your endpoint returns 200 after 12 seconds. Our timeout is 10, so we retry. Respond immediately and process in the background, or we can raise the timeout for your account.", fromCustomer: false, age: 490 },
|
|
203
|
+
{ ticket: "webhook", body: "Changed our handler to ack first. Duplicates gone.", fromCustomer: true, age: 470 },
|
|
204
|
+
|
|
205
|
+
{ ticket: "billing-address", body: "We moved. New address is 41 Cannery Row, Portland, OR 97209.", fromCustomer: true, age: 520 },
|
|
206
|
+
{ ticket: "billing-address", body: "Updated. The next invoice will show the new address.", fromCustomer: false, age: 515 },
|
|
207
|
+
|
|
208
|
+
{ ticket: "old-import", body: "Some customer notes from the old system did not come across in the import.", fromCustomer: true, age: 600 },
|
|
209
|
+
{ ticket: "old-import", body: "Notes over 10,000 characters were skipped by the importer. I have re-run it for the 31 affected records.", fromCustomer: false, age: 590 },
|
|
210
|
+
|
|
211
|
+
{ ticket: "api-key", body: "A contractor had access to the warehouse integration key. Please rotate it.", fromCustomer: true, age: 650 },
|
|
212
|
+
{ ticket: "api-key", body: "Rotated. The old key stops working in 24 hours. The new one is in Settings, API.", fromCustomer: false, age: 648 },
|
|
213
|
+
|
|
214
|
+
{ ticket: "welcome", body: "Where do I edit the text of the welcome email new members get?", fromCustomer: true, age: 700 },
|
|
215
|
+
{ ticket: "welcome", body: "Settings, Emails, Welcome. Changes apply to invites sent after you save.", fromCustomer: false, age: 690 },
|
|
216
|
+
|
|
217
|
+
{ ticket: "rename-workspace", body: "Please rename our workspace from Kestrel Maintenance to Kestrel Aviation Services.", fromCustomer: true, age: 720 },
|
|
218
|
+
{ ticket: "rename-workspace", body: "Done.", fromCustomer: false, age: 715 },
|
|
219
|
+
|
|
220
|
+
{ ticket: "downtime", body: "The portal was down from 08:10 to 08:30 our time. Drivers could not check in.", fromCustomer: true, age: 800 },
|
|
221
|
+
{ ticket: "downtime", body: "Confirmed. A database failover took longer than it should have. A post-incident report is on the status page. Apologies for the disruption.", fromCustomer: false, age: 799.5 },
|
|
222
|
+
|
|
223
|
+
{ ticket: "cancel-trial", body: "We created a second trial workspace by mistake. Please cancel vantage-solar-2.", fromCustomer: true, age: 900 },
|
|
224
|
+
{ ticket: "cancel-trial", body: "Cancelled and scheduled for deletion in 30 days in case you need anything from it.", fromCustomer: false, age: 880 },
|
|
147
225
|
];
|
|
148
226
|
|
|
149
227
|
export interface ShapedSeed {
|
|
@@ -155,10 +233,16 @@ export interface ShapedSeed {
|
|
|
155
233
|
export function shapeSeed(now: number = Date.now()): ShapedSeed {
|
|
156
234
|
const hoursAgo = (hours: number) => new Date(now - hours * 3_600_000).toISOString();
|
|
157
235
|
|
|
236
|
+
const latestMessage = new Map<string, number>();
|
|
237
|
+
for (const m of SEED_MESSAGES) {
|
|
238
|
+
const current = latestMessage.get(m.ticket);
|
|
239
|
+
if (current === undefined || m.age < current) latestMessage.set(m.ticket, m.age);
|
|
240
|
+
}
|
|
241
|
+
|
|
158
242
|
return {
|
|
159
|
-
customers: SEED_CUSTOMERS.map((c) => ({
|
|
243
|
+
customers: SEED_CUSTOMERS.map((c, index) => ({
|
|
160
244
|
key: c.key,
|
|
161
|
-
row: { name: c.name, email: c.email, company: c.company, createdAt: hoursAgo(
|
|
245
|
+
row: { name: c.name, email: c.email, company: c.company, createdAt: hoursAgo(2000 - index * 60) },
|
|
162
246
|
})),
|
|
163
247
|
tickets: SEED_TICKETS.map((t) => ({
|
|
164
248
|
key: t.key,
|
|
@@ -169,7 +253,7 @@ export function shapeSeed(now: number = Date.now()): ShapedSeed {
|
|
|
169
253
|
priority: t.priority,
|
|
170
254
|
firstRespondedAt: t.respondedAgo === null ? null : hoursAgo(t.respondedAgo),
|
|
171
255
|
createdAt: hoursAgo(t.age),
|
|
172
|
-
updatedAt: hoursAgo(t.
|
|
256
|
+
updatedAt: hoursAgo(latestMessage.get(t.key) ?? t.age),
|
|
173
257
|
},
|
|
174
258
|
})),
|
|
175
259
|
messages: SEED_MESSAGES.map((m) => ({
|
|
@@ -65,7 +65,7 @@ this pass before the user has to ask.
|
|
|
65
65
|
- **`ctx.llm.stream(request, onEvent)` streams tokens as they generate** and still resolves with the full response, so `stop_reason === "tool_use"` drives an agent tool loop. Events are `text_delta` / `tool_use_start` / `tool_input_delta` / `done`. Same auth + model-allowlist gating as `ctx.llm.complete`. Streaming does NOT extend the call deadline (`PYLON_FN_CALL_TIMEOUT`, 30s default) — set `timeout: <secs>` on the def for a long run.
|
|
66
66
|
- **`ctx.stream.write(text)` streams to the caller — and every fn stream is RESUMABLE**: the server buffers frames under a stream id (`streamFn`'s `onStreamId`), so a dropped connection or closed tab catches up via `resumeStream(id)`, including the final result after the handler finished. `ctx.rooms.broadcast(room, topic, data)` fans out to every CURRENTLY-CONNECTED subscriber (second device, second tab) but does not replay missed messages — use the stream id for anything that must survive a gap. Broadcast resolves `{ delivered: false }` when the room has no members — a no-op, not an error. Clients receive with `useRoomMessages(room, cb)` from `@pylonsync/react`; `useRoom` is the send side.
|
|
67
67
|
- **It's `db.useQueryOne`, not `useOne`.** Validators and field types have aliases: `v.bool`/`v.boolean`, `v.float`/`v.number`.
|
|
68
|
-
- **Use the supported file and scheduling APIs.** Files go through `<FileUpload>` and `/api/files/*`; there is no `ctx.files`. One-shot work uses `ctx.scheduler.runAfter`, `runAt`, or `cancel`; there is no `defineWorkflow` or `defineJob`. Recurring work uses `cron("0 * * * *", "fnName")` in `buildManifest({ crons: [...] })`, imported from `@pylonsync/sdk`. Make the target function `internal: true`. It runs with anonymous auth, but its own `ctx.db.*` calls are server-side and bypass policies. Use `ctx.auth.elevate({ admin: true, reason: "..." })`, with a mandatory reason, only when chaining another internal function through `ctx.scheduler`.
|
|
68
|
+
- **Use the supported file and scheduling APIs.** Files go through `<FileUpload>` and `/api/files/*`; an upload is readable by its uploader only, so pass `visibility: "public"` to `uploadFile` or `<FileUpload>` for files every visitor sees; there is no `ctx.files`. One-shot work uses `ctx.scheduler.runAfter`, `runAt`, or `cancel`; there is no `defineWorkflow` or `defineJob`. Recurring work uses `cron("0 * * * *", "fnName")` in `buildManifest({ crons: [...] })`, imported from `@pylonsync/sdk`. Make the target function `internal: true`. It runs with anonymous auth, but its own `ctx.db.*` calls are server-side and bypass policies. Use `ctx.auth.elevate({ admin: true, reason: "..." })`, with a mandatory reason, only when chaining another internal function through `ctx.scheduler`.
|
|
69
69
|
|
|
70
70
|
## Testing
|
|
71
71
|
|