@simonarcher/fika-types 1.0.63 → 1.0.65

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/coffee.d.ts CHANGED
@@ -1,4 +1,48 @@
1
1
  import type { GeoPoint, Timestamp } from "firebase-admin/firestore";
2
+ /** How “established” a roaster is within specialty (used by shop scoring). */
3
+ export type RoasterTier = 1 | 2 | 3;
4
+ export interface RoasterSpecialtyMeta {
5
+ tier?: RoasterTier;
6
+ verified?: boolean;
7
+ notes?: string;
8
+ curatedByUserId?: string;
9
+ curatedAt?: Timestamp;
10
+ /** Optional admin override of tier for edge cases (rare). */
11
+ override?: {
12
+ tier: RoasterTier;
13
+ reason: string;
14
+ byUserId: string;
15
+ at: Timestamp;
16
+ } | null;
17
+ }
18
+ /** Sourcing / transparency signals that justify tier & help UX “Why” copy. */
19
+ export interface RoasterSourcingSignals {
20
+ directTrade?: boolean;
21
+ transparentPricing?: boolean;
22
+ qGradersOnStaff?: boolean;
23
+ cupOfExcellenceLots?: boolean;
24
+ competitionInvolvement?: boolean;
25
+ sustainabilityBadges?: string[];
26
+ relationshipCoffeeYears?: number;
27
+ originFootprint?: string[];
28
+ }
29
+ /** Public web signals—useful for automated parsing & evidence. */
30
+ export interface RoasterWebSignals {
31
+ website?: string;
32
+ instagram?: string;
33
+ lastCrawledAt?: Timestamp;
34
+ semanticKeywordHits?: number;
35
+ semanticKeywordDensity?: number;
36
+ sources?: Array<"website" | "ig" | "other">;
37
+ crawlError?: string | null;
38
+ }
39
+ /** Lightweight analytics to help admin and list pages. */
40
+ export interface RoasterStats {
41
+ shopsUsingCount?: number;
42
+ activeBeansCount?: number;
43
+ lastUsedAt?: Timestamp;
44
+ }
45
+ /** NEW extended Roaster model. All new fields optional to avoid breaking writes. */
2
46
  export interface Roaster {
3
47
  id: string;
4
48
  name: string;
@@ -24,15 +68,23 @@ export interface Roaster {
24
68
  };
25
69
  };
26
70
  farms?: LinkedFarm[];
71
+ /** ===== Specialty additions ===== */
72
+ specialty?: RoasterSpecialtyMeta;
73
+ sourcing?: RoasterSourcingSignals;
74
+ webSignals?: RoasterWebSignals;
75
+ stats?: RoasterStats;
76
+ /** ===== Existing fields (kept) ===== */
27
77
  addedByUser?: string;
28
78
  active: boolean;
29
79
  createdAt?: Timestamp;
30
80
  updatedAt?: Timestamp;
31
81
  status: "inReview" | "approved" | "rejected";
32
82
  additionalInfo?: string;
83
+ /** Consider replacing with stats.shopsUsingCount over time; keep for back-compat. */
33
84
  suppliedShops?: string[];
34
85
  geoPoint?: GeoPoint;
35
86
  }
87
+ /** Submission payload from users (or shops) proposing a new roaster. */
36
88
  export interface SubmissionRoaster {
37
89
  name: string;
38
90
  logoImage?: string;
@@ -51,12 +103,17 @@ export interface SubmissionRoaster {
51
103
  city: string;
52
104
  };
53
105
  };
106
+ /** Allow submitter to *suggest* a tier with evidence (curators decide). */
107
+ suggestedTier?: RoasterTier;
108
+ evidenceUrls?: string[];
109
+ notesForCurator?: string;
54
110
  userId: string;
55
111
  status: "inReview" | "approved" | "rejected";
56
112
  active: boolean;
57
113
  additionalInfo?: string;
58
114
  geoPoint?: GeoPoint;
59
115
  }
