summaryrefslogtreecommitdiffstats
path: root/docs/src
diff options
context:
space:
mode:
authorFelix Ableitner <me@nutomic.com>2019-12-31 15:31:34 +0100
committerFelix Ableitner <me@nutomic.com>2020-01-01 17:24:36 +0100
commitd80e8fc075bc9afb699afd1d6e5e5f79a0db9cd1 (patch)
treea0d6a0781a3d39905ba93a867b55cf5c669c6220 /docs/src
parent0b04aec6024ee87b6a3651b1f39f7726c5a1d0e7 (diff)
Use mdbook for documentation (fixes #375)
Diffstat (limited to 'docs/src')
-rw-r--r--docs/src/SUMMARY.md17
-rw-r--r--docs/src/about.md22
-rw-r--r--docs/src/about_features.md26
-rw-r--r--docs/src/about_goals.md44
-rw-r--r--docs/src/about_ranking.md29
-rw-r--r--docs/src/administration.md1
-rw-r--r--docs/src/administration_configuration.md6
-rw-r--r--docs/src/administration_install_ansible.md11
-rw-r--r--docs/src/administration_install_docker.md28
-rw-r--r--docs/src/administration_install_kubernetes.md22
-rw-r--r--docs/src/contributing.md1
-rw-r--r--docs/src/contributing_apub_api_outline.md378
-rw-r--r--docs/src/contributing_docker_development.md11
-rw-r--r--docs/src/contributing_local_development.md24
-rw-r--r--docs/src/contributing_translations.md23
-rw-r--r--docs/src/contributing_websocket_api.md1031
16 files changed, 1674 insertions, 0 deletions
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
new file mode 100644
index 00000000..9fc0fa87
--- /dev/null
+++ b/docs/src/SUMMARY.md
@@ -0,0 +1,17 @@
+# Summary
+
+- [About](about.md)
+ - [Features](about_features.md)
+ - [Goals](about_goals.md)
+ - [Post and Comment Ranking](about_ranking.md)
+- [Administration](administration.md)
+ - [Install with Docker](administration_install_docker.md)
+ - [Install with Ansible](administration_install_ansible.md)
+ - [Install with Kubernetes](administration_install_kubernetes.md)
+ - [Configuration](administration_configuration.md)
+- [Contributing](contributing.md)
+ - [Translations](contributing_translations.md)
+ - [Docker Development](contributing_docker_development.md)
+ - [Local Development](contributing_local_development.md)
+ - [Websocket API](contributing_websocket_api.md)
+ - [ActivityPub API Outline](contributing_apub_api_outline.md)
diff --git a/docs/src/about.md b/docs/src/about.md
new file mode 100644
index 00000000..14743df2
--- /dev/null
+++ b/docs/src/about.md
@@ -0,0 +1,22 @@
+<p align="center">A link aggregator / reddit clone for the fediverse.
+ <br>
+</p>
+
+[Lemmy Dev instance](https://dev.lemmy.ml) *for testing purposes only*
+
+[Lemmy](https://github.com/dessalines/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse).
+
+For a link aggregator, this means a user registered on one server can subscribe to forums on any other server, and can have discussions with users registered elsewhere.
+
+The overall goal is to create an easily self-hostable, decentralized alternative to reddit and other link aggregators, outside of their corporate control and meddling.
+
+Each lemmy server can set its own moderation policy; appointing site-wide admins, and community moderators to keep out the trolls, and foster a healthy, non-toxic environment where all can feel comfortable contributing.
+
+### Why's it called Lemmy?
+
+- Lead singer from [Motörhead](https://invidio.us/watch?v=pWB5JZRGl0U).
+- The old school [video game](<https://en.wikipedia.org/wiki/Lemmings_(video_game)>).
+- The [Koopa from Super Mario](https://www.mariowiki.com/Lemmy_Koopa).
+- The [furry rodents](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/).
+
+Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Inferno](https://www.infernojs.org), [Typescript](https://www.typescriptlang.org/) and [Diesel](http://diesel.rs/).
diff --git a/docs/src/about_features.md b/docs/src/about_features.md
new file mode 100644
index 00000000..dab859c1
--- /dev/null
+++ b/docs/src/about_features.md
@@ -0,0 +1,26 @@
+- Open source, [AGPL License](/LICENSE).
+- Self hostable, easy to deploy.
+ - Comes with [Docker](#docker), [Ansible](#ansible), [Kubernetes](#kubernetes).
+- Clean, mobile-friendly interface.
+ - Live-updating Comment threads.
+ - Full vote scores `(+/-)` like old reddit.
+ - Themes, including light, dark, and solarized.
+ - Emojis with autocomplete support. Start typing `:`
+ - User tagging using `@`, Community tagging using `#`.
+ - Notifications, on comment replies and when you're tagged.
+ - i18n / internationalization support.
+ - RSS / Atom feeds for `All`, `Subscribed`, `Inbox`, `User`, and `Community`.
+- Cross-posting support.
+ - A *similar post search* when creating new posts. Great for question / answer communities.
+- Moderation abilities.
+ - Public Moderation Logs.
+ - Both site admins, and community moderators, who can appoint other moderators.
+ - Can lock, remove, and restore posts and comments.
+ - Can ban and unban users from communities and the site.
+ - Can transfer site and communities to others.
+- Can fully erase your data, replacing all posts and comments.
+- NSFW post / community support.
+- High performance.
+ - Server is written in rust.
+ - Front end is `~80kB` gzipped.
+ - Supports arm64 / Raspberry Pi. \ No newline at end of file
diff --git a/docs/src/about_goals.md b/docs/src/about_goals.md
new file mode 100644
index 00000000..d8a71794
--- /dev/null
+++ b/docs/src/about_goals.md
@@ -0,0 +1,44 @@
+# Goals
+- Come up with a name / codename.
+- Must have communities.
+- Must have threaded comments.
+- Must be federated: liking and following communities across instances.
+- Be live-updating: have a right pane for new comments, and a main pain for the full threaded view.
+ - Use websockets for post / gets to your own instance.
+
+# Questions
+- How does voting work? Should we go back to the old way of showing up and downvote counts? Or just a score?
+- Decide on tech to be used
+ - Backend: Actix, Diesel.
+ - Frontend: inferno, typescript and bootstrap for now.
+- Should it allow bots?
+- Should the comments / votes be static, or feel like a chat, like [flowchat?](https://flow-chat.com).
+ - Two pane model - Right pane is live comments, left pane is live tree view.
+ - On mobile, allow you to switch between them. Default?
+
+# Resources / Potential Libraries
+- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
+- https://docs.rs/activitypub/0.1.4/activitypub/
+- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
+- [Activitypub main](https://www.w3.org/TR/activitypub/)
+- [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html)
+- [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/)
+- [Recursive query for adjacency list for nested comments](https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into-a-tree/192462#192462)
+- https://github.com/sparksuite/simplemde-markdown-editor
+- [Markdown-it](https://github.com/markdown-it/markdown-it)
+- [Sticky Sidebar](https://stackoverflow.com/questions/38382043/how-to-use-css-position-sticky-to-keep-a-sidebar-visible-with-bootstrap-4/49111934)
+- [RXJS websocket](https://stackoverflow.com/questions/44060315/reconnecting-a-websocket-in-angular-and-rxjs/44067972#44067972)
+- [Rust JWT](https://github.com/Keats/jsonwebtoken)
+- [Hierarchical tree building javascript](https://stackoverflow.com/a/40732240/1655478)
+- [Hot sorting discussion](https://meta.stackexchange.com/questions/11602/what-formula-should-be-used-to-determine-hot-questions) [2](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9)
+- [Classification types.](https://www.reddit.com/r/ModeratorDuck/wiki/subreddit_classification)
+- [RES expando - Possibly make this into a switching react component.](https://github.com/honestbleeps/Reddit-Enhancement-Suite/tree/d21f55c21e734f47d8ed03fe0ebce5b16653b0bd/lib/modules/hosts)
+- [Temp Icon](https://www.flaticon.com/free-icon/mouse_194242)
+- [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/)
+- [Zurb mentions](https://github.com/zurb/tribute)
+- Activitypub guides
+ - https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/
+ - https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tutorial.txt
+ - https://github.com/tOkeshu/activitypub-example
+ - https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/
+
diff --git a/docs/src/about_ranking.md b/docs/src/about_ranking.md
new file mode 100644
index 00000000..361dc24d
--- /dev/null
+++ b/docs/src/about_ranking.md
@@ -0,0 +1,29 @@
+# Trending / Hot / Best Sorting algorithm
+## Goals
+- During the day, new posts and comments should be near the top, so they can be voted on.
+- After a day or so, the time factor should go away.
+- Use a log scale, since votes tend to snowball, and so the first 10 votes are just as important as the next hundred.
+
+## Reddit Sorting
+[Reddit's comment sorting algorithm](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9), the wilson confidence sort, is inadequate, because it completely ignores time. What ends up happening, especially in smaller subreddits, is that the early comments end up getting upvoted, and newer comments stay at the bottom, never to be seen. Research showed that nearly all top comments are just the [first ones posted.](https://minimaxir.com/2016/11/first-comment/)
+
+## Hacker News Sorting
+The [Hacker New's ranking algorithm](https://medium.com/hacking-and-gonzo/how-hacker-news-ranking-algorithm-works-1d9b0cf2c08d) is great, but it doesn't use a log scale for the scores.
+
+## My Algorithm
+```
+Rank = ScaleFactor * log(Max(1, 3 + Score)) / (Time + 2)^Gravity
+
+Score = Upvotes - Downvotes
+Time = time since submission (in hours)
+Gravity = Decay gravity, 1.8 is default
+```
+
+- Use Max(1, score) to make sure all comments are affected by time decay.
+- Add 3 to the score, so that everything that has less than 3 downvotes will seem new. Otherwise all new comments would stay at zero, near the bottom.
+- The sign and abs of the score are necessary for dealing with the log of negative scores.
+- A scale factor of 10k gets the rank in integer form.
+
+A plot of rank over 24 hours, of scores of 1, 5, 10, 100, 1000, with a scale factor of 10k.
+
+![](https://i.imgur.com/w8oBLlL.png)
diff --git a/docs/src/administration.md b/docs/src/administration.md
new file mode 100644
index 00000000..c4c2b01f
--- /dev/null
+++ b/docs/src/administration.md
@@ -0,0 +1 @@
+Information for Lemmy instance admins, and those who want to start an instance. \ No newline at end of file
diff --git a/docs/src/administration_configuration.md b/docs/src/administration_configuration.md
new file mode 100644
index 00000000..73ea3504
--- /dev/null
+++ b/docs/src/administration_configuration.md
@@ -0,0 +1,6 @@
+The configuration is based on the file [defaults.hjson](server/config/defaults.hjson). This file also contains documentation for all the available options. To override the defaults, you can copy the options you want to change into your local `config.hjson` file.
+
+Additionally, you can override any config files with environment variables. These have the same name as the config options, and are prefixed with `LEMMY_`. For example, you can override the `database.password` with
+`LEMMY__DATABASE__POOL_SIZE=10`.
+
+An additional option `LEMMY_DATABASE_URL` is available, which can be used with a PostgreSQL connection string like `postgres://lemmy:password@lemmy_db:5432/lemmy`, passing all connection details at once.
diff --git a/docs/src/administration_install_ansible.md b/docs/src/administration_install_ansible.md
new file mode 100644
index 00000000..03642b89
--- /dev/null
+++ b/docs/src/administration_install_ansible.md
@@ -0,0 +1,11 @@
+First, you need to [install Ansible on your local computer](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (e.g. using `sudo apt install ansible`) or the equivalent for you platform.
+
+Then run the following commands on your local computer:
+
+```bash
+git clone https://github.com/dessalines/lemmy.git
+cd lemmy/ansible/
+cp inventory.example inventory
+nano inventory # enter your server, domain, contact email
+ansible-playbook lemmy.yml --become
+```
diff --git a/docs/src/administration_install_docker.md b/docs/src/administration_install_docker.md
new file mode 100644
index 00000000..64abe737
--- /dev/null
+++ b/docs/src/administration_install_docker.md
@@ -0,0 +1,28 @@
+Make sure you have both docker and docker-compose(>=`1.24.0`) installed:
+
+```bash
+mkdir lemmy/
+cd lemmy/
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson
+# Edit lemmy.hjson to do more configuration
+docker-compose up -d
+```
+
+and go to http://localhost:8536.
+
+[A sample nginx config](/ansible/templates/nginx.conf), could be setup with:
+
+```bash
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf
+# Replace the {{ vars }}
+sudo mv nginx.conf /etc/nginx/sites-enabled/lemmy.conf
+```
+#### Updating
+
+To update to the newest version, run:
+
+```bash
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
+docker-compose up -d
+```
diff --git a/docs/src/administration_install_kubernetes.md b/docs/src/administration_install_kubernetes.md
new file mode 100644
index 00000000..886558dc
--- /dev/null
+++ b/docs/src/administration_install_kubernetes.md
@@ -0,0 +1,22 @@
+You'll need to have an existing Kubernetes cluster and [storage class](https://kubernetes.io/docs/concepts/storage/storage-classes/).
+Setting this up will vary depending on your provider.
+To try it locally, you can use [MicroK8s](https://microk8s.io/) or [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/).
+
+Once you have a working cluster, edit the environment variables and volume sizes in `docker/k8s/*.yml`.
+You may also want to change the service types to use `LoadBalancer`s depending on where you're running your cluster (add `type: LoadBalancer` to `ports)`, or `NodePort`s.
+By default they will use `ClusterIP`s, which will allow access only within the cluster. See the [docs](https://kubernetes.io/docs/concepts/services-networking/service/) for more on networking in Kubernetes.
+
+**Important** Running a database in Kubernetes will work, but is generally not recommended.
+If you're deploying on any of the common cloud providers, you should consider using their managed database service instead (RDS, Cloud SQL, Azure Databse, etc.).
+
+Now you can deploy:
+
+```bash
+# Add `-n foo` if you want to deploy into a specific namespace `foo`;
+# otherwise your resources will be created in the `default` namespace.
+kubectl apply -f docker/k8s/db.yml
+kubectl apply -f docker/k8s/pictshare.yml
+kubectl apply -f docker/k8s/lemmy.yml
+```
+
+If you used a `LoadBalancer`, you should see it in your cloud provider's console.
diff --git a/docs/src/contributing.md b/docs/src/contributing.md
new file mode 100644
index 00000000..4f29af3d
--- /dev/null
+++ b/docs/src/contributing.md
@@ -0,0 +1 @@
+Information about contributing to Lemmy, whether it is translating, testing, designing or programming. \ No newline at end of file
diff --git a/docs/src/contributing_apub_api_outline.md b/docs/src/contributing_apub_api_outline.md
new file mode 100644
index 00000000..e2776308
--- /dev/null
+++ b/docs/src/contributing_apub_api_outline.md
@@ -0,0 +1,378 @@
+# Activitypub API outline
+
+- Start with the [reddit API](https://www.reddit.com/dev/api), and find [Activitypub vocab](https://www.w3.org/TR/activitystreams-vocabulary/) to match it.
+
+<!-- toc -->
+
+- [Actors](#actors)
+ * [User / Person](#user--person)
+ * [Community / Group](#community--group)
+- [Objects](#objects)
+ * [Post / Page](#post--page)
+ * [Post Listings / Ordered CollectionPage](#post-listings--ordered-collectionpage)
+ * [Comment / Note](#comment--note)
+ * [Comment Listings / Ordered CollectionPage](#comment-listings--ordered-collectionpage)
+ * [Deleted thing / Tombstone](#deleted-thing--tombstone)
+- [Actions](#actions)
+ * [Comments](#comments)
+ + [Create](#create)
+ + [Delete](#delete)
+ + [Update](#update)
+ + [Read](#read)
+ + [Like](#like)
+ + [Dislike](#dislike)
+ * [Posts](#posts)
+ + [Create](#create-1)
+ + [Delete](#delete-1)
+ + [Update](#update-1)
+ + [Read](#read-1)
+ * [Communities](#communities)
+ + [Create](#create-2)
+ + [Delete](#delete-2)
+ + [Update](#update-2)
+ + [Join](#join)
+ + [Leave](#leave)
+ * [Moderator](#moderator)
+ + [Ban user from community / Block](#ban-user-from-community--block)
+ + [Delete Comment](#delete-comment)
+ + [Invite a moderator](#invite-a-moderator)
+ + [Accept Invitation](#accept-invitation)
+ + [Reject Invitation](#reject-invitation)
+
+<!-- tocstop -->
+
+## Actors
+
+### [User / Person](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Person",
+ "id": "https://instance_url/api/v1/user/sally_smith",
+ "inbox": "https://instance_url/api/v1/user/sally_smith/inbox",
+ "outbox": "https://instance_url/api/v1/user/sally_smith/outbox",
+ "liked": "https://instance_url/api/v1/user/sally_smith/liked",
+ // TODO disliked?
+ "following": "https://instance_url/api/v1/user/sally_smith/following",
+ "name": "sally_smith",
+ "preferredUsername": "Sally",
+ "icon"?: {
+ "type": "Image",
+ "name": "User icon",
+ "url": "https://instance_url/api/v1/user/sally_smith/icon.png",
+ "width": 32,
+ "height": 32
+ },
+ "published": "2014-12-31T23:00:00-08:00",
+ "summary"?: "This is sally's profile."
+}
+```
+
+### [Community / Group](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Group",
+ "id": "https://instance_url/api/v1/community/today_i_learned",
+ "name": "today_i_learned"
+ "attributedTo": [ // The moderators
+ "http://joe.example.org",
+ ],
+ "followers": "https://instance_url/api/v1/community/today_i_learned/followers",
+ "published": "2014-12-31T23:00:00-08:00",
+ "summary"?: "The group's tagline",
+ "attachment: [{}] // TBD, these would be where strong types for custom styles, and images would work.
+}
+```
+
+## Objects
+
+### [Post / Page](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Page",
+ "id": "https://instance_url/api/v1/post/1",
+ "name": "The title of a post, maybe a link to imgur",
+ "url": "https://news.blah.com"
+ "attributedTo": "http://joe.example.org", // The poster
+ "published": "2014-12-31T23:00:00-08:00",
+}
+```
+
+### [Post Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "OrderedCollectionPage",
+ "id": "https://instance_url/api/v1/posts?type={all, best, front}&sort={}&page=1,
+ "partOf": "http://example.org/foo",
+ "orderedItems": [Posts]
+}
+```
+
+### [Comment / Note](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Note",
+ "id": "https://instance_url/api/v1/comment/1",
+ "mediaType": "text/markdown",
+ "content": "Looks like it is going to rain today. Bring an umbrella *if necessary*!"
+ "attributedTo": john_id,
+ "inReplyTo": "comment or post id",
+ "published": "2014-12-31T23:00:00-08:00",
+ "updated"?: "2014-12-12T12:12:12Z"
+ "replies" // TODO, not sure if these objects should embed all replies in them or not.
+ "to": [sally_id, group_id]
+}
+```
+### [Comment Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "OrderedCollectionPage",
+ "id": "https://instance_url/api/v1/comments?type={all,user,community,post,parent_comment}&id=1&page=1,
+ "partOf": "http://example.org/foo",
+ "orderedItems": [Comments]
+}
+```
+### [Deleted thing / Tombstone](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone)
+```
+{
+ "type": "Tombstone",
+ "formerType": "Note / Post",
+ "id": note / post_id,
+ "deleted": "2016-03-17T00:00:00Z"
+}
+```
+## Actions
+- These are all posts to a user's outbox.
+- The server then creates a post to the necessary inbox of the recipient, or the followers.
+- Whenever a user accesses the site, they do a get from their inbox.
+
+### Comments
+#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "object": comment_id, or post_id
+}
+```
+#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Delete",
+ "actor": id,
+ "object": comment_id, or post_id
+}
+```
+#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "object": comment_id, or post_id
+ "content": "New comment",
+ "updated": "New Date"
+}
+```
+#### [Read](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Read",
+ "actor": user_id
+ "object": comment_id
+}
+```
+
+#### [Like](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like)
+- TODO: Should likes be notifications? IE, have a to?
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Like",
+ "actor": user_id
+ "object": comment_id
+ // TODO different types of reactions, or no?
+}
+```
+#### [Dislike](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Dislike",
+ "actor": user_id
+ "object": comment_id
+ // TODO different types of reactions, or no?
+}
+```
+
+### Posts
+#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "to": community_id/followers
+ "object": post_id
+}
+```
+#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Delete",
+ "actor": id,
+ "object": comment_id, or post_id
+}
+```
+
+#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "object": comment_id, or post_id
+ TODO fields.
+}
+```
+#### [Read](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Read",
+ "actor": user_id
+ "object": post_id
+}
+```
+
+### Communities
+#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "object": community_id
+}
+```
+#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Delete",
+ "actor": id,
+ "object": community_id
+}
+```
+
+#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": id,
+ "object": community_id
+ TODO fields.
+}
+```
+
+#### [Follow / Subscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Follow",
+ "actor": id
+ "object": community_id
+}
+```
+
+#### [Ignore/ Unsubscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Follow",
+ "actor": id
+ "object": community_id
+}
+```
+#### [Join / Become a Mod](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Join",
+ "actor": user_id,
+ "object": community_id
+}
+```
+
+#### [Leave](https://www.w3.org/TR/activitystreams-vocabulary#dfn-leave)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Leave",
+ "actor": user_id,
+ "object": community_id
+}
+```
+
+### Moderator
+#### [Ban user from community / Block](https://www.w3.org/TR/activitystreams-vocabulary#dfn-block)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Remove",
+ "actor": mod_id,
+ "object": user_id,
+ "origin": group_id
+}
+```
+
+#### [Delete Comment](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Delete",
+ "actor": id,
+ "object": community_id
+}
+```
+
+#### [Invite a moderator](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Invite",
+ "id": "https://instance_url/api/v1/invite/1",
+ "actor": sally_id,
+ "object": group_id,
+ "target": john_id
+}
+```
+#### [Accept Invitation](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Accept",
+ "actor": john_id,
+ "object": invite_id
+}
+```
+#### [Reject Invitation](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Reject",
+ "actor": john_id,
+ "object": invite_id
+}
+```
+
diff --git a/docs/src/contributing_docker_development.md b/docs/src/contributing_docker_development.md
new file mode 100644
index 00000000..0ed5bde5
--- /dev/null
+++ b/docs/src/contributing_docker_development.md
@@ -0,0 +1,11 @@
+Run:
+
+```bash
+git clone https://github.com/dessalines/lemmy
+cd lemmy/docker/dev
+./docker_update.sh # This builds and runs it, updating for your changes
+```
+
+and go to http://localhost:8536.
+
+Note that compile times are relatively long with Docker, because builds can't be properly cached. If this is a problem for you, you should use [Local Development](contributing_local_development.md). \ No newline at end of file
diff --git a/docs/src/contributing_local_development.md b/docs/src/contributing_local_development.md
new file mode 100644
index 00000000..a681eeb0
--- /dev/null
+++ b/docs/src/contributing_local_development.md
@@ -0,0 +1,24 @@
+#### Requirements
+
+- [Rust](https://www.rust-lang.org/)
+- [Yarn](https://yarnpkg.com/en/)
+- [Postgres](https://www.postgresql.org/)
+
+#### Set up Postgres DB
+
+```bash
+ psql -c "create user lemmy with password 'password' superuser;" -U postgres
+ psql -c 'create database lemmy with owner lemmy;' -U postgres
+ export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
+```
+
+#### Running
+
+```bash
+git clone https://github.com/dessalines/lemmy
+cd lemmy
+./install.sh
+# For live coding, where both the front and back end, automagically reload on any save, do:
+# cd ui && yarn start
+# cd server && cargo watch -x run
+```
diff --git a/docs/src/contributing_translations.md b/docs/src/contributing_translations.md
new file mode 100644
index 00000000..de890770
--- /dev/null
+++ b/docs/src/contributing_translations.md
@@ -0,0 +1,23 @@
+If you'd like to add translations, take a look a look at the [English translation file](ui/src/translations/en.ts).
+
+- Languages supported: English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`).
+
+lang | done | missing
+--- | --- | ---
+de | 97% | avatar,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw
+eo | 84% | number_of_communities,preview,upload_image,avatar,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,theme,are_you_sure,yes,no
+es | 92% | avatar,archive_link,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw
+fr | 92% | avatar,archive_link,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw
+it | 93% | avatar,archive_link,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw
+nl | 86% | preview,upload_image,avatar,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,theme
+ru | 80% | cross_posts,cross_post,number_of_communities,preview,upload_image,avatar,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,recent_comments,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+sv | 92% | avatar,archive_link,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw
+zh | 78% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,avatar,formatting_help,view_source,sticky,unsticky,archive_link,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,recent_comments,nsfw,show_nsfw,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+
+
+If you'd like to update this report, run:
+
+```bash
+cd ui
+ts-node translation_report.ts > tmp # And replace the text above.
+``` \ No newline at end of file
diff --git a/docs/src/contributing_websocket_api.md b/docs/src/contributing_websocket_api.md
new file mode 100644
index 00000000..16383d53
--- /dev/null
+++ b/docs/src/contributing_websocket_api.md
@@ -0,0 +1,1031 @@
+# Lemmy API
+*Note: this may lag behind the actual API endpoints [here](../server/src/api).*
+
+<!-- toc -->
+
+- [Data types](#data-types)
+- [Basic usage](#basic-usage)
+ * [WebSocket Endpoint](#websocket-endpoint)
+ * [Testing with Websocat](#testing-with-websocat)
+ * [Testing with the WebSocket JavaScript API](#testing-with-the-websocket-javascript-api)
+- [Rate limits](#rate-limits)
+- [Errors](#errors)
+- [API documentation](#api-documentation)
+ * [Sort Types](#sort-types)
+ * [User / Authentication / Admin actions](#user--authentication--admin-actions)
+ + [Login](#login)
+ - [Request](#request)
+ - [Response](#response)
+ + [Register](#register)
+ - [Request](#request-1)
+ - [Response](#response-1)
+ + [Get User Details](#get-user-details)
+ - [Request](#request-2)
+ - [Response](#response-2)
+ + [Save User Settings](#save-user-settings)
+ - [Request](#request-3)
+ - [Response](#response-3)
+ + [Get Replies / Inbox](#get-replies--inbox)
+ - [Request](#request-4)
+ - [Response](#response-4)
+ + [Get User Mentions](#get-user-mentions)
+ - [Request](#request-5)
+ - [Response](#response-5)
+ + [Mark All As Read](#mark-all-as-read)
+ - [Request](#request-6)
+ - [Response](#response-6)
+ + [Delete Account](#delete-account)
+ - [Request](#request-7)
+ - [Response](#response-7)
+ + [Add admin](#add-admin)
+ - [Request](#request-8)
+ - [Response](#response-8)
+ + [Ban user](#ban-user)
+ - [Request](#request-9)
+ - [Response](#response-9)
+ * [Site](#site)
+ + [List Categories](#list-categories)
+ - [Request](#request-10)
+ - [Response](#response-10)
+ + [Search](#search)
+ - [Request](#request-11)
+ - [Response](#response-11)
+ + [Get Modlog](#get-modlog)
+ - [Request](#request-12)
+ - [Response](#response-12)
+ + [Create Site](#create-site)
+ - [Request](#request-13)
+ - [Response](#response-13)
+ + [Edit Site](#edit-site)
+ - [Request](#request-14)
+ - [Response](#response-14)
+ + [Get Site](#get-site)
+ - [Request](#request-15)
+ - [Response](#response-15)
+ + [Transfer Site](#transfer-site)
+ - [Request](#request-16)
+ - [Response](#response-16)
+ * [Community](#community)
+ + [Get Community](#get-community)
+ - [Request](#request-17)
+ - [Response](#response-17)
+ + [Create Community](#create-community)
+ - [Request](#request-18)
+ - [Response](#response-18)
+ + [List Communities](#list-communities)
+ - [Request](#request-19)
+ - [Response](#response-19)
+ + [Ban from Community](#ban-from-community)
+ - [Request](#request-20)
+ - [Response](#response-20)
+ + [Add Mod to Community](#add-mod-to-community)
+ - [Request](#request-21)
+ - [Response](#response-21)
+ + [Edit Community](#edit-community)
+ - [Request](#request-22)
+ - [Response](#response-22)
+ + [Follow Community](#follow-community)
+ - [Request](#request-23)
+ - [Response](#response-23)
+ + [Get Followed Communities](#get-followed-communities)
+ - [Request](#request-24)
+ - [Response](#response-24)
+ + [Transfer Commun