io.kich.recipe.recipe
Schema Diff
+64 -4
Compatibility Analysis
Backward Compatible
Backward compatible. 25 non-breaking changes.
Non-Breaking Changes (25)
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.heuristicAmount" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.heuristicUnit" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.measuredAmount" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.measuredUnit" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#tag" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#tag.id" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe#tag.name" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.embedding" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.images" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.images:items" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.tags" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.tags:items" }
- AddedVertex AddedVertex { vertex_id: "io.kich.recipe.recipe:body.variationOf" }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.heuristicAmount", kind: "prop", name: Some("heuristicAmount") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.heuristicUnit", kind: "prop", name: Some("heuristicUnit") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.measuredAmount", kind: "prop", name: Some("measuredAmount") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.measuredUnit", kind: "prop", name: Some("measuredUnit") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#tag", tgt: "io.kich.recipe.recipe#tag.id", kind: "prop", name: Some("id") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe#tag", tgt: "io.kich.recipe.recipe#tag.name", kind: "prop", name: Some("name") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.embedding", kind: "prop", name: Some("embedding") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.images", kind: "prop", name: Some("images") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.tags", kind: "prop", name: Some("tags") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.variationOf", kind: "prop", name: Some("variationOf") }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body.images", tgt: "io.kich.recipe.recipe:body.images:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "io.kich.recipe.recipe:body.tags", tgt: "io.kich.recipe.recipe:body.tags:items", kind: "items", name: None }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.heuristicAmount" }AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.heuristicUnit" }AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.measuredAmount" }AddedVertex { vertex_id: "io.kich.recipe.recipe#ingredient.measuredUnit" }AddedVertex { vertex_id: "io.kich.recipe.recipe#tag" }AddedVertex { vertex_id: "io.kich.recipe.recipe#tag.id" }AddedVertex { vertex_id: "io.kich.recipe.recipe#tag.name" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.embedding" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.images" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.images:items" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.tags" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.tags:items" }AddedVertex { vertex_id: "io.kich.recipe.recipe:body.variationOf" }
Additional Notes
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.heuristicAmount", kind: "prop", name: Some("heuristicAmount") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.heuristicUnit", kind: "prop", name: Some("heuristicUnit") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.measuredAmount", kind: "prop", name: Some("measuredAmount") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#ingredient", tgt: "io.kich.recipe.recipe#ingredient.measuredUnit", kind: "prop", name: Some("measuredUnit") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#tag", tgt: "io.kich.recipe.recipe#tag.id", kind: "prop", name: Some("id") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe#tag", tgt: "io.kich.recipe.recipe#tag.name", kind: "prop", name: Some("name") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.embedding", kind: "prop", name: Some("embedding") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.images", kind: "prop", name: Some("images") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.tags", kind: "prop", name: Some("tags") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body", tgt: "io.kich.recipe.recipe:body.variationOf", kind: "prop", name: Some("variationOf") }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body.images", tgt: "io.kich.recipe.recipe:body.images:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "io.kich.recipe.recipe:body.tags", tgt: "io.kich.recipe.recipe:body.tags:items", kind: "items", name: None }
1
1
{
2
2
"id": "io.kich.recipe.recipe",
3
3
"defs": {
4
+
"tag": {
5
+
"type": "object",
6
+
"required": [
7
+
"id",
8
+
"name"
9
+
],
10
+
"properties": {
11
+
"id": {
12
+
"type": "string",
13
+
"description": "Tag identifier"
14
+
},
15
+
"name": {
16
+
"type": "string",
17
+
"description": "Tag display name"
18
+
}
19
+
}
20
+
},
4
21
"main": {
5
22
"key": "tid",
6
23
"type": "record",
7
24
"record": {
8
25
"type": "object",
9
26
"required": [
10
27
"name",
11
28
"servings",
12
29
"createdAt"
13
30
],
14
31
"properties": {
15
32
"url": {
16
33
"type": "string",
17
34
"format": "uri",
18
35
"description": "Source URL of the recipe"
19
36
},
20
37
"name": {
21
38
"type": "string",
22
39
"description": "Recipe name"
23
40
},
41
+
"tags": {
42
+
"type": "array",
43
+
"items": {
44
+
"ref": "#tag",
45
+
"type": "ref"
46
+
},
47
+
"description": "Tags for categorizing the recipe"
48
+
},
49
+
"images": {
50
+
"type": "array",
51
+
"items": {
52
+
"type": "blob",
53
+
"accept": [
54
+
"image/*"
55
+
]
56
+
},
57
+
"maxLength": 10,
58
+
"description": "Recipe images as blobs (hero first; preferred over imageUrl)"
59
+
},
24
60
"source": {
25
61
"type": "string",
26
62
"description": "Source name (book, magazine, blog)"
27
63
},
28
64
"imageUrl": {
29
65
"type": "string",
30
66
"format": "uri",
31
-
"description": "Image URL for the recipe"
67
+
"description": "[Deprecated] Image URL for the recipe. Use images blob array instead. Kept for legacy fallback."
32
68
},
33
69
"servings": {
34
70
"type": "integer",
35
71
"default": 1,
36
72
"description": "Number of servings this recipe makes"
37
73
},
38
74
"createdAt": {
39
75
"type": "string",
40
76
"format": "datetime",
41
77
"description": "When this recipe was created"
42
78
},
43
79
"createdBy": {
44
80
"ref": "com.atproto.repo.strongRef",
45
81
"type": "ref",
46
82
"description": "Reference to the user who created this recipe"
47
83
},
84
+
"embedding": {
85
+
"type": "string",
86
+
"description": "Vector embedding for semantic similarity search (1024 dimensions, stored as JSON array of numbers)"
87
+
},
48
88
"isPrivate": {
49
89
"type": "boolean",
50
90
"default": false,
51
91
"description": "Whether this recipe is private (only visible to household members)"
52
92
},
53
93
"updatedAt": {
54
94
"type": "string",
55
95
"format": "datetime",
56
96
"description": "When this recipe was last updated"
57
97
},
58
98
"description": {
59
99
"type": "string",
60
100
"description": "Recipe description"
61
101
},
62
102
"ingredients": {
63
103
"type": "array",
64
104
"items": {
65
105
"ref": "#ingredient",
66
106
"type": "ref"
67
107
},
68
108
"description": "Recipe ingredients"
69
109
},
110
+
"variationOf": {
111
+
"ref": "com.atproto.repo.strongRef",
112
+
"type": "ref",
113
+
"description": "Optional reference to the original recipe this is a variation of (for attribution and variation discovery)"
114
+
},
70
115
"instructions": {
71
116
"type": "array",
72
117
"items": {
73
118
"ref": "#instructionStep",
74
119
"type": "ref"
75
120
},
76
121
"description": "Cooking instructions as an array of steps"
77
122
},
78
123
"cookTimeMinutes": {
79
124
"type": "integer",
80
125
"description": "Cooking time in minutes"
81
126
},
82
127
"prepTimeMinutes": {
83
128
"type": "integer",
84
129
"description": "Preparation time in minutes"
85
130
}
86
131
}
87
132
}
88
133
},
89
134
"ingredient": {
90
135
"type": "object",
91
136
"required": [
92
137
"id",
93
-
"name",
94
-
"grams"
138
+
"name"
95
139
],
96
140
"properties": {
97
141
"id": {
98
142
"type": "string",
99
143
"description": "Unique identifier for this ingredient"
100
144
},
101
145
"name": {
102
146
"type": "string",
103
147
"description": "Ingredient name"
104
148
},
105
149
"grams": {
106
150
"type": "integer",
107
-
"description": "Amount needed in grams"
151
+
"description": "[Deprecated] Amount needed in grams. Use measuredAmount/measuredUnit instead."
108
152
},
109
153
"group": {
110
154
"type": "string",
111
155
"description": "Optional group name for organizing ingredients (e.g., 'For the sauce:', 'For the pasta:')"
112
156
},
113
157
"notes": {
114
158
"type": "string",
115
159
"description": "Optional notes about this ingredient (e.g., original quantity)"
116
160
},
117
161
"isDetached": {
118
162
"type": "boolean",
119
163
"default": false,
120
164
"description": "Whether this ingredient is detached (doesn't count towards recipe completeness)"
121
165
},
122
166
"isOptional": {
123
167
"type": "boolean",
124
168
"default": false,
125
169
"description": "Whether this ingredient is optional"
170
+
},
171
+
"measuredUnit": {
172
+
"type": "string",
173
+
"description": "Measured unit (g, kg, oz, lb, ml)"
174
+
},
175
+
"heuristicUnit": {
176
+
"type": "string",
177
+
"description": "Heuristic unit from parsed ingredient text (e.g., cup, cookies)"
178
+
},
179
+
"measuredAmount": {
180
+
"type": "integer",
181
+
"description": "Measured amount needed (e.g., 250, 1.5)"
182
+
},
183
+
"heuristicAmount": {
184
+
"type": "integer",
185
+
"description": "Heuristic amount from parsed ingredient text (e.g., 2 in \"2 cups\")"
126
186
}
127
187
}
128
188
},
129
189
"instructionStep": {
130
190
"type": "object",
131
191
"required": [
132
192
"id",
133
193
"value"
134
194
],
135
195
"properties": {
136
196
"id": {
137
197
"type": "string",
138
198
"description": "Unique identifier for this instruction step"
139
199
},
140
200
"value": {
141
201
"type": "string",
142
202
"description": "Instruction text"
143
203
}
144
204
}
145
205
}
146
206
},
147
207
"$type": "com.atproto.lexicon.schema",
148
208
"lexicon": 1,
149
209
"description": "A recipe record containing cooking instructions, ingredients, and metadata."
150
210
}