116
+ /** Unchanged helper types (kept for beans/origins) */
60
117
  export interface LinkedFarm {
61
118
  id: string;
62
119
  name: string;
@@ -68,7 +125,7 @@ export interface LinkedFarm {
68
125
  export type DecafMethod = "Swiss Water" | "Sugarcane / Ethyl Acetate" | "Carbon Dioxide (CO₂)" | "Methylene Chloride" | "Mountain Water" | "Unknown";
69
126
  export declare const DECAF_METHODS: readonly ["Swiss Water", "Sugarcane / Ethyl Acetate", "Carbon Dioxide (CO₂)", "Methylene Chloride", "Mountain Water", "Unknown"];
70
127
  export type CoffeeProcessingMethod = "Washed (Wet)" | "Natural (Dry)" | "Honey" | "Anaerobic Fermentation" | "Carbonic Maceration" | "Wet-Hulled" | "Semi-Washed" | "Experimental / Other" | "Unknown";
71
- export type RoastLevel = 'Light' | 'Medium' | 'Dark' | 'Medium-Dark' | 'Medium-Light' | 'Espresso';
128
+ export type RoastLevel = "Light" | "Medium" | "Dark" | "Medium-Dark" | "Medium-Light" | "Espresso";
72
129
  export interface Origin {
73
130
  countryCode: string;
74
131
  countryName?: string;
package/dist/coffee.js CHANGED
@@ -7,36 +7,12 @@ exports.DECAF_METHODS = [
7
7
  "Carbon Dioxide (CO₂)",
8
8
  "Methylene Chloride",
9
9
  "Mountain Water",
10
- "Unknown"
10
+ "Unknown",
11
11
  ];
12
12
  exports.COFFEE_PRODUCING_COUNTRIES = [
13
- "Bolivia",
14
- "Brazil",
15
- "Burundi",
16
- "Colombia",
17
- "Costa Rica",
18
- "Dominican Republic",
19
- "Ecuador",
20
- "El Salvador",
21
- "Ethiopia",
22
- "Guatemala",
23
- "Haiti",
24
- "Honduras",
25
- "India",
26
- "Indonesia",
27
- "Jamaica",
28
- "Kenya",
29
- "Mexico",
30
- "Nicaragua",
31
- "Panama",
32
- "Papua New Guinea",
33
- "Peru",
34
- "Rwanda",
35
- "Tanzania",
36
- "Uganda",
37
- "Vietnam",
38
- "Yemen",
39
- "Other",
13
+ "Bolivia", "Brazil", "Burundi", "Colombia", "Costa Rica", "Dominican Republic", "Ecuador", "El Salvador",
14
+ "Ethiopia", "Guatemala", "Haiti", "Honduras", "India", "Indonesia", "Jamaica", "Kenya", "Mexico", "Nicaragua",
15
+ "Panama", "Papua New Guinea", "Peru", "Rwanda", "Tanzania", "Uganda", "Vietnam", "Yemen", "Other",
40
16
  ];
41
17
  // Mapping between common origin country names and ISO 3166-1 alpha-2 codes
42
18
  exports.COUNTRY_NAME_TO_CODE = {
package/dist/shop.d.ts CHANGED
@@ -5,6 +5,7 @@ export type MenuItemDrinkType = "Filter" | "ColdBrew" | "Specialty" | "Iced" | "
5
5
  export type MenuItemFoodType = "Breakfast" | "Lunch" | "Pastry" | "Snack" | "Sweets" | "Sandwiches" | "Other";
6
6
  export type MenuItemType = MenuItemDrinkType | MenuItemFoodType;
7
7
  export type MenuItemCategory = "drink" | "food";
8
+ export type SpecialtyTier = 'specialty' | 'quality' | 'everyday';
8
9
  export interface MenuItem {
9
10
  id: string;
10
11
  productId?: string;
@@ -190,6 +191,18 @@ export type ShopData = {
190
191
  communityStats?: ShopCommunityStats;
191
192
  spotifyPlaylistId?: string;
192
193
  paymentOptions?: ShopPaymentOptions;
194
+ /**
195
+ * --------- NEW FOR SPECIALTY SCORING (all optional/merge-friendly) ----------
196
+ */
197
+ roasterRefs?: RoasterRef[];
198
+ houseRoasted?: boolean;
199
+ brewMethods?: string[];
200
+ menuKeywords?: string[];
201
+ events?: string[];
202
+ sustainability?: Array<'direct trade' | 'traceable' | 'organic' | 'b-corp' | string>;
203
+ baristaAchievements?: BaristaAchievement[];
204
+ signals?: SpecialtySignals;
205
+ specialty?: SpecialtyMeta;
193
206
  };
194
207
  export interface ShopCommunityStats {
195
208
  totalCheckIns: number;
@@ -448,4 +461,43 @@ export interface PublicShopData extends Omit<ShopData, 'analytics' | 'googleRati
448
461
  spotifyPlaylistId?: string;
449
462
  address?: string;
450
463
  }
464
+ export type SpecialtyOverride = {
465
+ score: number;
466
+ reason?: string;
467
+ byUserId?: string;
468
+ at?: number;
469
+ };
470
+ export type SpecialtyMeta = {
471
+ score?: number;
472
+ tier?: SpecialtyTier;
473
+ verified?: boolean;
474
+ override?: SpecialtyOverride | null;
475
+ explanations?: string[];
476
+ updatedAt?: number;
477
+ };
478
+ export type SpecialtySemanticSignals = {
479
+ keywordHits?: number;
480
+ keywordDensity?: number;
481
+ sources?: Array<'website' | 'ig' | 'menu' | 'other'>;
482
+ };
483
+ export type SpecialtyCrowdSignals = {
484
+ votes?: number;
485
+ specialtyVotes?: number;
486
+ avgCraftRating?: number;
487
+ };
488
+ export type SpecialtySignals = {
489
+ semantic?: SpecialtySemanticSignals;
490
+ crowd?: SpecialtyCrowdSignals;
491
+ };
492
+ export type RoasterRef = {
493
+ id: string;
494
+ displayName?: string;
495
+ tierHint?: 1 | 2 | 3;
496
+ };
497
+ export type CommunitySignal = 'cupping' | 'training' | 'education' | 'origin talk' | 'sustainability' | 'direct trade' | 'traceable';
498
+ export type BaristaAchievement = {
499
+ title: string;
500
+ year?: number;
501
+ notes?: string;
502
+ };
451
503
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simonarcher/fika-types",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "description": "Shared TypeScript types for Fika projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",