forked from learn-anything/learn-anything
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdefault.esdl
368 lines (367 loc) · 13.5 KB
/
default.esdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
95
96
97
98
99
100
101
102
103
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# schema that defines entire LA data model
# User type is at the center of it
# there are `GlobalThings` and `PersonalThings`
# such as GlobalTopic and Topic (will be named PersonalTopic in future)
# GlobalTopic is viewed by all and many can edit it
# PersonalTopic is part of user's PersonalWiki and only that user can edit it (at least for now)
# being edited as we figure out how to best store personal user data and integrate it well
# into the global knowledge graph that is LA
# figjam going over the architecture:
# https://www.figma.com/file/GelB3DWCdjQ2tU4v3kbHOj/LA-architecture?type=whiteboard&node-id=0%3A1&t=nL3VXI1ztTo7ohmd-1
module default {
type User {
# unique email
required email: str {
constraint exclusive;
};
# User is authorised by `hankoToken` which comes from Hanko JWT token
# its unique and is created on signup
hankoId: str {
constraint exclusive;
};
# unique username
name: str {
constraint exclusive;
};
admin: bool;
# custom name user can choose for themselves similar to X
displayName: str;
# aws s3 or cloudflare r2 url with image
profileImage: str;
# TODO: in future can consider `GlobalWiki` as concept maybe as a wiki that multiple users can edit
# user owns one personal wiki
link wiki := .<user[is PersonalWiki];
# topics user wants to learn
multi topicsToLearn: GlobalTopic;
# topics user is learning
multi topicsLearning: GlobalTopic;
# topics user learned
multi topicsLearned: GlobalTopic;
property topicsTracked := count(.topicsToLearn) + count(.topicsLearning) + count(.topicsLearned);
# links user wants to complete
multi linksBookmarked: PersonalLink;
# links user is currently trying to complete
multi linksInProgress: PersonalLink;
# links user has completed
multi linksCompleted: PersonalLink;
# links user has liked
multi linksLiked: PersonalLink;
property linksTracked := count(.linksBookmarked) + count(.linksInProgress) + count(.linksCompleted) + count(.linksLiked);
# links user has disliked (not sure if useful, but we need some way to give feedback to links more perhaps?)
# multi dislikedLinks: GlobalLink;
# notes user has liked
# TODO: what happens when user deletes note? should it be deleted from here too?
# or moved to global note?
multi likedNotes: Note;
# notes user has disliked (same question as for `dislikedLinks`)
# multi dislikedNotes: Note;
# list of topics user is moderating
multi topicsModerated: GlobalTopic;
# products user is selling
multi productsSelling: Product;
# products user bought
multi productsBought: Product;
# date until user has paid membership for
memberUntil: datetime;
# TODO: would be nice to make work but fails right now (https://discord.com/channels/841451783728529451/1176875453336780820/1179455590481809538)
# isMember := ((.memberUntil > datetime_of_statement()) ?? false);
# month / year
stripePlan: str;
# after stripe payment works, you get back subscription object id (can be used to cancel subscription)
stripeSubscriptionObjectId: str;
# whether user has stopped subscription and won't be be charged again
subscriptionStopped: bool;
# limit of actions non member user can do (can be reset every day after to 10 or similar number)
# TODO: not used as instead model of just limiting actions for some operations is used instead (simpler)
# this can be useful for doing AI actions limits as they will cost money
# freeActions: int16 {
# default := 50;
# constraint min_value(0);
# };
}
# other users can `like` or `follow` PersonalWiki
type PersonalWiki {
# TODO: is `required link user` the best way to store this relationship of a user owning one wiki
# owner of this wiki
required link user: User;
# all topics belonging to this wiki
multi link topics := .<wiki[is Topic];
# TODO: everything below is questionable (maybe no need to store it)
# contains topic names + children of the topic(s)
# is used to generate sidebar in wiki
# indent is how to know which topics are children of which
# sorted alphebetically
# example:
# {
# 0: {name: 'Analytics', indent: 0},
# 1: {name: 'Grafana', indent: 1},
# }
# TODO: should in theory just be array of objects above. but how?
# TODO: perhaps there is better way to do this?8
# TODO: probably computed from the topics, can also compute it as part of query
# so maybe no need to store it?
topicSidebar: json;
# used to generate local interactive graph of topics for wiki
# TODO: find out structure needed for this
# TODO: same for this, can be computed as part of query
topicGraph: json;
}
# TODO: should be called PersonalTopic
type Topic {
# wiki this topic belongs to
required link wiki: PersonalWiki;
# url friendly unique name of topic. i.e. 'physics' or 'linear-algebra'
# lowercase + dash separate words
# the connected .md file name of topic is also this name
required name: str {
constraint exclusive;
};
# pretty version of `name`, uppercased nicely, proper capitalisation
# i.e. Physics
required prettyName: str;
# markdown content of topic (user's knowledge/thoughts on the topic)
required content: str;
# true = anyone can see the topic. false = only user can see topic
public: bool;
# non published content will be end to end encrypted
required published: bool;
# each published topic is part of a global topic
# TODO: not sure how to best do it
# TODO: probably best to just do it by `name`, if `name` matches, its part of that global topic
globalTopic: GlobalTopic;
# optional path of topic: /physics/quantum-physics where each GlobalTopic name is separated by /
# for start, do the folder/file structure and have that be the topicPath
# optional for users to define
topicPath: str;
# TODO: there should probably be a GlobalNote and PersonalNote
# all notes belonging to this topic
multi link notes := .<topic[is Note];
# all links belonging to this topic (TODO: think through how best do it with GlobalLink)
multi link links := .<topic[is Link];
# parent topic if there is one
parentTopic: Topic;
# topics that are mentioned in this topic (computed every time topic changes)
# TODO: maybe no need to save it but have it be derived?
multi mentionedTopics: Topic;
# mentions of this topic in other topics
# TODO: maybe no need to save it but have it be derived?
multi topicBacklinks: Topic;
# users can't have two topics with same name
constraint exclusive on ((.name, .wiki));
# everything in the topic as markdown
# recomputed on every change made to the topic
topicAsMarkdown: str;
}
type Note {
# main topic this note belongs to
required topic: Topic;
# main content of the note
required content: str;
# true = anyone can see the note. false = only user can see note
required public: bool;
# topics this note can also relate more loosely to
# there is still one main topic a note belongs to as chosen by user
multi relatedTopics: Topic;
# additional content of the note
# i.e.
# - note
# - additional content in form of subnotes
# - another subnote
additionalContent: str;
# url from where the note was taken from or has reference to
url: str;
}
type Link {
# main topic this link belongs to
required topic: Topic;
# url of the link
required url: str;
# title as grabbed from the url
urlTitle: str;
# title of link as set by the user
title: str;
# true = anyone can see the link. false = only user can see link
required public: bool;
# type of the link: course/pdf/video/..
# TODO: should be a new object as Type maybe?
type: str;
# link description
description: str;
# how long it takes to `process` the link
# if its article, estimate content of article by average/user reading time
# if video, it's time length of video. i.e. `12 min`
timeEstimate: str;
# author of the link
author: str;
# TODO: should probably be int, but keeping it str for now
year: str;
# related links to this link
# could be link to `Code` or `Tweet` or some other Link
multi relatedLinks: RelatedLink;
# all links are mapped by unique URL to a global link
link globalLink: GlobalLink {
on target delete allow;
};
}
type RelatedLink {
url: str;
title: str;
}
type GlobalLink {
# nice title from url
required title: str;
# unique url of the link (without protocol)
required url: str {
constraint exclusive;
};
# http / https
required protocol: str;
# full url of the link as saved initially by user
fullUrl: str;
# true = link was verified, its valid URL, good metadata was added etc.
required verified: bool;
# true = link is available for all to see/search. false = link is private
required public: bool;
# link description
description: str;
# title as grabbed from url
urlTitle: str;
# optionally have a main topic that the link belongs to
link mainTopic: GlobalTopic;
# TODO: should probably be int, but keeping it str for now
year: str;
# related links to this link
# could be link to `Code` or `Tweet` or some other Link
multi relatedLinks: RelatedLink;
# connected topics for this link
multi link links := .<globalLink[is Link];
}
type PersonalLink {
required link globalLink: GlobalLink {
constraint exclusive;
};
title: str;
description: str;
link mainTopic: GlobalTopic;
}
type GlobalNote {
required content: str;
url: str;
# optionally have a main topic that the note belongs to
link mainTopic: GlobalTopic;
}
type GlobalTopic {
# url friendly unique name of topic. i.e. 'physics' or 'linear-algebra'
# lowercase + dash separate words
required name: str {
constraint exclusive;
};
# pretty version of `name`, uppercased nicely, proper capitalisation i.e. Physics
required prettyName: str;
# detailed summary of the topic (in html, due to https://github.com/SaltyAom/mobius/issues/4)
topicSummary: str;
# summary of the topic (short version)
topicSummaryShort: str;
# global guide for the topic, improved by community
# required globalTopic := .<globalTopic[is GlobalTopic];
# true = topic is available to anyone to see
# i.e. learn-anything.xyz/physics
# false = not available for all to see
# kept for future, needs more thinking, how it's different to `verified`
required public: bool;
# true = topic was verified (reviewed by LA and approved to be shown on LA)
required verified: bool;
# optional path of topic: /physics/quantum-physics where each GlobalTopic name is separated by /
topicPath: str;
# used to generate interactive graph of topics for the global topic
# check GlobalGraph type for structure
similarTopicsGraph: json;
# related topics to this global topic
multi relatedTopics: GlobalTopic;
# all links submitted to the global topic
multi relatedLinks: GlobalLink;
# all notes submitted to the global topic
multi relatedNotes: Note;
# link globalGuide: GlobalGuide {
# on target delete allow;
# };
# past changes to global guide versioned by time
multi globalGuides: GlobalGuide;
# there is one global guide attached to each global topic
latestGlobalGuide: GlobalGuide;
description: str;
topicWebsiteLink: str;
wikipediaLink: str;
githubLink: str;
xLink: str;
redditLink: str;
aiSummary: str;
}
type GlobalGuide {
required created_at: datetime {
readonly := true;
default := datetime_of_statement();
}
# guide is split by sections
multi sections: GlobalGuideSection {
on target delete allow;
}
}
type GlobalGuideSection {
# title of section
required title: str;
# summary of the section (in html, due to https://github.com/SaltyAom/mobius/issues/4)
summary: str;
# list of links in a section
multi links: GlobalLink {
order: int16;
};
}
type UserGuide {
# global topic
required link globalTopic: GlobalTopic;
required created_at: datetime {
readonly := true;
default := datetime_of_statement();
}
# guide is split by sections
multi sections: UserGuideSection;
# owner of guide
required link user: User;
}
type UserGuideSection {
# title of section
required title: str;
# list of links in a section
multi links: GlobalLink;
}
# TODO: think through how useful this is
type GlobalGraph {
# JSON graph of all topics and connections
# structure:
# [
# {
# 'topic': "physics",
# 'links': [{"topic": "quantum-physics", "weight": 1}, {"topic": "relativity", "weight": 1}"}]
# }
# ]
# gets recomputed from how users in LA draw connections between topics
required connections: json;
}
# digital marketplace (anything from above can in theory be a product that can have a price attached)
# or be gated to certain members that user decides on
type Product {
required name: str;
description: str;
imageUrl: str;
websiteUrl: str;
priceInUsdCents: int16;
}
}
# TODO: think through more
# users should be able to favorite some instance of NeuralCache
# it should be tied to some mainTopic too
# type NeuralCache {
# question: str;
# answer: str;
# }