com.atmosphereaccount.registry.profile
Schema Diff
+79 -7
Compatibility Analysis
Breaking Changes Detected
6 breaking changes, 20 non-breaking changes.
Breaking Changes (6)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry", src: "com.atmosphereaccount.registry.profile#screenshotEntry", tgt: "com.atmosphereaccount.registry.profile#screenshotEntry.image", kind: "prop", name: Some("image") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body", src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.description", kind: "prop", name: Some("description") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body", src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.categories", kind: "prop", name: Some("categories") }
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile:body.createdAt", sort: "maxLength", value: "64" }
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile#linkEntry.kind", sort: "maxLength", value: "32" }
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile:body.categories:items", sort: "maxLength", value: "32" }
Non-Breaking Changes (20)
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry.image" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.androidLink" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.banner" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.iconBw" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.iosLink" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.mainLink" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.profileType" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.screenshots" }
- AddedVertex AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.screenshots:items" }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.androidLink", kind: "prop", name: Some("androidLink") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.banner", kind: "prop", name: Some("banner") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.iconBw", kind: "prop", name: Some("iconBw") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.iosLink", kind: "prop", name: Some("iosLink") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.mainLink", kind: "prop", name: Some("mainLink") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.profileType", kind: "prop", name: Some("profileType") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.screenshots", kind: "prop", name: Some("screenshots") }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body.screenshots", tgt: "com.atmosphereaccount.registry.profile:body.screenshots:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "com.atmosphereaccount.registry.profile:body.screenshots:items", tgt: "com.atmosphereaccount.registry.profile#screenshotEntry", kind: "ref", name: None }
- ConstraintRemoved ConstraintRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body.description", sort: "minLength" }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry.image" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.androidLink" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.banner" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.iconBw" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.iosLink" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.mainLink" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.profileType" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.screenshots" }AddedVertex { vertex_id: "com.atmosphereaccount.registry.profile:body.screenshots:items" }
Constraint Changes
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile#linkEntry.kind", sort: "maxLength", value: "32" }
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile:body.categories:items", sort: "maxLength", value: "32" }
- ConstraintAdded ConstraintAdded { vertex_id: "com.atmosphereaccount.registry.profile:body.createdAt", sort: "maxLength", value: "64" }
- ConstraintRemoved ConstraintRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body.description", sort: "minLength" }
Additional Notes
- Breaking: RequiredEdgeAdded { vertex_id: "com.atmosphereaccount.registry.profile#screenshotEntry", src: "com.atmosphereaccount.registry.profile#screenshotEntry", tgt: "com.atmosphereaccount.registry.profile#screenshotEntry.image", kind: "prop", name: Some("image") }
- Breaking: RequiredEdgeRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body", src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.description", kind: "prop", name: Some("description") }
- Breaking: RequiredEdgeRemoved { vertex_id: "com.atmosphereaccount.registry.profile:body", src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.categories", kind: "prop", name: Some("categories") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.androidLink", kind: "prop", name: Some("androidLink") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.banner", kind: "prop", name: Some("banner") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.iconBw", kind: "prop", name: Some("iconBw") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.iosLink", kind: "prop", name: Some("iosLink") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.mainLink", kind: "prop", name: Some("mainLink") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.profileType", kind: "prop", name: Some("profileType") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body", tgt: "com.atmosphereaccount.registry.profile:body.screenshots", kind: "prop", name: Some("screenshots") }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body.screenshots", tgt: "com.atmosphereaccount.registry.profile:body.screenshots:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "com.atmosphereaccount.registry.profile:body.screenshots:items", tgt: "com.atmosphereaccount.registry.profile#screenshotEntry", kind: "ref", name: None }
1
1
{
2
2
"$type": "com.atproto.lexicon.schema",
3
3
"defs": {
4
4
"linkEntry": {
5
5
"properties": {
6
6
"clientId": {
7
7
"description": "Required when kind=\"bsky\". Picks which Bluesky-compatible web client should host the link (bluesky, blacksky, deer, …).",
8
8
"maxLength": 64,
9
9
"type": "string"
10
10
},
11
11
"kind": {
12
12
"description": "Link kind. Drives the icon/label and how `url` / `clientId` are resolved at render time. New atmosphere services can be added to knownValues without breaking older records.",
13
13
"knownValues": [
14
14
"bsky",
15
15
"tangled",
16
16
"supper",
17
17
"website",
18
18
"other"
19
19
],
20
+
"maxLength": 32,
20
21
"type": "string"
21
22
},
22
23
"label": {
23
24
"description": "Required when kind=\"other\". Used as the visible button title for custom links.",
24
25
"maxLength": 64,
25
26
"type": "string"
26
27
},
27
28
"url": {
28
29
"description": "Optional for atmosphere kinds (bsky derives URL from clientId+handle; tangled/supper default to the canonical handle URL but accept an override). Required for `website` and `other`.",
29
30
"format": "uri",
30
31
"maxLength": 512,
31
32
"type": "string"
32
33
}
33
34
},
34
35
"required": [
35
36
"kind"
36
37
],
37
38
"type": "object"
38
39
},
39
40
"main": {
40
-
"description": "A project's profile in the Atmosphere registry. Created by the project's own account on its PDS; one record per account. Kept intentionally minimal so future additions (reviews, age ratings, donations metadata, etc.) live in sibling com.atmosphereaccount.registry.* records.",
41
+
"description": "A user or project profile in the Atmosphere registry. Created by the account owner on their PDS; one record per account. Reviews, ratings, moderation, and other social data live in sibling com.atmosphereaccount.registry.* records.",
41
42
"key": "literal:self",
42
43
"record": {
43
44
"properties": {
45
+
"androidLink": {
46
+
"description": "Optional Google Play or Android distribution URL for projects with an Android app. Rendered as an Android button on the public profile when present.",
47
+
"format": "uri",
48
+
"maxLength": 512,
49
+
"type": "string"
50
+
},
44
51
"avatar": {
45
52
"accept": [
46
53
"image/png",
47
54
"image/jpeg",
48
55
"image/webp"
49
56
],
50
57
"description": "Project icon. Recommended 512x512 square.",
51
58
"maxSize": 1000000,
52
59
"type": "blob"
53
60
},
61
+
"banner": {
62
+
"accept": [
63
+
"image/png",
64
+
"image/jpeg",
65
+
"image/webp"
66
+
],
67
+
"description": "Optional project banner image. Rendered at the top of the project page and used as the OpenGraph / Twitter card preview when the page is shared. Recommended 1200x630 (1.91:1 OG ratio).",
68
+
"maxSize": 3000000,
69
+
"type": "blob"
70
+
},
54
71
"categories": {
55
72
"description": "All categories that apply to the project. A project can be both an app and an account provider, etc. The first item is treated as the primary category for sort/grouping. New values can be added to knownValues over time without breaking existing records.",
56
73
"items": {
57
74
"knownValues": [
58
75
"app",
59
76
"accountProvider",
60
77
"moderator",
61
78
"infrastructure",
62
79
"developerTool"
63
80
],
81
+
"maxLength": 32,
64
82
"type": "string"
65
83
},
66
84
"maxLength": 4,
67
85
"minLength": 1,
68
86
"type": "array"
69
87
},
70
88
"createdAt": {
71
89
"format": "datetime",
90
+
"maxLength": 64,
72
91
"type": "string"
73
92
},
74
93
"description": {
75
-
"description": "Short description of the project.",
94
+
"description": "Optional short description for a project or bio for a user profile.",
76
95
"maxGraphemes": 500,
77
96
"maxLength": 500,
78
-
"minLength": 1,
79
97
"type": "string"
80
98
},
81
99
"icon": {
82
100
"accept": [
83
101
"image/svg+xml"
84
102
],
85
103
"description": "Optional vector icon (SVG) intended for developers building badges, app showcases, sign-in flows, etc. Not displayed on the public Explore profile. Sanitised on upload (script tags, event handlers, foreignObject and javascript:/data: hrefs are stripped).",
86
104
"maxSize": 200000,
87
105
"type": "blob"
88
106
},
107
+
"iconBw": {
108
+
"accept": [
109
+
"image/svg+xml"
110
+
],
111
+
"description": "Optional black & white companion to `icon`. Same audience and sanitisation rules — published alongside the color mark for monochrome contexts (light/dark badges, sign-in chrome, print).",
112
+
"maxSize": 200000,
113
+
"type": "blob"
114
+
},
115
+
"iosLink": {
116
+
"description": "Optional App Store URL for projects with an iOS app. Rendered as an iOS button on the public profile when present.",
117
+
"format": "uri",
118
+
"maxLength": 512,
119
+
"type": "string"
120
+
},
89
121
"links": {
90
-
"description": "Outbound buttons shown on the public profile. Atmosphere links (kind = bsky / tangled / supper) derive their URL from the project's current handle by default; a `url` override is allowed for tangled / supper when the canonical destination differs from the handle. Custom link kinds (kind = website / other) always carry their `url`.",
122
+
"description": "Outbound buttons shown on the public profile after the Web / iOS / Android app links. Atmosphere links (kind = bsky / tangled / supper) derive their URL from the project's current handle by default; a `url` override is allowed for tangled / supper when the canonical destination differs from the handle. Custom link kinds (kind = website / other) always carry their `url`; new records no longer emit website entries.",
91
123
"items": {
92
124
"ref": "#linkEntry",
93
125
"type": "ref"
94
126
},
95
127
"maxLength": 12,
96
128
"type": "array"
97
129
},
130
+
"mainLink": {
131
+
"description": "Primary web destination for the project (the actual web app, service, or website). Rendered as the Web button inside the public profile card when present. Optional when an iOS or Android destination is provided.",
132
+
"format": "uri",
133
+
"maxLength": 512,
134
+
"type": "string"
135
+
},
98
136
"name": {
99
-
"description": "Display name for the project.",
137
+
"description": "Display name for the user or project.",
100
138
"maxGraphemes": 60,
101
139
"maxLength": 60,
102
140
"minLength": 1,
103
141
"type": "string"
104
142
},
143
+
"profileType": {
144
+
"description": "Distinguishes project profiles from user profiles. Omitted means project for backwards compatibility with existing records.",
145
+
"knownValues": [
146
+
"project",
147
+
"user"
148
+
],
149
+
"maxLength": 16,
150
+
"type": "string"
151
+
},
152
+
"screenshots": {
153
+
"description": "Optional screenshots for the project. Up to 4 PNG, JPEG, or WebP images.",
154
+
"items": {
155
+
"ref": "#screenshotEntry",
156
+
"type": "ref"
157
+
},
158
+
"maxLength": 4,
159
+
"type": "array"
160
+
},
105
161
"subcategories": {
106
162
"description": "Open-ended subcategory tags. For apps: microblog, photo, video, blogging, music, events, clients, tools, social, reading, productivity, research, science, reviews, gaming, community, food, location, liveStreaming, niche, content, art.",
107
163
"items": {
108
164
"maxLength": 32,
109
165
"type": "string"
110
166
},
111
167
"maxLength": 10,
112
168
"type": "array"
113
169
}
114
170
},
115
171
"required": [
116
172
"name",
117
-
"description",
118
-
"categories",
119
173
"createdAt"
120
174
],
121
175
"type": "object"
122
176
},
123
177
"type": "record"
178
+
},
179
+
"screenshotEntry": {
180
+
"properties": {
181
+
"image": {
182
+
"accept": [
183
+
"image/png",
184
+
"image/jpeg",
185
+
"image/webp"
186
+
],
187
+
"description": "Screenshot image. Up to 5MB.",
188
+
"maxSize": 5000000,
189
+
"type": "blob"
190
+
}
191
+
},
192
+
"required": [
193
+
"image"
194
+
],
195
+
"type": "object"
124
196
}
125
197
},
126
198
"id": "com.atmosphereaccount.registry.profile",
127
199
"lexicon": 1
128
200
}