page.mooring.site
Schema Diff
+20 -0
Compatibility Analysis
Backward Compatible
Backward compatible. 6 non-breaking changes.
Non-Breaking Changes (6)
- AddedVertex AddedVertex { vertex_id: "page.mooring.site#heroSection.style" }
- AddedVertex AddedVertex { vertex_id: "page.mooring.site:body.contactEmail" }
- AddedVertex AddedVertex { vertex_id: "page.mooring.site:body.signOff" }
- AddedEdge AddedEdge { src: "page.mooring.site#heroSection", tgt: "page.mooring.site#heroSection.style", kind: "prop", name: Some("style") }
- AddedEdge AddedEdge { src: "page.mooring.site:body", tgt: "page.mooring.site:body.contactEmail", kind: "prop", name: Some("contactEmail") }
- AddedEdge AddedEdge { src: "page.mooring.site:body", tgt: "page.mooring.site:body.signOff", kind: "prop", name: Some("signOff") }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "page.mooring.site#heroSection.style" }AddedVertex { vertex_id: "page.mooring.site:body.contactEmail" }AddedVertex { vertex_id: "page.mooring.site:body.signOff" }
Additional Notes
- Non-breaking: AddedEdge { src: "page.mooring.site#heroSection", tgt: "page.mooring.site#heroSection.style", kind: "prop", name: Some("style") }
- Non-breaking: AddedEdge { src: "page.mooring.site:body", tgt: "page.mooring.site:body.contactEmail", kind: "prop", name: Some("contactEmail") }
- Non-breaking: AddedEdge { src: "page.mooring.site:body", tgt: "page.mooring.site:body.signOff", kind: "prop", name: Some("signOff") }
1
1
{
2
2
"id": "page.mooring.site",
3
3
"defs": {
4
4
"rgb": {
5
5
"type": "object",
6
6
"required": [
7
7
"r",
8
8
"g",
9
9
"b"
10
10
],
11
11
"properties": {
12
12
"b": {
13
13
"type": "integer",
14
14
"maximum": 255,
15
15
"minimum": 0
16
16
},
17
17
"g": {
18
18
"type": "integer",
19
19
"maximum": 255,
20
20
"minimum": 0
21
21
},
22
22
"r": {
23
23
"type": "integer",
24
24
"maximum": 255,
25
25
"minimum": 0
26
26
}
27
27
}
28
28
},
29
29
"main": {
30
30
"key": "any",
31
31
"type": "record",
32
32
"record": {
33
33
"type": "object",
34
34
"required": [
35
35
"createdAt"
36
36
],
37
37
"properties": {
38
38
"icon": {
39
39
"type": "blob",
40
40
"accept": [
41
41
"image/*"
42
42
],
43
43
"maxSize": 1000000,
44
44
"description": "Square image used as the site icon/favicon. Should be at least 256x256."
45
45
},
46
46
"name": {
47
47
"type": "string",
48
48
"maxLength": 5000,
49
49
"description": "Site title. When absent, renderers should fall back to the owner's profile displayName or handle.",
50
50
"maxGraphemes": 500
51
51
},
52
52
"theme": {
53
53
"ref": "#theme",
54
54
"type": "ref"
55
55
},
56
56
"labels": {
57
57
"refs": [
58
58
"com.atproto.label.defs#selfLabels"
59
59
],
60
60
"type": "union"
61
61
},
62
+
"signOff": {
63
+
"type": "string",
64
+
"maxLength": 640,
65
+
"description": "Valediction rendered before the owner's name in the site's closing sign-off, like 'Warmly,'. When absent, the sign-off shows the name alone.",
66
+
"maxGraphemes": 64
67
+
},
62
68
"sections": {
63
69
"type": "array",
64
70
"items": {
65
71
"refs": [
66
72
"#heroSection",
67
73
"#postsSection",
68
74
"#writingSection",
69
75
"#careerSection",
70
76
"#pagesSection"
71
77
],
72
78
"type": "union",
73
79
"closed": false
74
80
},
75
81
"maxLength": 50,
76
82
"description": "Ordered sections of the site, rendered top to bottom; order is array position. When absent, renderers should use a sensible default order based on which sources have data."
77
83
},
78
84
"createdAt": {
79
85
"type": "string",
80
86
"format": "datetime",
81
87
"description": "Client-declared timestamp when this record was created."
82
88
},
83
89
"description": {
84
90
"type": "string",
85
91
"maxLength": 30000,
86
92
"description": "Short description of the site, used for meta tags and previews.",
87
93
"maxGraphemes": 3000
88
94
},
95
+
"contactEmail": {
96
+
"type": "string",
97
+
"maxLength": 2540,
98
+
"description": "Public contact email, rendered as a contact affordance on the site. Publishing an address here makes it world-readable.",
99
+
"maxGraphemes": 254
100
+
},
89
101
"discoverable": {
90
102
"type": "boolean",
91
103
"description": "Default true when absent. When false, the renderer emits noindex directives for the site. Does not affect the public visibility of the underlying atproto records."
92
104
}
93
105
}
94
106
},
95
107
"description": "A Mooring site. Every field except createdAt is optional: an empty record is a valid site, and the renderer falls back to the owner's profile records and a default section order."
96
108
},
97
109
"theme": {
98
110
"type": "object",
99
111
"properties": {
100
112
"colors": {
101
113
"ref": "#colors",
102
114
"type": "ref"
103
115
},
104
116
"preset": {
105
117
"type": "string",
106
118
"description": "Named theme preset. Unknown values should fall back to the renderer's default preset.",
107
119
"knownValues": [
108
120
"classic"
109
121
]
110
122
}
111
123
},
112
124
"description": "Theme selection and overrides. All fields optional; renderer defaults apply."
113
125
},
114
126
"colors": {
115
127
"type": "object",
116
128
"properties": {
117
129
"accent": {
118
130
"refs": [
119
131
"#rgb"
120
132
],
121
133
"type": "union",
122
134
"closed": false,
123
135
"description": "Color used for links and button backgrounds."
124
136
},
125
137
"background": {
126
138
"refs": [
127
139
"#rgb"
128
140
],
129
141
"type": "union",
130
142
"closed": false,
131
143
"description": "Color used for content background."
132
144
},
133
145
"foreground": {
134
146
"refs": [
135
147
"#rgb"
136
148
],
137
149
"type": "union",
138
150
"closed": false,
139
151
"description": "Color used for content text."
140
152
},
141
153
"accentForeground": {
142
154
"refs": [
143
155
"#rgb"
144
156
],
145
157
"type": "union",
146
158
"closed": false,
147
159
"description": "Color used for button text."
148
160
}
149
161
},
150
162
"description": "Semantic color overrides, mirroring the role vocabulary of site.standard.theme.basic. Any subset may be set."
151
163
},
152
164
"heroSection": {
153
165
"type": "object",
154
166
"properties": {
167
+
"style": {
168
+
"type": "string",
169
+
"description": "Banner treatment when the profile carries a banner: 'band' renders it full-width above the heading, 'postcard' renders it as a framed photograph beside the heading. Default 'band'. Without a banner both fall back to the avatar-led hero.",
170
+
"knownValues": [
171
+
"band",
172
+
"postcard"
173
+
]
174
+
},
155
175
"title": {
156
176
"type": "string",
157
177
"maxLength": 1280,
158
178
"description": "Heading override. When absent, renderers should fall back to profile data.",
159
179
"maxGraphemes": 128
160
180
},
161
181
"tagline": {
162
182
"type": "string",
163
183
"maxLength": 3000,
164
184
"description": "Short line under the heading. When absent, renderers should fall back to the profile description or sifa headline.",
165
185
"maxGraphemes": 300
166
186
},
167
187
"showAvatar": {
168
188
"type": "boolean",
169
189
"description": "Default true when absent."
170
190
}
171
191
},
172
192
"description": "Introductory section rendered from the owner's profile records (app.bsky.actor.profile, with id.sifa.profile.self as professional-context overlay when present)."
173
193
},
174
194
"pagesSection": {
175
195
"type": "object",
176
196
"properties": {
177
197
"pages": {
178
198
"type": "array",
179
199
"items": {
180
200
"type": "string",
181
201
"format": "at-uri"
182
202
},
183
203
"maxLength": 100,
184
204
"description": "Explicit ordered list of page records (AT-URIs) to show. Renderers should skip dangling references. When absent, all public pages are listed in a renderer-defined order."
185
205
},
186
206
"title": {
187
207
"type": "string",
188
208
"maxLength": 1280,
189
209
"maxGraphemes": 128
190
210
}
191
211
},
192
212
"description": "Listing of the site's authored page.mooring.page records."
193
213
},
194
214
"postsSection": {
195
215
"type": "object",
196
216
"properties": {
197
217
"limit": {
198
218
"type": "integer",
199
219
"maximum": 50,
200
220
"minimum": 1,
201
221
"description": "Maximum number of posts to display. Renderer default applies when absent."
202
222
},
203
223
"title": {
204
224
"type": "string",
205
225
"maxLength": 1280,
206
226
"maxGraphemes": 128
207
227
}
208
228
},
209
229
"description": "Recent microblog posts from the owner's app.bsky.feed.post collection."
210
230
},
211
231
"careerSection": {
212
232
"type": "object",
213
233
"properties": {
214
234
"parts": {
215
235
"type": "array",
216
236
"items": {
217
237
"type": "string",
218
238
"knownValues": [
219
239
"positions",
220
240
"education",
221
241
"skills",
222
242
"projects",
223
243
"certifications",
224
244
"publications"
225
245
]
226
246
},
227
247
"maxLength": 10,
228
248
"description": "Which parts of the sifa profile to render, in order. When absent, renderers should show the parts that have data, in a default order."
229
249
},
230
250
"title": {
231
251
"type": "string",
232
252
"maxLength": 1280,
233
253
"maxGraphemes": 128
234
254
}
235
255
},
236
256
"description": "Professional profile rendered from the owner's id.sifa.* records."
237
257
},
238
258
"writingSection": {
239
259
"type": "object",
240
260
"properties": {
241
261
"limit": {
242
262
"type": "integer",
243
263
"maximum": 50,
244
264
"minimum": 1,
245
265
"description": "Maximum number of documents to display. Renderer default applies when absent."
246
266
},
247
267
"title": {
248
268
"type": "string",
249
269
"maxLength": 1280,
250
270
"maxGraphemes": 128
251
271
},
252
272
"publication": {
253
273
"type": "string",
254
274
"format": "at-uri",
255
275
"description": "AT-URI of a site.standard.publication record to scope the listing to. When absent, renderers should list the owner's documents across publications."
256
276
}
257
277
},
258
278
"description": "Long-form writing from the owner's site.standard.document collection (with pub.leaflet.* legacy records as fallback)."
259
279
}
260
280
},
261
281
"$type": "com.atproto.lexicon.schema",
262
282
"lexicon": 1,
263
283
"description": "Configuration for a Mooring site. The record at rkey 'self' is the owner's default site; other rkeys are reserved for possible future multi-site support."
264
284
}