diff --git a/.dockerignore b/.dockerignore
index ab350a72f..0096a00a7 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -38,7 +38,6 @@ node_modules/
/app/assets/javascripts/generated/*
latest.dump
.byebug_history
-.gitdocs_build/
# Ignore application configuration
/public/packs
diff --git a/.gitdocs.js b/.gitdocs.js
deleted file mode 100644
index 577ad7eda..000000000
--- a/.gitdocs.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is created so that it's possible to
- * Run `gitdocs serve` from root
- */
-
-var config = require('./docs/.gitdocs.json');
-
-module.exports = new Promise((resolve, reject) => {
- config.root = 'docs/';
- setupHost(config);
- resolve(config);
-});
-
-function fetchAppDomain() {
- const { execSync } = require('child_process');
-
- const appDomainGetCmd =
- 'rails runner "puts ApplicationConfig.app_domain_no_port"';
- return execSync(appDomainGetCmd).toString().replace(/\s/g, '');
-}
-
-function setupHost(config) {
- const appDomain = fetchAppDomain();
-
- if (config.host === '0.0.0.0' && appDomain) {
- config.host = appDomain;
- }
-}
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 6cff4fb11..a2dd8c469 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -41,7 +41,7 @@ images for UI changes._
_If your PR includes UI changes, please replace this line with details on how
accessibility is impacted and tested. For more info, check out the
-[Forem Accessibility Docs](https://docs.forem.com/frontend/accessibility)._
+[Forem Accessibility Docs](https://developers.forem.com/frontend/accessibility)._
## Added/updated tests?
@@ -56,7 +56,7 @@ _Will this PR introduce a change that impacts Forem members or creators, the
development process, or any of our internal teams? If so, please note how you
will share this change with the people who need to know about it._
-- [ ] I've updated the [Developer Docs](https://docs.forem.com) and/or
+- [ ] I've updated the [Developer Docs](https://developers.forem.com) and/or
[Admin Guide](https://admin.forem.com/), or
[Storybook](https://storybook.forem.com/) (for Crayons components)
- [ ] I've updated the README or added inline documentation
diff --git a/.gitignore b/.gitignore
index dfcc73ac3..cabc9083a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,7 +32,6 @@ node_modules/
/app/assets/javascripts/generated/*
latest.dump
.byebug_history
-.gitdocs_build/
# Ignore application configuration
/config/application.yml
@@ -64,11 +63,6 @@ package-lock.json
# Development Docker storage location
_docker-storage/
-# YARD generated doc (in the Gitdocs folder)
-docs/.static/ruby-doc/
-# ReDoc generated API doc (in the Gitdocs folder)
-docs/.static/api/
-
# AWS Cloud9 specific folder for user settings
.c9/
diff --git a/.rubocop.yml b/.rubocop.yml
index 723d0bad5..13f0a6962 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -100,7 +100,6 @@ Layout/LineLength:
Description: 'Checks that line length does not exceed the configured limit.'
AutoCorrect: true # this is false by default
Exclude:
- - docs/Gemfile
- Gemfile
- app/lib/constants/site_config.rb
diff --git a/.slugignore b/.slugignore
index 4cdf276df..572b978a4 100644
--- a/.slugignore
+++ b/.slugignore
@@ -7,7 +7,6 @@
.eslintignore
.eslintrc.js
.gitattributes
-.gitdocs.js
.github/
.gitpod.dockerfile
.gitpod.yml
@@ -40,7 +39,6 @@ cypress.dev.json
cypress.json
cypress/
docker-compose.yml
-docs/
empty-module.js
jest.config.js
postcss_error.log
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ccf326758..38b0669d9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,4 +19,4 @@ We are all humans trying to work together to improve the community. Always be
kind and appreciate the need for trade-offs. ❤️
Before making your first pull request or issue, give our full
-[Contributor's Guide](https://docs.forem.com/contributing/forem/) a read.
+[Contributor's Guide](https://developers.forem.com/contributing/forem/) a read.
diff --git a/README.md b/README.md
index 833141d2e..4b051cf60 100644
--- a/README.md
+++ b/README.md
@@ -94,14 +94,14 @@ proceed.
## Getting Started
This section provides a high-level quick start guide. If you're looking for the
-[installation guide](https://docs.forem.com/installation/), you'll want to refer
-to our complete [Developer Documentation](https://docs.forem.com/).
+[installation guide](https://developers.forem.com/installation/), you'll want to
+refer to our complete [Developer Documentation](https://developers.forem.com/).
We run on a [Rails](https://rubyonrails.org/) backend, and we are currently
transitioning to a [Preact](https://preactjs.com/)-first frontend.
A more complete overview of our stack is available in
-[our docs](https://docs.forem.com/technical-overview/).
+[our docs](https://developers.forem.com/technical-overview/).
### Prerequisites
@@ -130,11 +130,11 @@ A more complete overview of our stack is available in
### Installation Documentation
-[View Full Installation Documentation](https://docs.forem.com/installation/).
+[View Full Installation Documentation](https://developers.forem.com/installation/).
## Developer Documentation
-[Check out our dedicated docs page for more technical documentation](https://docs.forem.com).
+[Check out our dedicated docs page for more technical documentation](https://developers.forem.com).
## Core team
@@ -192,7 +192,7 @@ Agreement, which they generously made available to the public domain under
Creative Commons CC0 1.0 Universal.
Any questions, please refer to our
-[license FAQ](https://docs.forem.com/licensing/) doc or email yo@dev.to.
+[license FAQ](https://developers.forem.com/licensing/) doc or email yo@dev.to.
diff --git a/app/controllers/concerns/edge_cache_safety_check.rb b/app/controllers/concerns/edge_cache_safety_check.rb
index 59d301f10..938ec0601 100644
--- a/app/controllers/concerns/edge_cache_safety_check.rb
+++ b/app/controllers/concerns/edge_cache_safety_check.rb
@@ -8,7 +8,7 @@ module EdgeCacheSafetyCheck
def current_user
# In production, current_user will cause a cache leak if it's placed within an edge-cached code path.
# More information here:
- # https://docs.forem.com/technical-overview/architecture/#we-cache-many-content-pages-on-the-edge
+ # https://developers.forem.com/technical-overview/architecture/#we-cache-many-content-pages-on-the-edge
return super unless RequestStore.store[:edge_caching_in_place]
return if session_current_user_id.blank?
diff --git a/app/javascript/crayons/guidelines/__stories__/Components.stories.mdx b/app/javascript/crayons/guidelines/__stories__/Components.stories.mdx
index 55dbbf5e5..452046dea 100644
--- a/app/javascript/crayons/guidelines/__stories__/Components.stories.mdx
+++ b/app/javascript/crayons/guidelines/__stories__/Components.stories.mdx
@@ -8,7 +8,7 @@ import { Meta } from '@storybook/addon-docs/blocks';
Forem is a Rails application. Most of what we build for views uses ERB templates
(\*.html.erb files). We also build out parts of or sometimes complete views
-using [Preact](https://docs.forem.com/frontend/preact), typically for the logged
+using [Preact](https://developers.forem.com/frontend/preact), typically for the logged
on user experience. For example, the main page feed.
Because of that, we components that are written in pure HTML & CSS as well as
diff --git a/app/views/users/_account.html.erb b/app/views/users/_account.html.erb
index 48c345928..024659cce 100644
--- a/app/views/users/_account.html.erb
+++ b/app/views/users/_account.html.erb
@@ -7,7 +7,7 @@
<%= community_name %> API Keys
-
You can generate personal API keys to use for authentication with the <%= community_name %> API. The API is still in its beta stage. The documentation contains further information.
+
You can generate personal API keys to use for authentication with the <%= community_name %> API. The API is still in its beta stage. The documentation contains further information.
diff --git a/config/routes.rb b/config/routes.rb
index 93382967b..8389f02a4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -296,7 +296,7 @@ Rails.application.routes.draw do
# You can have the root of your site routed with "root
get "/robots.:format", to: "pages#robots"
- get "/api", to: redirect("https://docs.forem.com/api")
+ get "/api", to: redirect("https://developers.forem.com/api")
get "/privacy", to: "pages#privacy"
get "/terms", to: "pages#terms"
get "/contact", to: "pages#contact"
diff --git a/docs/.gitdocs.json b/docs/.gitdocs.json
deleted file mode 100644
index 8ced4bda1..000000000
--- a/docs/.gitdocs.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "Forem Docs",
- "root": "./",
- "logo": "seedling.png",
- "host": "0.0.0.0",
- "header_links": [
- {
- "title": "Repo",
- "href": "https://github.com/forem/forem",
- "target": "_blank",
- "rel": "noopener noreferrer nofollow"
- },
- {
- "title": "DEV",
- "href": "https://dev.to",
- "target": "_blank",
- "rel": "noopener noreferrer nofollow"
- },
- {
- "title": "Ruby doc",
- "href": "https://docs.forem.com/ruby-doc",
- "target": "_blank",
- "rel": "noopener noreferrer nofollow"
- },
- {
- "title": "API doc",
- "href": "https://docs.forem.com/api",
- "target": "_blank",
- "rel": "noopener noreferrer nofollow"
- }
- ]
-}
diff --git a/docs/.nvmrc b/docs/.nvmrc
deleted file mode 100644
index e1fcd1ea2..000000000
--- a/docs/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-lts/erbium
diff --git a/docs/.ruby-version b/docs/.ruby-version
deleted file mode 100644
index 37c2961c2..000000000
--- a/docs/.ruby-version
+++ /dev/null
@@ -1 +0,0 @@
-2.7.2
diff --git a/docs/.static/admin_feature_flags.png b/docs/.static/admin_feature_flags.png
deleted file mode 100644
index a4071b3a6..000000000
Binary files a/docs/.static/admin_feature_flags.png and /dev/null differ
diff --git a/docs/.static/cypress-test-runner.png b/docs/.static/cypress-test-runner.png
deleted file mode 100644
index 4788b1526..000000000
Binary files a/docs/.static/cypress-test-runner.png and /dev/null differ
diff --git a/docs/.static/devblacksquarelogo.svg b/docs/.static/devblacksquarelogo.svg
deleted file mode 100644
index 57f853e7b..000000000
--- a/docs/.static/devblacksquarelogo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/.static/favicon.ico b/docs/.static/favicon.ico
deleted file mode 100644
index 6f22222c0..000000000
Binary files a/docs/.static/favicon.ico and /dev/null differ
diff --git a/docs/.static/jest-watch-mode-screenshot.png b/docs/.static/jest-watch-mode-screenshot.png
deleted file mode 100644
index 0c3d57e26..000000000
Binary files a/docs/.static/jest-watch-mode-screenshot.png and /dev/null differ
diff --git a/docs/.static/seedling.png b/docs/.static/seedling.png
deleted file mode 100644
index aa93c9ce2..000000000
Binary files a/docs/.static/seedling.png and /dev/null differ
diff --git a/docs/.static/vscode_launch_debugger.png b/docs/.static/vscode_launch_debugger.png
deleted file mode 100644
index 0b0bbf12f..000000000
Binary files a/docs/.static/vscode_launch_debugger.png and /dev/null differ
diff --git a/docs/.static/wsl-feature.png b/docs/.static/wsl-feature.png
deleted file mode 100644
index 5cf46d750..000000000
Binary files a/docs/.static/wsl-feature.png and /dev/null differ
diff --git a/docs/Gemfile b/docs/Gemfile
deleted file mode 100644
index 06a342089..000000000
--- a/docs/Gemfile
+++ /dev/null
@@ -1,11 +0,0 @@
-ruby_version = File.read(
- File.join(File.dirname(File.dirname(__FILE__)), ".ruby-version"),
-).strip
-
-source "https://rubygems.org"
-ruby ruby_version
-
-gem "activerecord", "~> 5.2.3" # Databases on Rails
-gem "yard", "~> 0.9.19" # YARD is a documentation generation tool for the Ruby programming language
-gem "yard-activerecord", "~> 0.0.16" # YARD extension that handles and interprets methods used when developing applications with ActiveRecord
-gem "yard-activesupport-concern", "~> 0.0.1" # YARD extension that brings support for modules making use of ActiveSupport::Concern
diff --git a/docs/Makefile b/docs/Makefile
deleted file mode 100644
index 48a325998..000000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-.PHONY: build
-
-build: api-doc ruby-doc gitdocs
-
-api-doc:
- # docs/.static/api will let gitdocs serve the API doc as static content
- cd .. && \
- npm install -g redoc-cli@latest && \
- redoc-cli bundle docs/api_v0.yml --options.suppressWarnings --options.pathInMiddlePanel --options.jsonSampleExpandLevel=all --options.menuToggle -t docs/api_template.hbs && \
- mkdir -p docs/.static/api/ && \
- mv redoc-static.html docs/.static/api/index.html
-
-ruby-doc:
- # docs/.static/ruby-doc will let gitdocs serve the Ruby doc as static content
- cd .. && yard doc -o docs/.static/ruby-doc
-
-gitdocs:
- npm install -g gitdocs@latest && gitdocs build
diff --git a/docs/admin/admin-search.md b/docs/admin/admin-search.md
deleted file mode 100644
index a9aa6048d..000000000
--- a/docs/admin/admin-search.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Admin Search
----
-
-# Admin Search
-
-For admin views that need to take advantage of searching and filtering, we've
-chosen to use [Ransack][ransack].
-
-Ransack is a Ruby gem that makes searching relatively painless. It has excellent
-documentation, but if you're looking for an example of how it's being used on
-Forem, we've implemented it to help searching and sorting user reports.
-
-The view responsible for managing user reports can be found at
-`/admin/moderation/reports` and Ransack can be seen in use on the
-index action of the [`admin/feedback_messages_controller`][feedback_messages].
-
-For Forem, Ransack is being used exclusively in admin, for search problems in
-other parts of the app we use [PostgreSQL Full Text Search][postgres_fts].
-
-[feedback_messages]:
- https://github.com/forem/forem/blob/4e41e4a2ac893fa2a6c36990cfe475858ffb086a/app/controllers/admin/feedback_messages_controller.rb#L4
-[ransack]: https://github.com/activerecord-hackery/ransack
-[postgres_fts]: https://www.postgresql.org/docs/11/textsearch.html
diff --git a/docs/admin/admin-user-interface.md b/docs/admin/admin-user-interface.md
deleted file mode 100644
index 4288587f2..000000000
--- a/docs/admin/admin-user-interface.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: Admin User Interface
----
-
-# User Interface
-
-Our admin dashboard is primarily ERB views that render on the server. Largely,
-we try to adhere to
-[ActionView](https://guides.rubyonrails.org/action_view_overview.html)'s
-conventions in these views.
-
-For layout, basic styles, and some interactions, we use
-[Bootstrap 4](https://getbootstrap.com/). Forem isn't dedicated to using
-Bootstrap for everything, but because our design team hasn't spent much time on
-these views, we find it's easier to stick with something many developers already
-know.
-
-When a view requires some custom interactivity, we've historically leaned on
-vanilla JavaScript or jQuery, but going forward we've elected to use
-[StimulusJS](https://stimulusjs.org/) for DOM manipulation and interactivity
-inside of admin.
-
-# Forms
-
-Inside of the admin views, we're
-[actively moving from the old ERB syntax for forms](https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a).
-We tend to prefer the `form_with` helper over the previous `form_for` and
-`form_tag` helpers.
-
-# StimulusJS
-
-Stimulus is a modest frontend framework; its primary purpose is manipulating
-HTML. It does not provide templating features.
-
-In the Forem application, [Webpacker](/frontend/webpacker/) is used to load
-Stimulus controllers via the `app/javascript/packs/admin.js`
-[pack file](https://github.com/rails/webpacker/blob/main/docs/folder-structure.md#packs-aka-webpack-entries).
-Ideally, controllers serve as an abstraction for shared functionality between
-views.
-
-New controllers can be added in `/app/javascript/admin/controllers`. Unit tests
-should exist for each controller in the adjacent
-`/app/javascript/admin/__tests__/contollers` directory.
diff --git a/docs/admin/readme.md b/docs/admin/readme.md
deleted file mode 100644
index ab551df0a..000000000
--- a/docs/admin/readme.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Admin Guide
-items:
- - admin-search.md
- - internal-user-interface.md
----
-
-# Admin Guide
-
-The Forem application contains a rudimentary administration dashboard that lives
-behind the admin route.
-
-The admin dashboard is made up of a series of views that range from
-administration tools to simplified reports. These tools are used by users with
-the `admin` or `super_admin` roles to administrate the Forem application.
-
-Authorization for these tools is handled by the [Rolify][rolify] gem.
-
-Currently, a workaround exists to give access to certain `admin` views via
-Rolify by assigning the role `single_resource_admin` to a user.
-
-`single_resource_admin` users are given access to a Ruby class. In the codebase,
-there are admin models, not backed by database tables, that exist for this
-purpose. For example, if you needed to give a user access to only
-`/admin/apps/welcome`, you'd run the following command in the Rails console:
-
-```ruby
-user = User.find(some_user_id)
-user.add_role(:single_resource_admin, Welcome)
-```
-
-This gives the user administration privileges on the controller associated with
-an almost empty Rails model that lives in `app/models/admin/welcome.rb`:
-
-```ruby
-class Welcome < ApplicationRecord
- resourcify
- # This class exists to take advantage of Rolify for limiting authorization
- # on admin reports.
- # NOTE: It is not backed by a database table and should not be expected to
- # function like a traditional Rails model
-end
-```
-
-Now that user will be able to access the view at `admin/welcome`. The same
-workaround has been implemented for most of the admin views.
-
-[rolify]: https://github.com/RolifyCommunity/rolify
diff --git a/docs/api_template.hbs b/docs/api_template.hbs
deleted file mode 100644
index c9ddaa4e7..000000000
--- a/docs/api_template.hbs
+++ /dev/null
@@ -1,33 +0,0 @@
-{{! This template is used by ReDoc to render the final API doc }}
-{{! It is written in HandlerbarsJS syntax }}
-{{! Please refer to https://github.com/Redocly/redoc/blob/master/cli/README.md }}
-{{! and https://github.com/Redocly/redoc/blob/master/cli/template.hbs }}
-
-
-
-
-
- DEV API (beta)
-
-
-
-
-
-
- {{! needed for adaptive design }}
-
-
- {{{redocHead}}}
-
-
-
-
- {{{redocHTML}}}
-
-
-
diff --git a/docs/api_v0.yml b/docs/api_v0.yml
deleted file mode 100644
index 6d84a7627..000000000
--- a/docs/api_v0.yml
+++ /dev/null
@@ -1,3782 +0,0 @@
-# This document follows the OpenAPI spec
-# It contains two Redoc vendor extensions, x-codeSamples and x-logo
-# x-logo: https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-logo
-# x-codeSamples: https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-codesamples
-
-openapi: "3.0.3"
-info:
- title: DEV API (beta)
- description: |
-
- Access Forem articles, users and other resources via API.
-
- For a real-world example of Forem in action, check out [DEV](https://www.dev.to).
-
- All endpoints that don't require authentication are CORS enabled.
-
- Dates and date times, unless otherwise specified, must be in
- the [RFC 3339](https://tools.ietf.org/html/rfc3339) format.
-
- version: "0.9.7"
- termsOfService: https://dev.to/terms
- contact:
- name: DEV Team
- url: https://dev.to/contact
- email: yo@dev.to
- x-logo:
- url: https://res.cloudinary.com/practicaldev/image/fetch/s--EYllUmBG--/c_limit,f_auto,fl_progressive,q_80,w_190/https://res.cloudinary.com/practicaldev/image/fetch/s--m5i3pkpk--/c_limit%252cf_auto%252cfl_progressive%252cq_auto%252cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sf6uve8ehm4ogwka0mez.png
- backgroundColor: ""
- altText: "Forem logo"
-
-servers:
- - url: https://dev.to/api
- description: Production server
-
-components:
- parameters:
- pageParam:
- in: query
- name: page
- required: false
- description: Pagination page.
- schema:
- type: integer
- format: int32
- minimum: 1
- default: 1
- perPageParam10to1000:
- in: query
- name: per_page
- required: false
- description: Page size (the number of items to return per page).
- schema:
- type: integer
- format: int32
- minimum: 1
- maximum: 1000
- default: 10
- perPageParam24to1000:
- in: query
- name: per_page
- required: false
- description: Page size (the number of items to return per page).
- schema:
- type: integer
- format: int32
- minimum: 1
- maximum: 1000
- default: 24
- perPageParam30to1000:
- in: query
- name: per_page
- required: false
- description: Page size (the number of items to return per page).
- schema:
- type: integer
- format: int32
- minimum: 1
- maximum: 1000
- default: 30
- perPageParam30to100:
- in: query
- name: per_page
- required: false
- description: Page size (the number of items to return per page).
- schema:
- type: integer
- format: int32
- minimum: 1
- maximum: 100
- default: 30
- perPageParam80to1000:
- in: query
- name: per_page
- required: false
- description: Page size (the number of items to return per page).
- schema:
- type: integer
- format: int32
- minimum: 1
- maximum: 1000
- default: 80
- listingCategoryParam:
- name: category
- in: query
- description: |
- Using this parameter will return listings belonging to the
- requested category.
- schema:
- type: string
- example: cfp
-
- securitySchemes:
- api_key:
- type: apiKey
- description: |
- API Key authentication.
-
- Authentication for some endpoints, like write operations on the
- Articles API require a DEV API key.
-
- ### Getting an API key
-
- To obtain one, please follow these steps:
-
- - visit https://dev.to/settings/account
- - in the "DEV API Keys" section create a new key by adding a
- description and clicking on "Generate API Key"
-
- 
- - You'll see the newly generated key in the same view
- 
- name: api-key
- in: header
- oauth2:
- type: oauth2
- description: |
- OAuth2 authentication.
-
- OAuth2 authentication is still in private alpha.
- flows:
- authorizationCode:
- authorizationUrl: https://dev.to/oauth/authorize
- tokenUrl: https://dev.to/oauth/token
- refreshUrl: https://dev.to/oauth/token
- scopes: {}
- clientCredentials:
- tokenUrl: https://dev.to/oauth/token
- refreshUrl: https://dev.to/oauth/token
- scopes: {}
-
- schemas:
- APIError:
- type: object
- required:
- - error
- - status
- properties:
- error:
- type: string
- status:
- type: integer
- format: int32
- ArticleIndex:
- type: object
- required:
- - type_of
- - id
- - title
- - description
- - cover_image
- - readable_publish_date
- - social_image
- - tag_list
- - tags
- - slug
- - path
- - url
- - canonical_url
- - comments_count
- - positive_reactions_count
- - public_reactions_count
- - created_at
- - edited_at
- - crossposted_at
- - published_at
- - last_comment_at
- - published_timestamp
- - user
- - reading_time_minutes
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- title:
- type: string
- description:
- type: string
- cover_image:
- type: string
- format: url
- nullable: true
- readable_publish_date:
- type: string
- social_image:
- type: string
- format: url
- tag_list:
- type: array
- items:
- type: string
- tags:
- type: string
- slug:
- type: string
- path:
- type: string
- format: path
- url:
- type: string
- format: url
- canonical_url:
- type: string
- format: url
- comments_count:
- type: integer
- format: int32
- positive_reactions_count:
- type: integer
- format: int32
- public_reactions_count:
- type: integer
- format: int32
- created_at:
- type: string
- format: date-time
- edited_at:
- type: string
- format: date-time
- nullable: true
- crossposted_at:
- type: string
- format: date-time
- nullable: true
- published_at:
- type: string
- format: date-time
- last_comment_at:
- type: string
- format: date-time
- published_timestamp:
- description: Crossposting or published date time
- type: string
- format: date-time
- user:
- $ref: "#/components/schemas/SharedUser"
- reading_time_minutes:
- description: Reading time, in minutes
- type: integer
- format: int32
- organization:
- $ref: "#/components/schemas/SharedOrganization"
- flare_tag:
- $ref: "#/components/schemas/ArticleFlareTag"
-
- ArticleShow:
- type: object
- required:
- - type_of
- - id
- - title
- - description
- - cover_image
- - readable_publish_date
- - social_image
- - tag_list
- - tags
- - slug
- - path
- - url
- - canonical_url
- - comments_count
- - positive_reactions_count
- - public_reactions_count
- - created_at
- - edited_at
- - crossposted_at
- - published_at
- - last_comment_at
- - published_timestamp
- - body_html
- - body_markdown
- - user
- - reading_time_minutes
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- title:
- type: string
- description:
- type: string
- cover_image:
- type: string
- format: url
- nullable: true
- readable_publish_date:
- type: string
- social_image:
- type: string
- format: url
- tag_list:
- type: string
- tags:
- type: array
- items:
- type: string
- slug:
- type: string
- path:
- type: string
- format: path
- url:
- type: string
- format: url
- canonical_url:
- type: string
- format: url
- comments_count:
- type: integer
- format: int32
- positive_reactions_count:
- type: integer
- format: int32
- public_reactions_count:
- type: integer
- format: int32
- created_at:
- type: string
- format: date-time
- edited_at:
- type: string
- format: date-time
- nullable: true
- crossposted_at:
- type: string
- format: date-time
- nullable: true
- published_at:
- type: string
- format: date-time
- last_comment_at:
- type: string
- format: date-time
- published_timestamp:
- description: Crossposting or published date time
- type: string
- format: date-time
- body_html:
- type: string
- body_markdown:
- type: string
- user:
- $ref: "#/components/schemas/SharedUser"
- reading_time_minutes:
- description: Reading time, in minutes
- type: integer
- format: int32
- organization:
- $ref: "#/components/schemas/SharedOrganization"
- flare_tag:
- $ref: "#/components/schemas/ArticleFlareTag"
-
- ArticleCreate:
- type: object
- properties:
- article:
- type: object
- properties:
- title:
- type: string
- body_markdown:
- description: |
- The body of the article.
-
- It can contain an optional front matter. For example
-
- ```markdown
- ---
- title: Hello, World!
- published: true
- tags: discuss, help
- date: 20190701T10:00Z
- series: Hello series
- canonical_url: https://example.com/blog/hello
- cover_image: article_published_cover_image
- ---
- ```
-
- `date`, `series` and `canonical_url` are optional.
- `date` is the publication date-time
- `series` is the name of the series the article belongs to
- `canonical_url` is the canonical URL of the article
- `cover_image` is the main image of the article
-
- *If the markdown contains a front matter, it will take precedence
- on the equivalent params given in the payload.*
- type: string
- published:
- description: |
- True to create a published article, false otherwise. Defaults to false
- type: boolean
- series:
- description: |
- Article series name.
-
- All articles belonging to the same series need to have the same name
- in this parameter.
- type: string
- main_image:
- type: string
- format: url
- canonical_url:
- type: string
- format: url
- description:
- type: string
- tags:
- type: array
- items:
- type: string
- organization_id:
- description: |
- Only users belonging to an organization can assign the article to it
- type: integer
- format: int32
-
- ArticleUpdate:
- type: object
- properties:
- article:
- type: object
- properties:
- title:
- type: string
- body_markdown:
- description: |
- The body of the article.
-
- It can contain an optional front matter. For example
-
- ```markdown
- ---
- title: Hello, World!
- published: true
- tags: discuss, help
- date: 20190701T10:00Z
- series: Hello series
- canonical_url: https://example.com/blog/hello
- cover_image: article_published_cover_image
- ---
- ```
-
- `date`, `series` and `canonical_url` are optional.
- `date` is the publication date-time
- `series` is the name of the series the article belongs to
- `canonical_url` is the canonical URL of the article
- `cover_image` is the main image of the article
-
- *If the markdown contains a front matter, it will take precedence
- on the equivalent params given in the payload.*
- type: string
- published:
- description: |
- True to create a published article, false otherwise. Defaults to false
- type: boolean
- series:
- description: |
- Article series name.
-
- All articles belonging to the same series need to have the same name
- in this parameter.
-
- To remove an article from a series, the `null` value can be used.
- type: string
- main_image:
- type: string
- format: url
- canonical_url:
- type: string
- format: url
- description:
- type: string
- tags:
- type: array
- items:
- type: string
- organization_id:
- description: |
- Only users belonging to an organization can assign the article to it
- type: integer
- format: int32
-
- ArticleMe:
- type: object
- required:
- - type_of
- - id
- - title
- - description
- - cover_image
- - published
- - published_at
- - tag_list
- - slug
- - path
- - url
- - canonical_url
- - comments_count
- - positive_reactions_count
- - public_reactions_count
- - page_views_count
- - published_timestamp
- - body_markdown
- - user
- - reading_time_minutes
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- title:
- type: string
- description:
- type: string
- cover_image:
- type: string
- format: url
- nullable: true
- published:
- type: boolean
- published_at:
- type: string
- format: date-time
- tag_list:
- type: array
- items:
- type: string
- slug:
- type: string
- path:
- type: string
- format: path
- url:
- type: string
- format: url
- canonical_url:
- type: string
- format: url
- comments_count:
- type: integer
- format: int32
- positive_reactions_count:
- type: integer
- format: int32
- public_reactions_count:
- type: integer
- format: int32
- page_views_count:
- type: integer
- format: int32
- published_timestamp:
- description: Crossposting or published date time
- type: string
- format: date-time
- body_markdown:
- description: The body of the article in Markdown format
- type: string
- user:
- $ref: "#/components/schemas/SharedUser"
- reading_time_minutes:
- description: Reading time, in minutes
- type: integer
- format: int32
- organization:
- $ref: "#/components/schemas/SharedOrganization"
- flare_tag:
- $ref: "#/components/schemas/ArticleFlareTag"
-
- ArticleFlareTag:
- description: Flare tag of the article
- type: object
- properties:
- name:
- type: string
- bg_color_hex:
- description: Background color (hexadecimal)
- type: string
- text_color_hex:
- description: Text color (hexadecimal)
- type: string
-
- ArticleVideo:
- type: object
- required:
- - type_of
- - id
- - path
- - cloudinary_video_url
- - title
- - user_id
- - video_duration_in_minutes
- - video_source_url
- - user
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- path:
- type: string
- cloudinary_video_url:
- description: The preview image of the video
- type: string
- format: url
- title:
- type: string
- user_id:
- type: integer
- format: int32
- video_duration_in_minutes:
- description: |
- The duration of the video.
-
- If the video duration is below 1 hour, the format will be `mm:ss`,
- if it's 1 hour or above the format will be `h:mm:ss`.
- type: string
- video_source_url:
- format: url
- type: string
- user:
- type: object
- properties:
- name:
- description: The user's name
- type: string
-
- Comment:
- type: object
- required:
- - type_of
- - id_code
- - created_at
- - body_html
- - user
- - children
- properties:
- type_of:
- type: string
- id_code:
- type: string
- created_at:
- type: string
- format: date-time
- body_html:
- description: HTML formatted comment
- type: string
- user:
- $ref: "#/components/schemas/SharedUser"
- children:
- type: array
- items:
- $ref: "#/components/schemas/Comment"
- FollowedTag:
- type: object
- required:
- - id
- - name
- - points
- properties:
- id:
- description: Tag id
- type: integer
- format: int64
- name:
- type: string
- points:
- type: number
- format: float
-
- Follower:
- type: object
- required:
- - type_of
- - created_at
- - id
- - name
- - path
- - username
- - profile_image
- properties:
- type_of:
- type: string
- created_at:
- description: Date the user became a follower
- type: string
- format: date-time
- id:
- description: Follow id
- type: integer
- format: int32
- name:
- type: string
- path:
- type: string
- username:
- type: string
- profile_image:
- description: Profile image (60x60)
- type: string
- format: url
-
- Listing:
- type: object
- required:
- - type_of
- - id
- - title
- - slug
- - body_markdown
- - tag_list
- - tags
- - category
- - processed_html
- - published
- - user
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int64
- title:
- type: string
- slug:
- type: string
- body_markdown:
- type: string
- tag_list:
- type: string
- tags:
- type: array
- items:
- type: string
- category:
- $ref: "#/components/schemas/ListingCategory"
- processed_html:
- type: string
- published:
- type: boolean
- user:
- $ref: "#/components/schemas/SharedUser"
- organization:
- $ref: "#/components/schemas/SharedOrganization"
-
- ListingCategory:
- type: string
- enum: [cfp, forhire, collabs, education, jobs, mentors, products, mentees, forsale, events, misc]
-
- ListingCreate:
- type: object
- properties:
- listing:
- type: object
- required:
- - title
- - body_markdown
- - category
- properties:
- title:
- type: string
- body_markdown:
- description: The body of the listing in Markdown format.
- type: string
- category:
- $ref: "#/components/schemas/ListingCategory"
- tags:
- description: |
- Tags related to the listing.
-
- A maximum of 8 tags are allowed and it takes precedence over `tag_list`.
- type: array
- items:
- type: string
- tag_list:
- description: |
- Comma separated list of tags.
-
- A maximum of 8 tags are allowed.
- type: string
- expires_at:
- description: Date and time of expiration.
- type: string
- format: date-time
- contact_via_connect:
- description: |
- True if users are allowed to contact the listing's owner
- via DEV connect, false otherwise.
-
- Defaults to false.
- type: boolean
- location:
- description: Geographical area or city for the listing.
- type: string
- organization_id:
- description: |
- The id of the organization the user is creating the listing for.
-
- Only users belonging to an organization can assign the listing to it.
- type: integer
- format: int64
- action:
- description: Set it to "draft" to create an unpublished listing
- type: string
- enum: [draft]
-
- ListingUpdate:
- type: object
- properties:
- listing:
- type: object
- properties:
- title:
- type: string
- body_markdown:
- description: The body of the listing in Markdown format.
- type: string
- category:
- $ref: "#/components/schemas/ListingCategory"
- tags:
- description: |
- Tags related to the listing.
-
- A maximum of 8 tags are allowed and it takes precedence over `tag_list`.
- type: array
- items:
- type: string
- tag_list:
- description: |
- Comma separated list of tags.
-
- A maximum of 8 tags are allowed.
- type: string
- expires_at:
- description: Date and time of expiration.
- type: string
- format: date-time
- contact_via_connect:
- description: |
- True if users are allowed to contact the listing's owner
- via DEV connect, false otherwise.
-
- Defaults to false.
- type: boolean
- location:
- description: Geographical area or city for the listing.
- type: string
- action:
- description: |
- This param can be provided by itself to invoke some actions:
-
- - `bump` bumps the listing and charge either the
- organization or the user
- - `publish` publishes a draft listing
- - `unpublish` unpublishes a published listing
-
- It will take priority on any other param in the payload.
- type: string
- enum: [bump, publish, unpublish]
-
- ReadingList:
- type: object
- required:
- - type_of
- - id
- - status
- - created_at
- - article
- properties:
- type_of:
- type: string
- id:
- description: Follow id
- type: integer
- format: int32
- status:
- type: string
- enum:
- - valid
- - invalid
- - confirmed
- - archived
- created_at:
- type: string
- format: date-time
- article:
- $ref: "#/components/schemas/ArticleIndex"
-
- PodcastEpisode:
- type: object
- required:
- - type_of
- - id
- - path
- - image_url
- - title
- - podcast
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- path:
- type: string
- image_url:
- type: string
- format: url
- title:
- type: string
- podcast:
- type: object
- properties:
- title:
- type: string
- slug:
- type: string
- image_url:
- type: string
- format: url
-
- SharedUser:
- description: The resource creator
- type: object
- properties:
- name:
- type: string
- username:
- type: string
- twitter_username:
- type: string
- nullable: true
- github_username:
- type: string
- nullable: true
- website_url:
- type: string
- format: url
- nullable: true
- profile_image:
- description: Profile image (640x640)
- type: string
- profile_image_90:
- description: Profile image (90x90)
- type: string
-
- SharedOrganization:
- description: The organization the resource belongs to
- type: object
- properties:
- name:
- type: string
- username:
- type: string
- slug:
- type: string
- profile_image:
- description: Profile image (640x640)
- type: string
- format: url
- profile_image_90:
- description: Profile image (90x90)
- type: string
- format: url
-
- Tag:
- type: object
- required:
- - id
- - name
- - bg_color_hex
- - text_color_hex
- properties:
- id:
- type: integer
- format: int32
- name:
- type: string
- bg_color_hex:
- description: Background color (hexadecimal)
- type: string
- text_color_hex:
- description: Text color (hexadecimal)
- type: string
-
- User:
- type: object
- required:
- - type_of
- - id
- - username
- - name
- - summary
- - twitter_username
- - github_username
- - website_url
- - location
- - joined_at
- - profile_image
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int32
- username:
- type: string
- name:
- type: string
- summary:
- type: string
- nullable: true
- twitter_username:
- type: string
- nullable: true
- github_username:
- type: string
- nullable: true
- website_url:
- type: string
- format: url
- nullable: true
- location:
- type: string
- nullable: true
- joined_at:
- description: Date of joining (formatted with strftime `"%b %e, %Y"`)
- type: string
- profile_image:
- description: Profile image (320x320)
- type: string
- format: url
-
- WebhookCreate:
- description: Webhook creation payload
- type: object
- properties:
- webhook_endpoint:
- type: object
- required:
- - source
- - target_url
- - events
- properties:
- source:
- description: The name of the requester, eg. "DEV"
- type: string
- target_url:
- type: string
- format: url
- events:
- description: An array of events identifiers
- type: array
- items:
- type: string
- enum:
- - article_created
- - article_updated
- - article_destroyed
-
- WebhookIndex:
- description: Webhook
- type: object
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int64
- source:
- description: The name of the requester, eg. "DEV"
- type: string
- target_url:
- type: string
- format: url
- events:
- description: An array of events identifiers
- type: array
- items:
- type: string
- created_at:
- type: string
- format: date-time
-
- WebhookShow:
- description: Webhook
- type: object
- properties:
- type_of:
- type: string
- id:
- type: integer
- format: int64
- source:
- description: The name of the requester, eg. "DEV"
- type: string
- target_url:
- type: string
- format: url
- events:
- description: An array of events identifiers
- type: array
- items:
- type: string
- created_at:
- type: string
- format: date-time
- user:
- $ref: "#/components/schemas/SharedUser"
-
- ProfileImage:
- description: Profile image
- type: object
- properties:
- type_of:
- type: string
- enum: [profile_image]
- image_of:
- description: "Discriminates what is the type of the profile image owner (user or organization)"
- type: string
- enum: [user, organization]
- profile_image:
- type: string
- description: Profile image (640x640)
- profile_image_90:
- type: string
- description: Profile image (90x90)
-
- Organization:
- description: Organization
- type: object
- properties:
- type_of:
- type: string
- username:
- type: string
- name:
- type: string
- summary:
- type: string
- nullable: true
- twitter_username:
- type: string
- nullable: true
- github_username:
- type: string
- nullable: true
- url:
- type: string
- format: url
- location:
- type: string
- nullable: true
- tech_stack:
- type: string
- nullable: true
- tag_line:
- type: string
- nullable: true
- story:
- type: string
- nullable: true
- joined_at:
- description: Date of joining
- type: string
- format: date-time
- profile_image:
- type: string
- description: Profile image (640x640)
- format: url
-
- examples:
- ErrorBadRequest:
- value:
- error: bad request
- status: 400
- ErrorNotFound:
- value:
- error: not found
- status: 404
- ErrorUnauthorized:
- value:
- error: unauthorized
- status: 401
- ErrorPaymentRequired:
- value:
- error: not enough available credits
- status: 402
- ErrorForbidden:
- value:
- error: forbidden
- status: 403
- ErrorUnprocessableEntity:
- value:
- error: "param is missing or the value is empty: article"
- status: 422
- ErrorTooManyRequests:
- value:
- error: "Rate limit reached, try again in 30 seconds"
- status: 429
-
- ArticlesIndex:
- value:
- - type_of: article
- id: 194541
- title: There's a new DEV theme in town for all you 10x hackers out there (plus one
- actually useful new feature)
- description: ''
- cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--74Bl23tz--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://res.cloudinary.com/practicaldev/image/fetch/s--xU8cbIK4--/c_imagga_scale%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_1000/https://thepracticaldev.s3.amazonaws.com/i/8a39dzf3oovzc2snl7iv.png
- readable_publish_date: Oct 24
- social_image: https://res.cloudinary.com/practicaldev/image/fetch/s--SeMxdKIa--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://res.cloudinary.com/practicaldev/image/fetch/s--xU8cbIK4--/c_imagga_scale%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_1000/https://thepracticaldev.s3.amazonaws.com/i/8a39dzf3oovzc2snl7iv.png
- tag_list:
- - meta
- - changelog
- - css
- - ux
- tags: meta, changelog, css, ux
- slug: there-s-a-new-dev-theme-in-town-for-all-you-10x-hackers-out-there-plus-one-actually-useful-new-feature-2kgk
- path: "/devteam/there-s-a-new-dev-theme-in-town-for-all-you-10x-hackers-out-there-plus-one-actually-useful-new-feature-2kgk"
- url: https://dev.to/devteam/there-s-a-new-dev-theme-in-town-for-all-you-10x-hackers-out-there-plus-one-actually-useful-new-feature-2kgk
- canonical_url: https://dev.to/devteam/there-s-a-new-dev-theme-in-town-for-all-you-10x-hackers-out-there-plus-one-actually-useful-new-feature-2kgk
- comments_count: 37
- positive_reactions_count: 12
- public_reactions_count: 142
- collection_id:
- created_at: '2019-10-24T13:41:29Z'
- edited_at: '2019-10-24T13:56:35Z'
- crossposted_at:
- published_at: '2019-10-24T13:52:17Z'
- last_comment_at: '2019-10-25T08:12:43Z'
- published_timestamp: '2019-10-24T13:52:17Z'
- reading_time_minutes: 15
- user:
- name: Ben Halpern
- username: ben
- twitter_username: bendhalpern
- github_username: benhalpern
- website_url: http://benhalpern.com
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--Y1sq1tFG--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/1/f451a206-11c8-4e3d-8936-143d0a7e65bb.png
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--DcW51A6v--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/1/f451a206-11c8-4e3d-8936-143d0a7e65bb.png
- organization:
- name: The DEV Team
- username: devteam
- slug: devteam
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--0kDBq1Ne--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/1/0213bbaa-d5a1-4d25-9e7a-10c30b455af0.png
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--8tTU-XkZ--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/1/0213bbaa-d5a1-4d25-9e7a-10c30b455af0.png
- ArticleShow:
- value:
- type_of: article
- id: 150589
- title: "Byte Sized Episode 2: The Creation of Graph Theory "
- description: The full story of Leonhard Euler and the creation of this fundamental
- computer science principle, delivered in a few minutes.
- cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--qgutBUrH--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png
- readable_publish_date: Aug 1
- social_image: https://res.cloudinary.com/practicaldev/image/fetch/s--6wSHHfwd--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png
- tag_list: computerscience, graphtheory, bytesized, history
- tags:
- - computerscience
- - graphtheory
- - bytesized
- - history
- slug: byte-sized-episode-2-the-creation-of-graph-theory-34g1
- path: "/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1"
- url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
- canonical_url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
- comments_count: 21
- positive_reactions_count: 122
- public_reactions_count: 322
- collection_id: 1693
- created_at: "2019-07-31T11:15:06Z"
- edited_at:
- crossposted_at:
- published_at: "2019-08-01T15:47:54Z"
- last_comment_at: "2019-08-06T16:48:10Z"
- published_timestamp: "2019-08-01T15:47:54Z"
- reading_time_minutes: 15
- body_html: |+
-
Today's episode of Byte Sized is about Leonhard Euler and the creation of Graph Theory.
-
-
For more about how Graph Theory works, check out this video from BaseCS!
...
- body_markdown: "---\r\ntitle: Byte Sized Episode 2: The Creation of Graph Theory \r\npublished:
- true\r\ndescription: The full story of Leonhard Euler and the creation of this fundamental
- computer science principle, delivered in a few minutes.\r\ntags: computerscience,
- graphtheory, bytesized, history\r\ncover_image: https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png\r\nseries:
- Byte Sized Season 1\r\n---\r\n\r\nToday's episode of Byte Sized is about Leonhard
- Euler and the creation of [Graph Theory](https://en.wikipedia.org/wiki/Graph_theory).\r\n\r\nFor
- more about how Graph Theory works, check out this video from BaseCS!..."
- user:
- name: Vaidehi Joshi
- username: vaidehijoshi
- twitter_username: vaidehijoshi
- github_username: vaidehijoshi
- website_url: http://www.vaidehi.com
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--eDGAYAoK--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--htZnqMn3--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
- organization:
- name: Byte Sized
- username: bytesized
- slug: bytesized
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--sq0DrZfn--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/865/652f7998-32a8-4fd9-85ca-dd697d2a9ee9.png
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--1Pt_ICL---/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/865/652f7998-32a8-4fd9-85ca-dd697d2a9ee9.png
- ArticleCreateTitleBody:
- value:
- article:
- title: Hello, World!
- published: true
- body_markdown: Hello DEV, this is my first post
- tags: ["discuss", "help"]
- series: Hello series
- ArticleCreateFrontMatter:
- value:
- article:
- body_markdown: |
- ---
- title: Hello, World!
- published: true
- tags: discuss, help
- date: 20190701T10:00Z
- series: Hello series
- ---
-
- Hello DEV, this is my first post
- ArticleCreateOrganization:
- value:
- article:
- title: Hello, World!
- published: true
- body_markdown: Hello DEV, this is my first post
- tags: ["discuss", "help"]
- series: Hello series
- organization_id: 1234
- ArticleVideo:
- value:
- - type_of: video_article
- id: 273532
- path: "/devteam/basecs-depth-first-search-implementing-4kkl"
- cloudinary_video_url: https://res.cloudinary.com/....png
- title: 'BaseCS: Depth First Search Implementing'
- user_id: 2882
- video_duration_in_minutes: '11:47'
- video_source_url: 'https://dw71fyauz7yz9.cloudfront.net/123/123.m3u8'
- user:
- name: Vaidehi Joshi
-
- Comments:
- value:
- - type_of: comment
- id_code: m3m0
- created_at: 2020-07-01T17:59:43Z
- body_html: |
-
-
-
-
-
- user:
- name: rhymes
- username: rhymes
- twitter_username:
- github_username:
- website_url:
- profile_image: https://res.cloudinary.com/...jpeg
- profile_image_90: https://res.cloudinary.com/...jpeg
- children: []
-
- Followers:
- value:
- - type_of: user_follower
- id: 12
- created_at: "2021-04-02T04:21:46Z"
- name: Mrs. Neda Morissette
- path: "/nedamrsmorissette"
- username: nedamrsmorissette
- profile_image: https://res.cloudinary.com/...
- - type_of: user_follower
- id: 11
- created_at: "2021-04-02T04:21:46Z"
- name: Yoko Hintz
- path: "/yokohintz"
- username: yokohintz
- profile_image: https://res.cloudinary.com/...
-
- Listings:
- value:
- - type_of: listing
- id: 1157
- created_at: "2021-04-07 08:29:42 UTC"
- title: TestBash Detroit
- slug: testbash-detroit-50gb
- body_markdown: "Do you want to learn about automation? Maybe you're interested in
- AI-driven testing? Security testing? We have a selection of talks, workshops and
- training courses to help you in a wide variety of areas in software testing. Join
- us for our very first trip to Detroit MI! \n\nhttps://bit.ly/TBDetroit"
- tag_list: events
- tags:
- - events
- category: cfp
- processed_html: |
-
Do you want to learn about automation? Maybe you're interested in AI-driven testing? Security testing? We have a selection of talks, workshops and training courses to help you in a wide variety of areas in software testing. Join us for our very first trip to Detroit MI!
- published: true
- user:
- name: Heather
- username: heatherr
- twitter_username:
- github_username: Heather-R
- website_url:
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--ggU5WPaT--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--CjladMBD--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- ListingsByOrganization:
- value:
- - type_of: listing
- id: 1157
- title: TestBash Detroit
- slug: testbash-detroit-50gb
- body_markdown: "Do you want to learn about automation? Maybe you're interested in
- AI-driven testing? Security testing? We have a selection of talks, workshops and
- training courses to help you in a wide variety of areas in software testing. Join
- us for our very first trip to Detroit MI! \n\nhttps://bit.ly/TBDetroit"
- tag_list: events
- tags:
- - events
- category: cfp
- processed_html: |
-
Do you want to learn about automation? Maybe you're interested in AI-driven testing? Security testing? We have a selection of talks, workshops and training courses to help you in a wide variety of areas in software testing. Join us for our very first trip to Detroit MI!
- published: true
- user:
- name: Heather
- username: heatherr
- twitter_username:
- github_username: Heather-R
- website_url:
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--ggU5WPaT--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--CjladMBD--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- organization:
- name: E Corp
- username: ecorp
- slug: ecorp
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--ggU5WPaT--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--CjladMBD--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- Listing:
- value:
- type_of: listing
- id: 1157
- title: TestBash Detroit
- slug: testbash-detroit-50gb
- body_markdown: "Do you want to learn about automation? Maybe you're interested in
- AI-driven testing? Security testing? We have a selection of talks, workshops and
- training courses to help you in a wide variety of areas in software testing. Join
- us for our very first trip to Detroit MI! \n\nhttps://bit.ly/TBDetroit"
- tag_list: events
- tags:
- - events
- category: cfp
- processed_html: |
-
Do you want to learn about automation? Maybe you're interested in AI-driven testing? Security testing? We have a selection of talks, workshops and training courses to help you in a wide variety of areas in software testing. Join us for our very first trip to Detroit MI!
- published: true
- user:
- name: Heather
- username: heatherr
- twitter_username:
- github_username: Heather-R
- website_url:
- profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--ggU5WPaT--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--CjladMBD--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136256/11cced64-afd2-4421-91e1-c5f7b216d49b.jpeg
- ListingCreate:
- value:
- listing:
- title: ACME Conference
- body_markdown: Awesome conference
- category: cfp
- tags:
- - events
- ListingCreateOrganization:
- value:
- listing:
- title: ACME Conference
- body_markdown: Awesome conference
- category: cfp
- tags:
- - events
- organization_id: 1
- ListingUpdate:
- value:
- listing:
- title: ACME New Conference
- body_markdown: Awesome new conference
- ListingUpdateActionBump:
- value:
- listing:
- action: bump
- ListingUpdateActionPublish:
- value:
- listing:
- action: publish
- ListingUpdateActionUnpublish:
- value:
- listing:
- action: unpublish
-
- PodcastEpisodes:
- value:
- - type_of: podcast_episodes
- id: 13894
- path: "/codenewbie/s11-e7-why-site-reliability-is-so-important-molly-struve"
- image_url: https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/2/9f50a462-9152-429a-b15e-d024baaa8e01.png
- title: S11:E7 - Why site reliability is so important (Molly Struve)
- podcast:
- title: CodeNewbie
- slug: codenewbie
- image_url: https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/2/9f50a462-9152-429a-b15e-d024baaa8e01.png
- - type_of: podcast_episodes
- id: 13829
- path: "/codenewbie/s11-e6-what-are-the-pros-and-cons-of-working-in-civic-tech-aidan-feldman"
- image_url: https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/2/9f50a462-9152-429a-b15e-d024baaa8e01.png
- title: S11:E6 - What are the pros and cons of working in civic tech (Aidan Feldman)
- podcast:
- title: CodeNewbie
- slug: codenewbie
- image_url: https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/2/9f50a462-9152-429a-b15e-d024baaa8e01.png
-
- Tags:
- value:
- - id: 6
- name: javascript
- bg_color_hex: "#F7DF1E"
- text_color_hex: "#000000"
- - id: 8
- name: webdev
- bg_color_hex: "#562765"
- text_color_hex: "#ffffff"
- TagsFollowed:
- value:
- - id: 13
- name: discuss
- points: 3
- - id: 12
- name: webdev
- points: 1
-
- User:
- value:
- type_of: user
- id: 1234
- username: bob
- name: bob
- summary: Hello, world
- twitter_username: bob
- github_username: bob
- website_url:
- location: New York
- joined_at: Jan 1, 2017
- profile_image: https://res.cloudinary.com/...jpeg
-
- Users:
- value:
- - type_of: user
- id: 1234
- username: bob
- name: bob
- summary: Hello, world
- twitter_username: bob
- github_username: bob
- website_url:
- location: New York
- joined_at: Jan 1, 2017
- profile_image: https://res.cloudinary.com/...jpeg
-
- WebhookCreate:
- value:
- webhook_endpoint:
- target_url: https://example.com/webhooks/webhook1
- source: DEV
- events:
- - article_created
- WebhookShow:
- value:
- type_of: webhook_endpoint
- id: 1
- source: DEV
- target_url: https://example.com/webhooks/webhook1
- events:
- - article_created
- created_at: "2019-09-02T09:47:39.230Z"
- user:
- name: bob
- username: bob
- twitter_username:
- github_username: bob
- website_url:
- profile_image: "..."
- profile_image_90: "..."
-
- ProfileImage:
- value:
- type_of: profile_image
- image_of: user
- profile_image: https://res.cloudinary.com/...jpeg
- profile_image_90: https://res.cloudinary.com/...jpeg
-
- Organization:
- value:
- type_of: organization
- username: ecorp
- name: E Corp
- summary: Together we can change the world, with E Corp
- twitter_username: ecorp
- github_username: ecorp
- url: https://ecorp.internet
- location: New York
- joined_at: '2019-10-24T13:41:29Z'
- tech_stack: Ruby
- tag_line:
- story:
- profile_image: https://res.cloudinary.com/...jpeg
-
-tags:
- - name: articles
- description: Articles are all the posts users create on DEV
- - name: comments
- description: Users can leave comments to articles and podcasts episodes
- - name: follows
- description: Resources are user can follow
- - name: followers
- description: Users can follow other users on the website
- - name: listings
- description: Listings are classified ads
- - name: organizations
- description: Users can create and join organizations
- - name: podcast-episodes
- description: Podcast episodes
- - name: readinglist
- description: User's reading list
- - name: tags
- description: Tags for articles
- - name: users
- description: Users own resources that require authentication
- - name: videos
- description: Video articles
- - name: webhooks
- description: Webhooks are HTTP endpoints registered to receive events
- - name: profile images
- description: User or organization profile images
-
-paths:
- /articles:
- get:
- operationId: getArticles
- summary: Published articles
- description: |
- This endpoint allows the client to retrieve a list of articles.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- By default it will return featured, published articles ordered
- by descending popularity.
-
- It supports pagination, each page will contain `30` articles by default.
- tags:
- - articles
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- - name: tag
- in: query
- description: |
- Using this parameter will retrieve articles that contain the
- requested tag.
-
- Articles will be ordered by descending popularity.
-
- This parameter can be used in conjuction with `top`.
- schema:
- type: string
- example: discuss
- - name: tags
- in: query
- description: |
- Using this parameter will retrieve articles with any of the comma-separated tags.
-
- Articles will be ordered by descending popularity.
- schema:
- type: string
- example: "javascript, css"
- - name: tags_exclude
- in: query
- description: |
- Using this parameter will retrieve articles that do _not_ contain _any_ of comma-separated tags.
-
- Articles will be ordered by descending popularity.
- schema:
- type: string
- example: "node, java"
- - name: username
- in: query
- description: |
- Using this parameter will retrieve articles belonging
- to a User or Organization ordered by descending publication date.
-
- If `state=all` the number of items returned will be `1000` instead of the default `30`.
-
- This parameter can be used in conjuction with `state`.
- schema:
- type: string
- example: ben
- - name: state
- in: query
- description: |
- Using this parameter will allow the client to check which articles are fresh or rising.
-
- If `state=fresh` the server will return fresh articles.
- If `state=rising` the server will return rising articles.
-
- This param can be used in conjuction with `username`, only if set to `all`.
- schema:
- type: string
- enum: [fresh, rising, all]
- example: fresh
- - name: top
- in: query
- description: |
- Using this parameter will allow the client to return the most popular articles
- in the last `N` days.
-
- `top` indicates the number of days since publication of the articles
- returned.
-
- This param can be used in conjuction with `tag`.
- schema:
- type: integer
- format: int32
- minimum: 1
- example: 2
- - name: collection_id
- in: query
- description: |
- Adding this will allow the client to return the list of articles
- belonging to the requested collection, ordered by ascending
- publication date.
- schema:
- type: integer
- format: int32
- example: 99
- responses:
- "200":
- description: A list of articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleIndex"
- examples:
- articles-success:
- $ref: "#/components/examples/ArticlesIndex"
- x-codeSamples:
- - lang: Shell
- label: curl (all articles)
- source: |
- curl https://dev.to/api/articles
- - lang: Shell
- label: curl (user's articles)
- source: |
- curl https://dev.to/api/articles?username=ben
- post:
- operationId: createArticle
- summary: Create a new article
- description: |
- This endpoint allows the client to create a new article.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- ### Rate limiting
-
- There is a limit of 10 requests per 30 seconds.
-
- ### Additional resources
-
- - [Rails tests for Articles API](https://github.com/forem/forem/blob/main/spec/requests/api/v0/articles_spec.rb)
- tags:
- - articles
- requestBody:
- description: Article to create
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleCreate"
- examples:
- article-create-title-body:
- $ref: "#/components/examples/ArticleCreateTitleBody"
- article-create-front-matter:
- $ref: "#/components/examples/ArticleCreateFrontMatter"
- article-create-organization:
- $ref: "#/components/examples/ArticleCreateOrganization"
-
- responses:
- "201":
- description: A newly created article
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleShow"
- examples:
- article-success:
- $ref: "#/components/examples/ArticleShow"
- headers:
- Location:
- description: The URL of the new article
- schema:
- type: string
- format: url
- "400":
- description: BadRequest
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-bad-request:
- $ref: "#/components/examples/ErrorBadRequest"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "403":
- description: Forbidden
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-forbidden:
- $ref: "#/components/examples/ErrorForbidden"
- "422":
- description: Unprocessable Entity
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorUnprocessableEntity"
- "429":
- description: Too Many Requests
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorTooManyRequests"
- headers:
- Retry-After:
- description: The number of seconds to wait until the next request
- schema:
- type: integer
- format: int32
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"article":{"title":"Title","body_markdown":"Body","published":false,"tags":["discuss", "javascript"]}}' \
- https://dev.to/api/articles
- - lang: Shell
- label: curl (with front matter)
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"article":{"body_markdown":"---\ntitle:A sample article about...\npublished:false\n---\n..."}}' \
- https://dev.to/api/articles
-
- /articles/latest:
- get:
- operationId: getLatestArticles
- summary: Published articles sorted by publish date
- description: |
- This endpoint allows the client to retrieve a list of articles.
- ordered by descending publish date.
-
- It supports pagination, each page will contain `30` articles by default.
- tags:
- - articles
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of articles sorted by descending publish date
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleIndex"
- examples:
- articles-success:
- $ref: "#/components/examples/ArticlesIndex"
-
- /articles/{id}:
- parameters:
- - name: id
- in: path
- required: true
- description: Id of the article
- schema:
- type: integer
- format: int32
- minimum: 1
- example: 150589
- get:
- operationId: getArticleById
- summary: A published article by ID
- description: |
- This endpoint allows the client to retrieve a single
- published article given its `id`.
- tags:
- - articles
- responses:
- "200":
- description: An article
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleShow"
- examples:
- article-success:
- $ref: "#/components/examples/ArticleShow"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/articles/150589
- put:
- operationId: updateArticle
- summary: Update an article
- description: |
- This endpoint allows the client to update an existing article.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- ### Rate limiting
-
- There is a limit of 30 requests per 30 seconds.
-
- ### Additional resources
-
- - [Rails tests for Articles API](https://github.com/forem/forem/blob/main/spec/requests/api/v0/articles_spec.rb)
- tags:
- - articles
- requestBody:
- description: |
- Article params for the update.
-
- *Note: if the article contains a front matter in its body, its front
- matter properties will still take precedence over any JSON equivalent
- params, which means that the full body_markdown with the modified
- front matter params needs to be provided for an update to be successful*
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleUpdate"
- examples:
- article-update-title-body:
- $ref: "#/components/examples/ArticleCreateTitleBody"
- article-update-front-matter:
- $ref: "#/components/examples/ArticleCreateFrontMatter"
- article-update-organization:
- $ref: "#/components/examples/ArticleCreateOrganization"
- responses:
- "200":
- description: The updated article
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleShow"
- examples:
- article-success:
- $ref: "#/components/examples/ArticleShow"
- "400":
- description: BadRequest
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-bad-request:
- $ref: "#/components/examples/ErrorBadRequest"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "403":
- description: Forbidden
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-forbidden:
- $ref: "#/components/examples/ErrorForbidden"
- "422":
- description: Unprocessable Entity
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorUnprocessableEntity"
- "429":
- description: Too Many Requests
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorTooManyRequests"
- headers:
- Retry-After:
- description: The number of seconds to wait until the next request
- schema:
- type: integer
- format: int32
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -X PUT -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"article":{"title":"Title"}}' \
- https://dev.to/api/articles/{id}
-
- /articles/{username}/{slug}:
- parameters:
- - name: username
- in: path
- required: true
- description: User or organization username.
- schema:
- type: string
- example: devteam
- - name: slug
- in: path
- required: true
- description: Slug of the article.
- schema:
- type: string
- example: for-empowering-community-2k6h
- get:
- operationId: getArticleByPath
- summary: A published article by path
- description: |
- This endpoint allows the client to retrieve a single
- published article given its `path`.
- tags:
- - articles
- responses:
- "200":
- description: An article
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleShow"
- examples:
- article-success:
- $ref: "#/components/examples/ArticleShow"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/articles/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
-
- /articles/me:
- get:
- operationId: getUserArticles
- summary: User's articles
- description: |
- This endpoint allows the client to retrieve a list of published articles
- on behalf of an authenticated user.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- Published articles will be in reverse chronological publication order.
-
- It will return published articles with pagination.
- By default a page will contain `30` articles.
- tags:
- - articles
- - users
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of published articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleMe"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/articles/me
-
- /articles/me/published:
- get:
- operationId: getUserPublishedArticles
- summary: User's published articles
- description: |
- This endpoint allows the client to retrieve a list of published articles
- on behalf of an authenticated user.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- Published articles will be in reverse chronological publication order.
-
- It will return published articles with pagination.
- By default a page will contain `30` articles.
- tags:
- - articles
- - users
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of published articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleMe"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/articles/me/published
-
- /articles/me/unpublished:
- get:
- operationId: getUserUnpublishedArticles
- summary: User's unpublished articles
- description: |
- This endpoint allows the client to retrieve a list of unpublished articles
- on behalf of an authenticated user.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- Unpublished articles will be in reverse chronological creation order.
-
- It will return unpublished articles with pagination.
- By default a page will contain `30` articles.
- tags:
- - articles
- - users
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleMe"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/articles/me/unpublished
-
- /articles/me/all:
- get:
- operationId: getUserAllArticles
- summary: User's all articles
- description: |
- This endpoint allows the client to retrieve a list of all articles on
- behalf of an authenticated user.
-
- "Articles" are all the posts that users create on DEV that typically
- show up in the feed. They can be a blog post, a discussion question,
- a help thread etc. but is referred to as article within the code.
-
- It will return both published and unpublished articles with pagination.
-
- Unpublished articles will be at the top of the list in reverse chronological creation order.
- Published articles will follow in reverse chronological publication order.
-
- By default a page will contain `30` articles.
- tags:
- - articles
- - users
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleMe"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/articles/me/all
-
- /comments:
- get:
- operationId: getCommentsByArticleId
- summary: Comments
- description: |
- This endpoint allows the client to retrieve all comments belonging to an
- article or podcast episode as threaded conversations.
-
- It will return the all top level comments with their nested comments as
- threads. See the format specification for further details.
- tags:
- - comments
- parameters:
- - name: a_id
- in: query
- description: Article identifier.
- schema:
- type: integer
- format: int32
- minimum: 1
- example: 270180
- - name: p_id
- in: query
- description: Podcast Episode identifier.
- schema:
- type: integer
- format: int32
- minimum: 1
- example: 124
- responses:
- "200":
- description: A list of threads of comments
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Comment"
- examples:
- comments-success:
- $ref: "#/components/examples/Comments"
- comments-success-deleted:
- $ref: "#/components/examples/CommentsDeleted"
- comments-success-hidden:
- $ref: "#/components/examples/CommentsHidden"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl (all comments of an article)
- source: |
- curl https://dev.to/api/comments?a_id=270180
- - lang: Shell
- label: curl (all comments of a podcast episode)
- source: |
- curl https://dev.to/api/comments?p_id=124
-
- /comments/{id}:
- get:
- operationId: getCommentById
- summary: Comment
- description: |
- This endpoint allows the client to retrieve a comment as well as his
- descendants comments.
-
- It will return the required comment (the root) with its nested
- descendants as a thread.
-
- See the format specification for further details.
- tags:
- - comments
- parameters:
- - name: id
- in: path
- required: true
- description: Comment identifier.
- schema:
- type: string
- example: m35m
- responses:
- "200":
- description: A comment and its descendants
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Comment"
- examples:
- comment-success:
- $ref: "#/components/examples/Comment"
- comments-success-deleted:
- $ref: "#/components/examples/CommentDeleted"
- comments-success-hidden:
- $ref: "#/components/examples/CommentHidden"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl (a comment and its descendants)
- source: |
- curl https://dev.to/api/comments/m51e
-
- /followers/users:
- get:
- operationId: getFollowers
- summary: Followers
- description: |
- This endpoint allows the client to retrieve a list of the followers
- they have.
-
- "Followers" are users that are following other users on the website.
-
- It supports pagination, each page will contain `80` followers by default.
- tags:
- - followers
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam80to1000'
- - in: query
- name: sort
- schema:
- type: string
- default: 'created_at'
- pattern: '^-?\w+(,-?\w+)*$'
- required: false
- description: |
- Specifies the sort order for the `created_at` param of the follow
- relationship. To sort by newest followers first (descending order)
- specify `?sort=-created_at`.
- responses:
- "200":
- description: A list of followers
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Follower"
- examples:
- followers-success:
- $ref: "#/components/examples/Followers"
-
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/followers/users
-
- /follows/tags:
- get:
- operationId: getFollowedTags
- summary: Followed tags
- description: |
- This endpoint allows the client to retrieve a list of the tags
- they follow.
- tags:
- - follows
- - tags
- responses:
- "200":
- description: A list of followed tags
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/FollowedTag"
- examples:
- followers-success:
- $ref: "#/components/examples/TagsFollowed"
-
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/follows/tags
-
- /listings:
- get:
- operationId: getListings
- summary: Published listings
- description: |
- This endpoint allows the client to retrieve a list of listings.
-
- "Listings" are classified ads that users create on DEV.
- They can be related to conference announcements, job offers, mentorships,
- upcoming events and more.
-
- By default it will return published listings ordered by descending
- freshness.
-
- It supports pagination, each page will contain `30` articles by default.
- tags:
- - listings
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- - $ref: '#/components/parameters/listingCategoryParam'
- responses:
- "200":
- description: A list of listings
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Listing"
- examples:
- listings-success:
- $ref: "#/components/examples/Listings"
- x-codeSamples:
- - lang: Shell
- label: curl (all listings)
- source: |
- curl https://dev.to/api/listings
- post:
- operationId: createListing
- summary: Create a new listing
- description: |
- This endpoint allows the client to create a new listing.
-
- "Listings" are classified ads that users create on DEV.
- They can be related to conference announcements, job offers, mentorships,
- upcoming events and more.
-
- The user creating the listing or the organization on which behalf the user
- is creating for need to have enough creadits for this operation to be
- successful. The server will prioritize the organization's credits over
- the user's credits.
-
- ### Additional resources
-
- - [Rails tests for Listings API](https://github.com/forem/forem/blob/main/spec/requests/api/v0/listings_spec.rb)
- tags:
- - listings
- requestBody:
- description: Listing to create
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ListingCreate"
- examples:
- listing-create:
- $ref: "#/components/examples/ListingCreate"
- listing-create-organization:
- $ref: "#/components/examples/ListingCreateOrganization"
-
- responses:
- "201":
- description: A newly created Listing
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Listing"
- examples:
- article-success:
- $ref: "#/components/examples/Listing"
- "400":
- description: BadRequest
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-bad-request:
- $ref: "#/components/examples/ErrorBadRequest"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "402":
- description: PaymentRequired
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorPaymentRequired"
- "422":
- description: Unprocessable Entity
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorUnprocessableEntity"
- security:
- - api_key: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"listing":{"title":"Title","body_markdown":"Body","category":"cfp"}}' \
- https://dev.to/api/listings
- - lang: Shell
- label: curl (with tags)
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"listing":{"title":"Title","body_markdown":"Body","category":"cfp","tags":["python"]}}' \
- https://dev.to/api/listings
- - lang: Shell
- label: curl (draft)
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"listing":{"title":"Title","body_markdown":"Body","category":"cfp","action":"draft"}}' \
- https://dev.to/api/listings
-
- /listings/category/{category}:
- get:
- operationId: getListingsByCategory
- summary: Published listings by category
- description: |
- This endpoint allows the client to retrieve a list of listings belonging
- to the specified category.
-
- "Listings" are classified ads that users create on DEV.
- They can be related to conference announcements, job offers, mentorships,
- upcoming events and more.
-
- By default it will return published listings ordered by descending
- freshness.
-
- It supports pagination, each page will contain `30` articles by default.
- tags:
- - listings
- parameters:
- - name: category
- in: path
- required: true
- description: The category of the listing
- schema:
- $ref: "#/components/schemas/ListingCategory"
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of listings
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Listing"
- examples:
- listings-success:
- $ref: "#/components/examples/Listings"
- x-codeSamples:
- - lang: Shell
- label: curl (call for papers listings)
- source: |
- curl https://dev.to/api/listings/category/cfp
-
- /listings/{id}:
- parameters:
- - name: id
- in: path
- required: true
- description: Id of the listing
- schema:
- type: integer
- format: int64
- minimum: 1
- example: 1
- get:
- operationId: getListingById
- summary: A listing
- description: |
- This endpoint allows the client to retrieve
- a single listing given its `id`.
-
- An unpublished listing is only accessible if authentication is supplied
- and it belongs to the authenticated user.
- tags:
- - listings
- responses:
- "200":
- description: A listing
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Listing"
- examples:
- article-success:
- $ref: "#/components/examples/Listing"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- security:
- - {} # this indicates that authentication is optional
- - api_key: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/listings/1184
- - lang: Shell
- label: curl (with authentication)
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/listings/1185
- put:
- operationId: updateListing
- summary: Update a listing
- description: |
- This endpoint allows the client to update an existing listing.
- tags:
- - listings
- requestBody:
- description: |
- Listing params for the update.
-
- **Note**: except for bumping, publishing and unpublishing there are the
- following restrictions on the ability to update listings:
-
- - the payload has to contain at least one param among `title`, `body_markdown` or `tags`/`tag_list`
- - the listing can't be updated if it has not been bumped in the last 24 hours
- - the listing can't be updated if it has been published but not recently bumped
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ListingUpdate"
- examples:
- listing-update-action-bump:
- $ref: "#/components/examples/ListingUpdateActionBump"
- listing-update-action-publish:
- $ref: "#/components/examples/ListingUpdateActionPublish"
- listing-update-action-unpublish:
- $ref: "#/components/examples/ListingUpdateActionUnpublish"
- listing-update:
- $ref: "#/components/examples/ListingUpdate"
- responses:
- "200":
- description: The updated article
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ArticleShow"
- examples:
- article-success:
- $ref: "#/components/examples/ArticleShow"
- "400":
- description: BadRequest
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-bad-request:
- $ref: "#/components/examples/ErrorBadRequest"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "402":
- description: PaymentRequired
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorPaymentRequired"
- "422":
- description: Unprocessable Entity
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorUnprocessableEntity"
- security:
- - api_key: []
- x-codeSamples:
- - lang: Shell
- label: curl (bump)
- source: |
- curl -X PUT -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"listing":{"action":"bump"}' \
- https://dev.to/api/listings/{id}
- - lang: Shell
- label: curl (update)
- source: |
- curl -X PUT -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"listing":{"title":"Title"}' \
- https://dev.to/api/listings/{id}
-
- /readinglist:
- get:
- operationId: getReadinglist
- summary: User's reading list
- description: |
- This endpoint allows the client to retrieve a list of readinglist reactions along with the related article for the authenticated user.
-
- Reading list will be in reverse chronological order base
- on the creation of the reaction.
-
- It will return paginated reading list items along with the articles
- they refer to. By default a page will contain `30` items
- tags:
- - readinglist
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to100'
- responses:
- "200":
- description: The reading list with a overwiew of the article
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ReadingList"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/readinglist
-
- /organizations/{username}:
- get:
- operationId: getOrganization
- summary: An organization
- description: |
- This endpoint allows the client to retrieve a single organization by their username
- tags:
- - organizations
- parameters:
- - name: username
- in: path
- required: true
- description: |
- Username of the organization
- schema:
- type: string
- example: "ecorp"
- responses:
- "200":
- description: An organization
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Organization"
- examples:
- user-success:
- $ref: "#/components/examples/Organization"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- user-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/organizations/ecorp
-
- /organizations/{username}/users:
- get:
- operationId: getOrgUsers
- summary: Organization's users
- description: |
- This endpoint allows the client to retrieve a list of users belonging to the organization
-
- It supports pagination, each page will contain `30` users by default.
- tags:
- - organizations
- parameters:
- - name: username
- in: path
- required: true
- description: |
- Username of the organization
- schema:
- type: string
- example: "ecorp"
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of users belonging to the organization
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/User"
- examples:
- user-success:
- $ref: "#/components/examples/Users"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- user-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/organizations/ecorp/users
-
- /organizations/{username}/listings:
- get:
- operationId: getOrgListings
- summary: Organization's listings
- description: |
- This endpoint allows the client to retrieve a list of listings belonging to the organization
-
- It supports pagination, each page will contain `30` listing by default.
- tags:
- - organizations
- parameters:
- - name: username
- in: path
- required: true
- description: |
- Username of the organization
- schema:
- type: string
- example: "ecorp"
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- - $ref: '#/components/parameters/listingCategoryParam'
- responses:
- "200":
- description: A list of listings belonging to the organization
- content:
- application/json:
- schema:
- type: array
- items:
- allOf:
- - $ref: "#/components/schemas/Listing"
- - required:
- - organization
- examples:
- user-success:
- $ref: "#/components/examples/ListingsByOrganization"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- user-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/organizations/ecorp/listings
-
- /organizations/{username}/articles:
- get:
- operationId: getOrgArticles
- summary: Organization's Articles
- description: |
- This endpoint allows the client to retrieve a list of Articles belonging to the organization
-
- It supports pagination, each page will contain `30` listing by default.
- tags:
- - organizations
- parameters:
- - name: username
- in: path
- required: true
- description: |
- Username of the organization
- schema:
- type: string
- example: "ecorp"
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- responses:
- "200":
- description: A list of users belonging to the organization
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleIndex"
- examples:
- article-success:
- $ref: "#/components/examples/ArticlesIndex"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- user-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/organizations/ecorp/listings
-
- /podcast_episodes:
- get:
- operationId: getPodcastEpisodes
- summary: Published podcast episodes
- description: |
- This endpoint allows the client to retrieve a list of podcast episodes.
-
- "Podcast episodes" are episodes belonging to podcasts.
-
- It will only return active podcast episodes that belong to published
- podcasts available on the platform,
- ordered by descending publication date.
-
- It supports pagination, each page will contain `30` articles by default.
- tags:
- - podcast-episodes
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam30to1000'
- - name: username
- in: query
- description: |
- Using this parameter will retrieve episodes belonging
- to a specific podcast.
- schema:
- type: string
- example: codenewbie
- responses:
- "200":
- description: A list of podcast episodes
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/PodcastEpisode"
- examples:
- articles-success:
- $ref: "#/components/examples/PodcastEpisodes"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl (all podcast episodes)
- source: |
- curl https://dev.to/api/podcast_episodes
- - lang: Shell
- label: curl (all episodes belonging to a podcast)
- source: |
- curl https://dev.to/api/podcast_episodes?username=codenewbie
-
- /tags:
- get:
- operationId: getTags
- summary: Tags
- description: |
- This endpoint allows the client to retrieve a list of tags
- that can be used to tag articles.
-
- It will return tags ordered by popularity.
-
- It supports pagination, each page will contain `10` tags by default.
- tags:
- - tags
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam10to1000'
- responses:
- "200":
- description: A list of tags
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Tag"
- examples:
- articles-success:
- $ref: "#/components/examples/Tags"
- x-codeSamples:
- - lang: Shell
- label: curl (all tags)
- source: |
- curl https://dev.to/api/tags
-
- /users/{id}:
- get:
- operationId: getUser
- summary: A user
- description: |
- This endpoint allows the client to retrieve a single user, either by
- id or by the user's username
- tags:
- - users
- parameters:
- - name: id
- in: path
- required: true
- description: |
- Id of the user.
-
- It can be either of the following two values:
-
- - an integer representing the id of the user
- - the string `by_username` (needs to be used in conjuction with the param `url`)
- schema:
- type: string
- example: "1"
- - name: url
- in: query
- description: Username of the user
- schema:
- type: string
- example: ben
- responses:
- "200":
- description: A user
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/User"
- examples:
- user-success:
- $ref: "#/components/examples/User"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- user-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl (by id)
- source: |
- curl https://dev.to/api/users/1
- - lang: Shell
- label: curl (by username)
- source: |
- curl https://dev.to/api/users/by_username?url=ben
-
- /users/me:
- get:
- operationId: getUserMe
- summary: The authenticated user
- description: |
- This endpoint allows the client to retrieve information
- about the authenticated user
- tags:
- - users
- responses:
- "200":
- description: A user
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/User"
- examples:
- user-success:
- $ref: "#/components/examples/User"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/users/me
-
- /profile_images/{username}:
- get:
- operationId: getProfileImage
- summary: User or organization profile picture
- description: |
- This endpoint allows the client to retrieve a user or organization
- profile image information by its corresponding username
- tags:
- - profile images
- parameters:
- - name: username
- in: path
- required: true
- description: Username of the user or organization
- schema:
- type: string
- example: "diogoosorio"
- responses:
- "200":
- description: The profile image
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ProfileImage"
- examples:
- profile-image-success:
- $ref: "#/components/examples/ProfileImage"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- profile-image-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/profile_images/diogoosorio
-
- /videos:
- get:
- operationId: getArticlesWithVideo
- summary: Articles with a video
- description: |
- This endpoint allows the client to retrieve a list of articles
- that are uploaded with a video.
-
- It will only return published video articles
- ordered by descending popularity.
-
- It supports pagination, each page will contain `24` articles by default.
- tags:
- - articles
- - videos
- parameters:
- - $ref: '#/components/parameters/pageParam'
- - $ref: '#/components/parameters/perPageParam24to1000'
- responses:
- "200":
- description: A list of video articles
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/ArticleVideo"
- examples:
- articles-success:
- $ref: "#/components/examples/ArticleVideo"
- x-codeSamples:
- - lang: Shell
- label: curl (all video articles)
- source: |
- curl https://dev.to/api/videos
-
- /webhooks:
- get:
- operationId: getWebhooks
- summary: Webhooks
- description: |
- This endpoint allows the client to retrieve a list of webhooks they have
- previously registered.
-
- "Webhooks" are used to register HTTP endpoints that will be called once a relevant event is
- triggered inside the web application, events like `article_created`, `article_updated`.
-
- It will return all webhooks, without pagination.
- tags:
- - webhooks
- responses:
- "200":
- description: A list of webhooks
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/WebhookIndex"
- examples:
- webhooks-success:
- summary: Successful response
- value:
- - type_of: webhook_endpoint
- id: 1
- source: DEV
- target_url: https://example.com/webhooks/webhook1
- events:
- - article_created
- created_at: "2019-09-02T09:47:39.230Z"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -H "api-key: API_KEY" https://dev.to/api/webhooks
- post:
- operationId: createWebhook
- summary: Create a new webhook
- description: |
- This endpoint allows the client to create a new webhook.
-
- "Webhooks" are used to register HTTP endpoints that will be called once a relevant event is
- triggered inside the web application, events like `article_created`, `article_updated`.
- tags:
- - webhooks
- requestBody:
- description: Webhook to create
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/WebhookCreate"
- examples:
- webhook-create:
- $ref: "#/components/examples/WebhookCreate"
-
- responses:
- "201":
- description: A newly created webhook
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/WebhookShow"
- examples:
- webhook-success:
- $ref: "#/components/examples/WebhookShow"
- "400":
- description: BadRequest
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-bad-request:
- $ref: "#/components/examples/ErrorBadRequest"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "422":
- description: Unprocessable Entity
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- error-unprocessable-entity:
- $ref: "#/components/examples/ErrorUnprocessableEntity"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -X POST -H "Content-Type: application/json" \
- -H "api-key: API_KEY" \
- -d '{"webhook_endpoint":{"target_url":"https://example.org/webhooks/webhook1","source":"DEV","events":["article_created"]}}' \
- https://dev.to/api/webhooks
-
- /webhooks/{id}:
- parameters:
- - name: id
- in: path
- required: true
- description: Id of the webhook
- schema:
- type: integer
- format: int64
- minimum: 1
- example: 123
- get:
- operationId: getWebhookById
- summary: A webhook endpoint
- description: |
- This endpoint allows the client to retrieve a single
- webhook given its `id`.
- tags:
- - webhooks
- responses:
- "200":
- description: A webhook endpoint
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/WebhookShow"
- examples:
- webhook-success:
- $ref: "#/components/examples/WebhookShow"
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl https://dev.to/api/webhooks/123
- delete:
- operationId: deleteWebhook
- summary: A webhook endpoint
- description: |
- This endpoint allows the client to delete a single
- webhook given its `id`.
- tags:
- - webhooks
- responses:
- "204":
- description: A successful deletion
- "401":
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-unauthorized:
- $ref: "#/components/examples/ErrorUnauthorized"
- "404":
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/APIError"
- examples:
- article-not-found:
- $ref: "#/components/examples/ErrorNotFound"
- security:
- - api_key: []
- - oauth2: []
- x-codeSamples:
- - lang: Shell
- label: curl
- source: |
- curl -X DELETE \
- -H "api-key: API_KEY" \
- https://dev.to/api/webhooks/1
diff --git a/docs/backend/audit-log.md b/docs/backend/audit-log.md
deleted file mode 100644
index 63701fdcd..000000000
--- a/docs/backend/audit-log.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-title: Audit Log
----
-
-# Audit Log
-
-To help maintain accountability for users with elevated permissions the Forem
-application has a special model that records certain actions.
-
-For example, when a user with the `trusted` role creates a negative reaction on
-an article a record is created with certain information about that action.
-
-That record (which we call an `AuditLog`) looks something like this:
-
-```ruby
-#"create", "category"=>"vomit", "controller"=>"reactions", "reactable_id"=>"16", "reactable_type"=>"Article"},
- roles: ["trusted"],
- slug: "create",
- updated_at: Thu, 07 May 2020 20:25:31 UTC +00:00,
- user_id: 21>
-```
-
-You can see from this record that the user with an id of `21` created a vomit
-reaction on the article with an id of `16`. If that's not obvious to you from
-this object, don't worry, just take our word on it.
-
-You can find an example of `Audit::Logger` in action in
-`app/controllers/admin/reactions_controller.rb`:
-
-```ruby
- after_action only: [:update] do
- Audit::Logger.log(:moderator, current_user, params.dup)
- end
-```
-
-This code creates a record to indicate that a someone modified a reaction from
-the admin controller.
-
-It's a good idea to add a similar `after_action` to any controller action that
-might benefit from increased transparency.
-
-Additionally, the `AuditLog` is used to track important actions performed on a
-user's account, e.g. adding or removing a credit card:
-
-```ruby
-# {
- category: "user.credit_card.edit",
- created_at: Tue, 21 Jul 2020 06:35:13 +03 +03:00,
- data: {
- "action" => "create",
- "controller" => "stripe_active_cards",
- "user_action" => "add"
- },
- id: 4,
- roles: [],
- slug: "credit_card_add",
- updated_at: Tue, 21 Jul 2020 06:35:13 +03 +03:00,
- user_id: 53
-}
-```
diff --git a/docs/backend/auth-apple.md b/docs/backend/auth-apple.md
deleted file mode 100644
index f292675ae..000000000
--- a/docs/backend/auth-apple.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Apple Authentication
----
-
-# Sign in with Apple Authentication
-
-Forem allows you to authenticate using
-[Sign in with Apple](https://developer.apple.com/sign-in-with-apple/). In order
-to use this authentication method you'll need to be enrolled to the
-[Apple Developer Program](https://developer.apple.com/programs/) in order to
-retrieve the necessary credentials and an HTTPS supported URL for the callback
-configuration (HTTP won't work). Then you'll need to provide the keys to the
-Rails application.
-
-# Apple Developer Portal Configuration
-
-[Register/Sign in](https://developer.apple.com/account) to your Apple Developer
-Account.
-
-## Service ID Configuration
-
-1. [Create a Service ID](https://developer.apple.com/account/resources/identifiers/list/serviceId)
-
-
-
-2. Name the Service and finalize the registration
-
-
-
-3. Configure Domains and Subdomains & the callback URL. This example uses
- [ngrok](https://ngrok.io) for HTTPS support.
-
-
-
-## Key Configuration
-
-1. [Register a new Key](https://developer.apple.com/account/resources/authkeys/add).
- Enable the "Sign in with Apple" option and configure it so it's associated
- with the corresponding App ID
-
-
-
-2. Download the Key
-
-
-
-# Configuring the Rails Application
-
-Now with both the Service ID and Key you'll need to enable Apple Authentication
-and pass in the credentials in the admin dashboard
-`/admin/customization/config`.
-
-
-
-Add the corresponding configuration data. Make sure the PEM key you downloaded
-has explicit linebreaks (`\n`), don't forget the one at the very end of it.
-
-
-
-Save the changes and restart your server for these values to take effect.
-
-## Email configuration
-
-Apple uses what they call Private Email Relay Service to hide user's emails. For
-this to work first
-[create a new email source](https://developer.apple.com/account/resources/services/list).
-
-
-
-Emails sent need to be authenticated and the configuration depends on the
-different providers available:
-
-- [Mailchimp](https://mailchimp.com/help/set-up-custom-domain-authentication-dkim-and-spf/)
-- [SendGrid](https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/)
-- [SES](https://docs.aws.amazon.com/es_es/ses/latest/DeveloperGuide/send-email-authentication-dkim.html)
diff --git a/docs/backend/auth-facebook.md b/docs/backend/auth-facebook.md
deleted file mode 100644
index c165eb9b9..000000000
--- a/docs/backend/auth-facebook.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Facebook Authentication
----
-
-# Facebook App and Authentication
-
-Forem allows you to authenticate using Facebook. In order to use this
-authentication method in local development, you will need to setup a Facebook
-App and retrieve its keys. Then you'll need to provide these keys to the Rails
-application.
-
-## Sign up
-
-1. [Sign in](https://facebook.com) to your Facebook account.
-
-2. In order to get the API keys, you will have to
- [convert your account to a developer account](https://developers.facebook.com/).
-
-## Get API keys
-
-1. [Sign up](#facebook-sign-up) or [sign in](https://developers.facebook.com) to
- your Facebook developer account.
-
-2. From **My Apps** dashboard, click on **Add a New App**.
-
- 
-
-3. Select **For Everything Else**
-
- 
-
-4. Fill in the app display name and contact email, then click on **Create App
- ID**
-
- 
-
-5. On the **Add a Product** screen, click **Set Up** under the **Facebook
- Login** section
-
- 
-
-6. Ignore the quickstart options, and click **Settings -> Basic** in the sidebar
-
- 
-
-7. From the basic settings screen dashboard copy the **App ID** and **App
- Secret** values to your `.env` file accordingly (name of Facebook key -> name
- of our `Settings::General` variable).
-
- ```text
- APP ID -> FACEBOOK_APP_ID
- API secret -> FACEBOOK_APP_SECRET
- ```
-
- 
-
-## Configure the Facebook App
-
-1. From the basic settings screen dashboard set your application's domain name
- in **App Domains** field, and be sure to click **Save Changes**
-
- 
-
-2. Naviate to **Facebook Login --> Settings**, and enter the following callback
- URL in the field **Valid OAuth Redirect URIs**:
-
- `https://>/users/auth/facebook/callback`
-
- 
diff --git a/docs/backend/auth-github.md b/docs/backend/auth-github.md
deleted file mode 100644
index feccd95b3..000000000
--- a/docs/backend/auth-github.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: GitHub Authentication
----
-
-# GitHub App and Authentication
-
-Forem allows you to authenticate using GitHub. To use this authentication method
-in local development, you will need to set up a GitHub App and retrieve its
-keys. Then you'll need to provide these keys to the Rails application.
-
-1. [Click this link to create a new OAuth application in your Github account](https://github.com/settings/applications/new) -
- you will be redirected to sign in to Github account if you have not already.
-
-2. Fill in the form with an application name, description, and the URL
- `http://localhost:3000/users/auth/github/callback`. Replace the port `3000` if you run Forem on another
- port.
-
- 
-
-3. You will be redirected to the app's **Developer settings**. Here you will
- find the keys. Add them to your `.env` file accordingly (name of GitHub key
- -> name of our `ENV` variable):
-
- ```text
- Client ID -> GITHUB_KEY
- Client Secret -> GITHUB_SECRET
- ```
-
- 
-
-4. Done.
diff --git a/docs/backend/auth-twitter.md b/docs/backend/auth-twitter.md
deleted file mode 100644
index 89f71e54a..000000000
--- a/docs/backend/auth-twitter.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-title: Twitter Authentication
----
-
-# Twitter App and Authentication
-
-Forem allows you to authenticate using Twitter. In order to use this
-authentication method in local development, you will need to setup a Twitter App
-and retrieve its keys. Then you'll need to provide these keys to the Rails
-application.
-
-## Sign up
-
-1. [Sign in](https://developer.twitter.com/apps) to your Twitter account.
-
-2. In order to get the API keys, you will have to
- [apply for a developer account](https://developer.twitter.com/en/apply-for-access).
- Click the **Apply** button.
-
- 
-
-3. Setup your Twitter account. Be sure you have your phone number and email
- address filled in.
-
- 
-
-4. Fill in your account information and give a name to your **developer
- account**.
-
- 
-
-5. Write down the reasons that you want to use Twitter API. Mention Forem's
- community and describe the issues and tests and things that you want to work
- on. Copy it, you might use it later ;)
-
- 
-
-6. Read :) and accept the Terms and Conditions.
-
- 
-
-7. Verify your email address once more, and you will be done.
-
-8. You are done.
-
-## Get API keys
-
-1. [Sign up](#twitter-sign-up) or [sign in](https://developer.twitter.com/apps)
- to your Twitter developer account.
-
-2. From **Apps** dashboard, click on **Create and app**.
-
- 
-
-3. Fill in the app name, description, and URL `https://dev.to`.
-
- 
-
-4. Check the **Enable Sign in with Twitter** option and fill in the Callback URL
- `http://localhost:3000/users/auth/twitter/callback` (or whatever port you run
- Forem on).
-
- 
-
-5. Fill in the information, **Terms of Service** `http://dev.to/terms` and
- **Privacy policy** `http://dev.to/privacy`.
-
- 
-
-6. Write down (or paste) the things that you will work on. Press **Create**.
-
- 
-
-7. Review the
- [Twitter Developer Terms](https://developer.twitter.com/en/developer-terms/agreement-and-policy.html)
- and agree to do nothing sketchy.
-
- 
-
-8. The app is all set!
-
-9. One more change: From the app dashboard, go to **Permissions** and check
- **Request email addresses from users** option.
-
- 
-
-10. From the same dashboard access the **Keys and tokens** and add them to your
- `.env` file accordingly (name of Twitter key -> name of our `ENV` variable).
- Be sure to copy the _access token_ and _access token secret_ right away
- because it will be hidden from you in the future.
-
- ```text
- API key -> TWITTER_KEY
- API secret key -> TWITTER_SECRET
- ```
-
- 
diff --git a/docs/backend/authentication.md b/docs/backend/authentication.md
deleted file mode 100644
index d7cc97e2c..000000000
--- a/docs/backend/authentication.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Authentication
----
-
-# Authentication
-
-Authentication is handled by [Devise](https://github.com/plataformatec/devise)
-and [OmniAuth](https://github.com/omniauth/omniauth).
-
-On Forem you can authenticate through Facebook, GitHub, or Twitter. Please check out
-the respective guides on how to authenticate:
-
-- [Apple authentication](/backend/auth-apple)
-- [Facebook authentication](/backend/auth-facebook)
-- [Github authentication](/backend/auth-github)
-- [Twitter authentication](/backend/auth-twitter)
-
-We may add other authentication providers in the future. Please check back
-again, or search
-[our GitHub repository's issues.](https://github.com/forem/forem/issues)
diff --git a/docs/backend/authorization.md b/docs/backend/authorization.md
deleted file mode 100644
index 4555b7d05..000000000
--- a/docs/backend/authorization.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Authorization
----
-
-# Authorization
-
-Authorization is handled by the third-party gem
-[Pundit](https://github.com/varvet/pundit) through the `authorize` method which
-you can find in various controllers, look for statements like:
-
-```ruby
-authorize @user
-```
-
-All authorization policies can be found in `/app/policies`.
diff --git a/docs/backend/configuration.md b/docs/backend/configuration.md
deleted file mode 100644
index 324149a9d..000000000
--- a/docs/backend/configuration.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Configuration
----
-
-# Configuration
-
-We currently use the following gems for configuring the application:
-
-- [dotenv](https://github.com/bkeepers/dotenv)
-- [rails-settings-cached](https://github.com/huacnlee/rails-settings-cached)
-- [vault](https://github.com/hashicorp/vault-ruby)
-
-## dotenv
-
-This gem is used for configuring environment variables for test and development
-environments. Examples:
-
-- `REDIS_URL`
-- `FASTLY_API_KEY`
-- `STRIPE_SECRET_KEY`
-
-Settings managed via your ENV can be found in
-[Configuring Environment Variables](/getting-started/config-env)) and viewed at
-`/admin/customization/config` (see [the Admin guide](/admin)):
-
-
-
-## rails-settings-cached
-
-We use this gem for managing settings used within the app's business logic.
-Examples:
-
-- `Settings::General.main_social_image`
-- `Settings::RateLimit.follow_count_daily`
-- `Settings::Authentication.twitter_secret`
-
-These settings can be accessed via the
-[`Settings::General`](https://github.com/forem/forem/blob/master/app/models/settins/general.rb)
-object and various models in the `Settings::` namespace and viewed / modified
-via `/admin/customization/config` (see [the Admin guide](/admin)).
-
-
-
-## Vault
-
-The vault Ruby gem allows us to interact with
-[Vault](https://www.vaultproject.io/docs/what-is-vault). In a nutshell, Vault is
-a tool for securely storing and accessing secrets. It is completely optional for
-running a Forem. To access it we use the wrapper `AppSecrets`.
-
-```ruby
-class AppSecrets
- def self.[](key)
- result = Vault.kv(namespace).read(key)&.data&.fetch(:value) if ENV["VAULT_TOKEN"].present?
- result ||= ApplicationConfig[key]
-
- result
- rescue Vault::VaultError
- ApplicationConfig[key]
- end
-
- def self.[]=(key, value)
- Vault.kv(namespace).write(key, value: value)
- end
-
- def self.namespace
- ENV["VAULT_SECRET_NAMESPACE"]
- end
- private_class_method :namespace
-end
-```
-
-We attempt to access a secret from Vault if it is enabled, i.e. if the
-`VAULT_TOKEN` is present. If Vault is not enabled or if we cannot find the
-secret in it, then we fallback to fetching the secret from the
-`ApplicationConfig`.
-
-One advantage of using Vault with Forem is that it allows you to update your
-secrets easily through the application rather than having to mess with ENV
-files. If you would like to try out Vault, follow our
-[installation guide for setting it up locally](/installation/vault).
diff --git a/docs/backend/data-update-scripts.md b/docs/backend/data-update-scripts.md
deleted file mode 100644
index 7143f8676..000000000
--- a/docs/backend/data-update-scripts.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-title: Data Update Scripts
----
-
-## What are Data Update Scripts?
-
-Data Update Scripts were introduced in
-[this PR](https://github.com/forem/forem/pull/6025) and allow us to run any data
-updates we might need. For example, if we added a column to the database and
-then wanted to backfill that column with data, rather than going and manually
-doing it in a console, we would use a DataUpdateScript.
-
-## How it works
-
-First off, we added a
-[DataUpdateScript model](https://github.com/forem/forem/blob/master/app/models/data_update_script.rb)
-to Rails and a corresponding database table. This table is what we use to keep
-track of what scripts have been run and which ones have not/still need to be.
-
-To create a script you can use our custom Rails generator:
-
-```
-rails generate data_update BackfillColumnForArticles
-```
-
-This will create a simple Ruby class like below and all you have to do is fill
-in the code it will run.
-
-```ruby
-module DataUpdateScripts
- class BackfillColumnForArticles
- def run
- # Place your data update logic here
- # Make sure your code is idempotent and can be run safely
- # multiple times at any time
- end
- end
-end
-```
-
-The generator will also automatically create the corresponding spec file.
-
-```ruby
-require "rails_helper"
-require Rails.root.join(
- "lib/data_updates/20201103042915_backfill_column_for_articles.rb",
-)
-
-describe DataUpdateScripts::BackfillColumnForArticles do
- pending "add some examples to (or delete) #{__FILE__}"
-end
-```
-
-While we encourage adding tests for data update scripts, you can skip spec
-creation by adding the `--no-spec` option to the `rails generate` command:
-
-```
-rails generate data_update BackfillColumnForArticles --no-spec
-```
-
-Once your script is in place then you can either run `rails data_updates:run`
-manually or you can let our setup script handle it. In our local
-[bin/setup](https://github.com/forem/forem/blob/main/bin/setup) script you will
-see we have added an additional task to update data. This kicks off the rake
-task `data_updates:run` for you.
-
-The rake task itself will check the `lib/data_update_scripts` folder to see if
-there are any new scripts that need to be run. It does this by reading all of
-the files and then checking to see if they have a corresponding database entry.
-If they do not, then we create a new one and run the script. If a database entry
-already exists and it indicates the script has been run, then we skip that
-script.
-
-## In production
-
-DataUpdateScripts are also run automatically when a production deploy goes out.
-However, to ensure the new code they need to use has been deployed we use a
-[`DataUpdateWorker`](https://github.com/forem/forem/blob/main/app/workers/data_update_worker.rb)
-via Sidekiq and set it to run 10 minutes after the deploy script has completed.
-
-## Best practices
-
-### Working with large collections of rows
-
-From time to time, scripts need to operate on a large amount of rows; in those
-cases we encourage:
-
-- adding explicit logging to the script
-- reversing the order, to start processing the most recent records first
-
-For example:
-
-```ruby
-def run
- Article.find_each(order: :desc).with_index do |article, index|
- Rails.logging.info("...") if index % 1000 == 0 # this will log every 1000 articles
-
- article.save
- end
-end
-```
diff --git a/docs/backend/emails.md b/docs/backend/emails.md
deleted file mode 100644
index 9f663170a..000000000
--- a/docs/backend/emails.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Emails
----
-
-# Setting up email
-
-If you would like to enable transactional email using services like SendGrid or
-Mailgun, you can configure it by using the following environment variables:
-
-```shell
-SMTP_ADDRESS= # ie. "smtp.sendgrid.net"
-SMTP_PORT= # ie. 587
-SMTP_DOMAIN=
-SMTP_USER_NAME=
-SMTP_PASSWORD=
-SMTP_AUTHENTICATION= # defaults to :plain
-```
-
-We follow the standard `ActionMailer` configuration. For more info, please check
-out Rails'
-[official documentation](https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration).
-
-# Previewing emails in development
-
-You can view email previews at .
-
-Previews are setup in the directory `spec/mailers/previews`.
-
-# Overriding mailer templates
-
-To update the contents of emails that the app sends, edit the views under
-`app/views/mailers`. Note that this app uses the
-[`devise_invitable` gem](https://github.com/scambra/devise_invitable) for
-invitations. The views for this gem are stored under `app/views/devise/mailer`.
diff --git a/docs/backend/fastly.md b/docs/backend/fastly.md
deleted file mode 100644
index ba2074a98..000000000
--- a/docs/backend/fastly.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-title: Fastly
----
-
-## What is Fastly?
-
-[Fastly](https://www.fastly.com/) is a third party service we use for caching on
-the edge. It allows us to scale up and serve our millions of visitors quickly
-and efficiently.
-
-If you want to learn more about we use Fastly, check out this
-[talk](https://www.youtube.com/watch?v=Afy7H04X9Us) that one of our founders,
-[@benhalpern](https://dev.to/ben), gave at RailsConf 2018 talking about how we
-made our app so fast it went viral.
-
-Fastly offers many different configurations (conditions,
-[snippets](https://docs.fastly.com/vcl/vcl-snippets/about-vcl-snippets/), etc.).
-
-## Snippets
-
-Snippets, in general, are _"short blocks of VCL logic that can be included
-directly in your service configurations. They're ideal for adding small sections
-of code when you don't need more complex, specialized configurations that
-sometimes require custom VCL."_
-
-You can learn more about VCL snippets on
-[Fastly's website](https://docs.fastly.com/vcl/vcl-snippets/about-vcl-snippets/)
-
-### Adding query string parameters to a safe list
-
-In the context of contributing, here's what you need to know about Fastly. In
-order for our servers to receive any sort of query string parameters in a
-request, they must first be marked as safe in Fastly. For example, if you're
-creating a new API endpoint or updating an existing one to accept new
-parameters, you'll need to update Fastly.
-
-The reason we have a safe list of parameters in Fastly this way is so we don't
-have to consider junk parameters when busting the caches. Check out our
-[`EdgeCache` services](https://github.com/forem/forem/tree/main/app/services/edge_cache)
-to see examples of this.
-
-Previously this was a manual process done by an internal team member. Now we do
-it programmatically using the Fastly
-[gem](https://github.com/fastly/fastly-ruby).
-
-### How it works
-
-We created a new file, `config/fastly/safe_params_list.vcl`, to house all of the
-safe params in Fastly.
-
-If you need to update this list, simply update this file. It's as easy as that!
-This is a VCL file and you'll see a little Regex checking for a list of safe
-params.
-
-_Fastly is not setup for development._
-
-### In production
-
-If you have Fastly configured in Production, all Fastly configs are updated
-automatically when a production deploy goes out.
-
-We do this by executing `bin/rails fastly:update_configs` in our
-`release-tasks.sh` script.
diff --git a/docs/backend/internationalization.md b/docs/backend/internationalization.md
deleted file mode 100644
index 117ba0638..000000000
--- a/docs/backend/internationalization.md
+++ /dev/null
@@ -1,138 +0,0 @@
----
-title: Internationalization (i18n)
----
-
-# Internationalization (i18n)
-
-## What is internationlization (i18n)?
-
-To over simplify the concept a bit, internalization (i18n for short) is the
-process of making the platform more user-friendly in various languages for
-people around the globe. This includes, but is certainly not limited to, things
-like making the site available in different languages, changing currency values
-to match your region, changing date formats, etc.
-
-## What do we currently support?
-
-We introduced some routing to lay the groundwork for a more comprehensive i18n
-implementation.
-
-## What is the goal?
-
-We want everyone to feel included, regardless of where they're located or what
-language(s) they speak. The goal is to make the platform available in various
-languages.
-
-## How do you get involved?
-
-The following is a high level outline of an approach to internationalization.
-This is by no means set in stone.
-
-We encourage you to open a pull request (PR) to this documentation or to
-contribute to internationalization with your ideas - we're
-[open-source](https://github.com/forem/forem/pulls)!
-
-## Routing
-
-We have logic for routes setup. You can visit a page and add `/locale/:locale`
-to the beginning of the path. For example, if you visit the homepage, you can
-add `/locale/fr-ca` for French, Canadian where `fr` is the language code and
-`ca` is the region code.
-
-Setting up languages under this "sub-folder" approach helps with Search Engine
-Optimization (SEO), routing, and more.
-
-_Currently, the various language routes will not do anything - it will stil show
-the site in English (US)._
-
-Once i18n is up and running, users will be able to select their preferred
-language to view the platform in. These routes will be the location of various
-languages.
-
-## Translating content
-
-There are many ways to translate static content on the platform. To start, we
-can explore tools like [i18n-tasks](https://glebm.github.io/i18n-tasks/) which
-also has an option to leverage Google Translate programmatically. We'll need to
-create locale files (likely `.yml`) to house the translations.
-
-## Search Engine Optimization (SEO)
-
-It seems search engines, especially Google, don't particularly like content on a
-page to be in multiple languages. To account for this on pages like articles, we
-can try an approach using the canonical URL for the language the article was
-written in.
-
-For example, if we detect an article is written in Spanish, we can set the
-canonical URL for that article to be `/locale/es/username/article-slug`. We can
-then hide comments that are not in the same language as the article/rest of the
-page (Spanish in this example) only for the views the crawlers would see. That
-way, when the search engine crawler hits an article written in Spanish, the
-crawler will see the entire page in Spanish. We will not hide comments for the
-views that real users see.
-
-## Caching
-
-The platform relies on edge caching, especially with regards to articles. To
-account for this, we'll need to add logic at the edge that understands what
-languages the platform currently supports and where to look up the language
-variant in the cache.
-
-If the edge doesn't pick up on a user selected preference (possibly sent as an
-additional header or cookie), the edge will look at the `Accept-Language` header
-and normalize it. The header can include more specific preferences and look
-something like: `Accept-Language: fr-ca, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5`.
-There are 2 things going on here. 1) A user can specify country/region variants
-for a language - `fr-ca` (French - Canada) and `fr-fr` (French - France). For
-simplicity's sake, we want to normalize that sort of preference to `fr` to
-start. 2) A user can specify priority using the q argument. We'll want to
-interpret the user's priority preferences to match their highest priority
-language with one we currently support.
-
-Once the edge is aware of what language it should be looking for, it will set
-the cache key accordingly.
-
-We also make use of fragment caching in several places. We need to update the
-keys for those caches to account for `locale` so we're not mistakenly serving a
-cached fragment in a different language than intended.
-
-## Additional considerations
-
-- _Translating URLs_. For the best SEO result, we should also translate URLs
- themselves into various languages. Something like the `/about` page could be
- translated, for example. For now, we aren't going to account for this.
-- _Translating dynamic/user generated content_. For now, we plan to _not_
- automatically translate any dynamic/user generated content (articles,
- comments, listings, etc.). In the future we could explore what that looks
- like, how a user can opt-in/out of that, etc.
-
-## Styles, design, and UI
-
-We'll want to expand some design aspects to support other languages that may be
-right-to-left, have different spacings, have special characters, etc.
-
-## Next steps
-
-A few next steps we can take on the road to internationalization.
-
-- Update our logic to allow special characters/encodings in URLs. Currently, we
- generate slugs on dynamic content like articles and tags that may include
- characters that make the URL
- invalid.[Here](https://github.com/forem/forem/issues/10116) is a good example.
- We want to update this logic so these characters work in URLs as expected.
-- Allow Forem Admins to set a "default language". Currently, if a user doesn't
- select a language preference, it defaults to English ("en").
-- Clean up some code. There are some places we're hard-coding strings on the
- frontend. We'll want to explore moving that sort data to the backend to unify
- where and how we're translating.
-- Translate areas of the site into English (US) first to ensure things are still
- working. In other words, have the platform adhere to the default locale
- instead of hard-coded strings.
-- Start translating!
-
-## Resources
-
-- [Rails Guides - Rails Internationalization (I18n)](https://guides.rubyonrails.org/i18n.html)
-- [i18n-tasks](https://glebm.github.io/i18n-tasks/)
-- [Google: Managing multi-regional and multilingual sites](https://support.google.com/webmasters/answer/182192)
-- [forem.dev post: What internationalization features should we support?](https://forem.dev/vaidehijoshi/what-internationalization-features-should-we-support-4kl)
diff --git a/docs/backend/metrics.md b/docs/backend/metrics.md
deleted file mode 100644
index 1af7c6292..000000000
--- a/docs/backend/metrics.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Metrics
----
-
-## Time series data
-
-We track point-in-time data by sending data points to Datadog using
-[Statdsd](https://github.com/DataDog/dogstatsd-ruby).
-
-Currently, we run a daily metric fetching job in `fetch.rake` which is called
-via the Heroku scheduler. If we wanted to do other frequencies like hourly, etc.
-we could add similar tasks.
-
-The rake task calls `Metrics::RecordDailyUsageWorker.perform_async`, which
-performs algorithms to come up with data points to send, for example:
-
-```ruby
-DataDogStatsClient.count("users.active_days_past_week", one_day_users, tags: { resource: "users", group: "new_users, day_count: 1 })
-```
-
-If you want to create a new periodic data send, follow this pattern to do so.
-
-## Vendor-Agnostic
-
-While we currently are not vendor-agnostic in how we do this (Heroku/Datadog),
-it is set up in a way that could become so in the future. The main pattern is
-`Every x minutes/hours/etc. send aggregate data to warehouse where it can be examined on a timeseries basis`.
-This could, in the future, be bundled right into the platform using an open
-source timeseries database and data visualization.
-
-Once in Datadog, dashboards can created using
-
-
diff --git a/docs/backend/notification.md b/docs/backend/notification.md
deleted file mode 100644
index 21352a8bb..000000000
--- a/docs/backend/notification.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Notifications
----
-
-# Notifications
-
-Since notifications are run asynchronously, we'll want to make sure jobs are
-running: `bundle exec sidekiq`. If that's not running, you won't receive any
-notifications. You might need to create another account to pass notifications
-back and forth if you're doing this all through the UI.
-
-Otherwise, you can generate notifications from the Rails console and run the
-class methods from `app/models/notification.rb`. For example:
-
-```ruby
-# follow notification
-me = User.last
-follow = User.first.follow(me)
-Notification.send_new_follower_notification_without_delay(follow)
-# reaction notification
-rxn = Reaction.create(
-user_id: 1,
-category: "like",
-reactable: me.articles.last, # this assumes you have an article written
-)
-Notification.send_reaction_notification_without_delay(rxn, me)
-```
-
-Notice you have to run these methods `without_delay` since this is assuming jobs
-are not running.
diff --git a/docs/backend/push-notifications.md b/docs/backend/push-notifications.md
deleted file mode 100644
index 48e014efe..000000000
--- a/docs/backend/push-notifications.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Push Notifications
----
-
-# Push Notifications Delivery
-
-Forem instances rely on [Rpush](https://github.com/rpush/rpush) to deliver push
-notifications. This decision was heavily influenced by the desire to provide as
-much flexibility as possible to Creators. In order to do this, Forem instances
-can register and configure a `ConsumerApp`.
-
-These consumer apps represent mobile applications that users use to browse and
-consume content on a Forem. Authenticated users of a specific Forem instance can
-register a `Device` associated to a `ConsumerApp`. With these pieces we are able
-to deliver push notifications to users devices.
-
-The `ConsumerApp` configuration page can be found at
-`/admin/apps/consumer_apps`. The official Forem apps are supported by default
-and require their secret credential to be provided via ENV variable.
-
-## Rpush Implementation
-
-We use Rpush's `rpush-redis` implementation (read
-[this thread](https://github.com/forem/forem/pull/12419/files#r564660917) for
-the reasons why), hence all `Rpush` models are persisted in Redis. More details
-about how this works [here](https://github.com/rpush/rpush/wiki/Using-Redis).
diff --git a/docs/backend/pusher.md b/docs/backend/pusher.md
deleted file mode 100644
index 4b066f96e..000000000
--- a/docs/backend/pusher.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Pusher
----
-
-# Pusher for Realtime Notifications
-
-Pusher is a third party service being used to power the
-[chat system](https://dev.to/connect) and Push Notifications on
-[iOS](https://apps.apple.com/us/app/dev-community/id1439094790) &
-[Android](https://play.google.com/store/apps/details?id=to.dev.dev_android)
-native apps.
-
-## Chat System
-
-In order to use the chat functionality within your development environment, you
-will need to sign up for a free-tier Pusher account and retrieve its keys. Then
-you'll need to provide those keys to the Rails application.
-
-1. [Sign up](https://dashboard.pusher.com/accounts/sign_up) or
- [sign in](https://dashboard.pusher.com/) to your Pusher account.
-
-2. Once signed in, fill in the prompt to create a new Pusher Channels app.
-
- 
-
-3. In your new Pusher Channels app, click the "App Keys" tab.
-
- 
-
-4. Change your keys accordingly (name of Pusher key -> name of our application
- key):
-
- ```text
- app_id -> PUSHER_APP_ID
- key -> PUSHER_KEY
- secret -> PUSHER_SECRET
- cluster -> PUSHER_CLUSTER
- ```
-
- 
-
-5. Done.
diff --git a/docs/backend/readme.md b/docs/backend/readme.md
deleted file mode 100644
index d09a2e2d7..000000000
--- a/docs/backend/readme.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Backend Guide
-items:
- - audit-log.md
- - authentication.md
- - auth-apple.md
- - auth-facebook.md
- - auth-twitter.md
- - auth-github.md
- - authorization.md
- - configuration.md
- - data-update-scripts.md
- - emails.md
- - fastly.md
- - internationalization.md
- - roles.md
- - pusher.md
- - resource-admin.md
- - notification.md
- - scheduled-jobs.md
- - metrics.md
- - push-notifications.md
- - tracking.md
- - service-objects.md
----
-
-# Backend Guide
diff --git a/docs/backend/roles.md b/docs/backend/roles.md
deleted file mode 100644
index ba483e874..000000000
--- a/docs/backend/roles.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Roles
----
-
-# Roles
-
-## What is a role?
-
-If authorization is about who has permission to be allowed to do what you want
-to do, then Roles are common patterns of authorization across users - reducing
-the administrative overhead.
-
-## Why do I need to know about roles?
-
-Some bugs can only be seen for users with specific roles. You will need to
-change the role to reproduce a problem.
-
-## How do we implement roles in Forem?
-
-Roles are implemented in this application using [Rolify][1]. The list of roles
-can be found in [app/models/role.rb][2] and you can search for [has_role in the
-codebase][3] to find which pages need which roles.
-
-A new user starts without any roles, and there is no administrative way of
-adding roles to users yet. To assign a user a role you will have to run commands
-at the console.
-
-## Example of adding permissions to a user
-
-- open the Rails console
-
-```shell
-rails console
-```
-
-- after verifying the user `test_user_name` is missing the `trusted` role we
- proceed to add it and then verify the role has been added:
-
-```ruby
-> user = User.find_by(username: "test_user_name")
-> user.has_role?(:trusted)
-=> false
-
-> user.add_role(:trusted)
-=> #
-
-> user.has_role?(:trusted)
-=> true
-```
-
-Another common requirement is changing to the administrative role, and an
-example of this is found [on the admin page][5].
-
-## Verification
-
-A more complex query to list all the users and their roles:
-
-```ruby
-User.joins(:roles).order(:id).group(:id).pluck(:id, :username, Arel.sql("array_agg(roles.name)"))
-```
-
-## Further Reading
-
-1. [Rolify README.md][1]
-2. [What is the purpose of Rolify?][4]
-3. [Admin][5]
-
-[1]: https://github.com/RolifyCommunity/rolify
-[2]: https://github.com/forem/forem/blob/main/app/models/role.rb
-[3]: https://github.com/forem/forem/search?q=has_role&unscoped_q=has_role
-[4]: https://stackoverflow.com/a/16096790/1511504
-[5]: /backend/resource-admin
diff --git a/docs/backend/scheduled-jobs.md b/docs/backend/scheduled-jobs.md
deleted file mode 100644
index e92c2b163..000000000
--- a/docs/backend/scheduled-jobs.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Scheduled Jobs
----
-
-# Scheduled Jobs
-
-As in the [Technical Overview](/technical-overview), We use
-[Heroku Scheduler](https://devcenter.heroku.com/articles/scheduler) for
-scheduled jobs. As the name suggests, this is for regularly recurring tasks that
-need to be run every day, week, month, year, decade, and century.
-
-Tasks are implemented in `forem/lib/tasks/fetch.rake`, typically in the form of:
-
-```
-task some_unique_task_name:, [optional_arg] => :environment do |optional_arg|
- ... do your thing here ...
-end
-```
-
-You can explore the
-[official Heroku documentation](https://devcenter.heroku.com/articles/scheduler#defining-tasks)
-for defining tasks and read through tasks we have implemented for busting cache,
-awarding badges, and more.
-
-In your Pull Request, communicate with a Forem Core Team Member to discuss at
-what frequency and ensure your task is scheduled on Heroku once your code is
-reviewed, approved, and merged.
diff --git a/docs/backend/service-objects.md b/docs/backend/service-objects.md
deleted file mode 100644
index e71bef3ce..000000000
--- a/docs/backend/service-objects.md
+++ /dev/null
@@ -1,114 +0,0 @@
----
-title: Service Objects
----
-
-## What are Service Objects
-
-Service objects are Plain Old Ruby Objects (POROs) which encapsulate a whole
-business process/user interaction.
-
-Our services are located in `app/services` with the corresponding specs in
-`spec/services`. Their main interface is a class level method named `call`, as
-in the following example:
-
-```ruby
-class ImportUsers
- def self.call(arg1)
- new(arg1).call
- end
-
- def initialize(arg1)
- @arg1 = arg1
- end
-
- def call
- # import code goes here
- end
-end
-```
-
-To distinguish services from models we often give them verb names vs noun names,
-e.g. `ImportUsers` instead of `UserImporter`.
-
-## Generating Service Objects
-
-To make our services more consistent we use a custom Rails generator. Some usage
-examples:
-
-**Generate a non-namespaced service without arguments**
-
-`$ rails generate service DoTheThing`
-
-```ruby
-# app/services/do_the_thing.rb
-class DoTheThing
- def self.call
- new.call
- end
-
- def call
- end
-end
-```
-
-```ruby
-# spec/services/do_the_thing_spec.rb
-require "rails_helper"
-
-RSpec.describe DoTheThing, type: :service do
- pending "add some examples to (or delete) #{__FILE__}"
-end
-```
-
-**Generate a non-namespaced service with arguments:**
-
-`$ rails generate service DoTheThing arg1 arg2`
-
-```ruby
-# app/services/do_the_thing.rb
-class DoTheThing
- def self.call(arg1, arg2)
- new(arg1, arg2).call
- end
-
- def initialize(arg1, arg2)
- @arg1 = arg1
- @arg2 = arg2
- end
-
- def call
- end
-end
-```
-
-The generated spec is the same as above.
-
-**Generate a namespaced service with arguments**
-
-`$ rails generate service things/dothem arg1 arg2`
-
-```ruby
-# app/services/things/do_them.rb
-class Things::DoThem
- def self.call(arg1, arg2)
- new(arg1, arg2).call
- end
-
- def initialize(arg1, arg2)
- @arg1 = arg1
- @arg2 = arg2
- end
-
- def call
- end
-end
-```
-
-```ruby
-# spec/services/things/do_them_spec.rb
-require "rails_helper"
-
-RSpec.describe Things::DoThem, type: :service do
- pending "add some examples to (or delete) #{__FILE__}"
-end
-```
diff --git a/docs/backend/tracking.md b/docs/backend/tracking.md
deleted file mode 100644
index 9c5a5a03d..000000000
--- a/docs/backend/tracking.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Tracking
----
-
-## Visits & Events
-
-For first-party analytics, we use the
-[`ahoy_matey` gem](https://github.com/ankane/ahoy), which tracks visits and
-events.
-
-We intentionally choose to limit what user data we track and persist, and have
-opted to follow the GDPR compliance standards
-[set by Ahoy](https://github.com/ankane/ahoy#gdpr-compliance-1). By default, we
-have configured the Ahoy library to mask IP addresses, disable geocode tracking,
-and not track user cookies.
-
-### Visits
-
-Ahoy creates an `Ahoy::Visit` record for each visit that it tracks.
-
-By default, we have turned off visit tracking in the `ApplicationController`:
-
-```ruby
-skip_before_action :track_ahoy_visit
-```
-
-We currently only create visits on the server-side when they are required to be
-created by events. Visits can be re-enabled for specific controller actions if
-necessary, but this should be done so _with explict care_.
-
-We do not collect any personal user data when tracking visits. Our collected
-data is limited to the user's `id`. Each user has a unique `visitor_token`,
-while each visit to the site is marked with a unique `visit_token`.
-
-### Events
-
-Ahoy creates an `Ahoy::Event` record for each event that it tracks. If no visit
-is recorded for a user when an event is tracked, Ahoy will simultaneously create
-an `Ahoy::Visit` for the event being tracked.
-
-Events can be tracked in a controller action on the backend, or with JavaScript
-on the frontend. Learn more about tracking events with JavaScript in our
-[frontend tracking guide](/frontend/tracking).
-
-When an event is tracked, it should include a `name` and a `properties` hash.
-When adding new events, be sure that the name is unique per-event. The
-properties will help you differentiate between events.
-
-In order to track a specific event in a controller, use the `ahoy.track` call:
-
-```ruby
-class YourController < ApplicationController
- after_action :track_my_action
-
- protected
-
- def track_my_action
- ahoy.track "A specific description of your event", request.path_parameters
- end
-end
-```
-
-Event tracking can be enabled for specific controller actions, but should be
-done so _with explict care_.
-
-## Messages
-
-For email analytics, we use the
-[`ahoy_messages` gem](https://github.com/ankane/ahoy_email), which tracks a
-history of email messages sent to users.
-
-Ahoy creates an `Ahoy::Message` record for each email sent by default, but can
-be disabled on a per-mailer basis.
diff --git a/docs/contributing/api.md b/docs/contributing/api.md
deleted file mode 100644
index 28104cb48..000000000
--- a/docs/contributing/api.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Contributing to the API Specification Docs
----
-
-# Contributing to API specification docs
-
-The API v0 is described with the
-[OpenAPI 3 specification](https://spec.openapis.org/oas/v3.0.3).
-
-Swagger.io has
-[great docs](https://swagger.io/docs/specification/basic-structure/) that are
-helpful to understand the specification better.
-
-## Where you can find the spec file
-
-We auto-generate the documentation from `api_v0.yml` within the `/docs`
-directory. We use [ReDoc](https://github.com/Redocly/redoc) to turn the OpenAPI
-3 format into a readable and searchable HTML documentation.
-
-## Updating API docs
-
-Whenever you make changes to the API docs, make sure to bump the version at the
-top of `api_v0.yml`, in `info.version`.
-
-## Running and editing the docs locally
-
-If you want to browse the documentation locally you can use:
-
-```shell
-yarn api-docs:serve
-```
-
-This will let you browse the auto-generated version of the doc locally, and it
-will reload the documentation after every change of the specification file.
-
-## Linting and validation
-
-We use [spectral](https://github.com/stoplightio/spectral) and
-[ibm-openapi-validator](https://github.com/IBM/openapi-validator) to validate
-the spec file. The validation is performed as a `pre-commit` hook.
-
-You can also manually validate the document, running:
-
-```shell
-yarn api-docs:lint
-```
-
-If you have Visual Studio Code, we suggest you install the following extensions
-that enable validation and navigation within the spec file:
-
-- [OpenAPI (Swagger) editor](https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi)
-- [openapi-designer live preview](https://marketplace.visualstudio.com/items?itemName=philosowaffle.openapi-designer)
diff --git a/docs/contributing/docs.md b/docs/contributing/docs.md
deleted file mode 100644
index e855b9ec9..000000000
--- a/docs/contributing/docs.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: Contributing to the Docs
----
-
-# Contributing to Forem's developer documentation
-
-Contributions to the documentation are always appreciated! Thank you for making
-an effort to improve the developer experience of contributing to the DEV
-project.
-
-# Running the documentation locally
-
-Like Forem, this site is open source and the code is [hosted on GitHub][docs].
-If you find any incorrect information, or a even a typo, we'd love to see a pull
-request. Follow these steps to get the documentation site running locally.
-
-Forem's documentation is built with [GitDocs NodeJS library][gitdocs].
-
-Once installed, you should run `yarn gitdocs serve` from the root of the `forem`
-project or from the `/docs` directory.
-
-```shell
-yarn gitdocs serve
-```
-
-This will start a server where you can browse the documentation:
-
-
-If you add new pages or rename existing pages, you'll need to restart the server
-for those changes to take effect.
-
-Since our documentation is built on GitDocs, which is built on Netlify, you can
-use the generated deploy preview link to check out your documentation changes.
-Once you make a PR, click on "Show all checks" and find the "deploy/netlify"
-row. If your deploy preview is ready, you can click on "Details" to see the
-preview. Please note that the deploy preview only reflects any documentation
-changes you make (and not any changes elsewhere in the app).
-
-# Useful links
-
-The docs are a collection of [Markdown files][markdown] that also utilize
-[FrontMatter][frontmatter].
-
-For more information on how to use GitDocs read the [GitDocs
-guide][gitdocs_guide].
-
-# Regarding language & style
-
-We ask that you avoid trivializing terms when contributing to documentation.
-This includes words like "just", "simply", "easy", "obvious", and
-"straightforward". You can learn more about why we want to avoid this kind of
-language in [this blog post](https://jessitron.com/2020/06/26/just-dont).
-
-Generally speaking, the documentation hosted on this site is informal. There is
-no need to make things more complicated by writing these articles like a
-textbooks.
-
-However, it's expected that contributions to these documents are reasonably
-structured and mostly free of spelling and grammar errors. For this reason, if
-you submit a PR you might be asked to make changes before your PR is merged.
-
-Prettier is used to autowrap lines in these files to 80 characters. Using 80
-characters per line allows us to retain a more specific git history over time.
-If lines are not wrapped, changing a comma in a paragraph would attribute the
-entire paragraph to one commit. By line wrapping we are helping git to correctly
-attribute smaller changes to their commits. This keeps information from getting
-lost over time.
-
-For more information on effective technical writing, check out
-[writethedocs.org][writethedocs].
-
-[docs]: https://github.com/forem/forem/tree/main/docs/
-[gitdocs]: https://www.npmjs.com/package/gitdocs/
-[markdown]: https://en.wikipedia.org/wiki/Markdown
-[frontmatter]: https://jekyllrb.com/docs/front-matter/
-[gitdocs_guide]: https://gitdocs.netlify.com/
-[writethedocs]: https://www.writethedocs.org/guide/
diff --git a/docs/contributing/forem.md b/docs/contributing/forem.md
deleted file mode 100644
index 470747a54..000000000
--- a/docs/contributing/forem.md
+++ /dev/null
@@ -1,202 +0,0 @@
----
-title: Contributing to Forem
----
-
-# Contributing to Forem
-
-We expect contributors to abide by our underlying
-[Code of Conduct](https://dev.to/code-of-conduct). All discussions about this
-project must be respectful and harassment-free.
-
-Remember that communication is the lifeblood of any Open Source project. We are
-all working on this together, and we are all benefiting from this software.
-
-It's very easy to misunderstand one another in asynchronous, text-based
-conversations. When in doubt, assume everyone has the best intentions.
-
-If you feel anyone has violated our Code of Conduct, you should anonymously
-contact the team with our [abuse report form](https://dev.to/report-abuse).
-
-### Where to contribute
-
-All [issues](https://github.com/forem/forem/issues) labeled
-[ready for dev](https://github.com/forem/forem/issues?q=is%3Aissue+is%3Aopen+label%3A%22ready+for+dev%22)
-and
-[bug](https://github.com/forem/forem/issues?q=is%3Aissue+is%3Aopen+label%3A%22type%3A+bug%22+label%3Abug)
-are up for grabs. Please note that issues with the
-[Forem team](https://github.com/forem/forem/labels/Forem%20team) label are
-internal tasks that will be completed by a Forem
-[core team member](https://github.com/forem/forem/#core-team).
-
-- [good first issue](https://github.com/forem/forem/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+)
- issues are meant for newer developers.
-- [difficulty: easy](https://github.com/forem/forem/issues?q=is%3Aopen+is%3Aissue+label%3A%22difficulty%3A+easy%22)
- issues are usually confined to isolated areas of existing code.
-- [difficulty: medium](https://github.com/forem/forem/issues?q=is%3Aopen+is%3Aissue+label%3A%22difficulty%3A+medium%22)
- issues sometimes entail new features and might affect a significant area of
- the codebase, but aren't overly complex.
-- [difficulty: hard](https://github.com/forem/forem/issues?q=is%3Aopen+is%3Aissue+label%3A%22difficulty%3A+hard%22)
- issues are typically far-reaching, and might need architecture decisions
- during implementation. This label might also denote highly complex issues.
-
-PRs without an associated issue may still be merged, but the core team will
-focus on changes that solve existing issues. We strongly encourage creating an
-issue before working on a PR!
-
-When in doubt, ask a
-[core team member](https://github.com/forem/forem/#core-team) by mentioning us
-on the issue.
-
-**Documentation** is almost always a great place to start contributing to a new
-project. Forem is an Open Source, community-driven project. Therefore, providing
-and maintaining quality documentation is one of our most important jobs. You can
-find more information in our
-[docs guide](https://docs.forem.com/contributing/docs)!
-
-**Refactoring**, which involves improving the code without modifying behavior,
-is a great place to help out! Generally speaking, you can rely on existing tests
-to ensure that your refactor doesn't introduce any unexpected behavior. If an
-area isn't well tested, you might be asked to include a regression test with
-your refactoring PR. Refactors can touch many files, so we encourage breaking
-big changes into small PRs.
-
-**Fixing bugs** is a super fast way to improve the experience for our users!
-When you're fixing bugs, we appreciate communication in a GitHub issue. If an
-issue exists, please claim that issue and link it in your PR, otherwise creating
-an issue is the best first step! Be sure to surround bug fixes with ample tests;
-bugs are magnets for other bugs. Write tests around bugs!
-
-**Features** tend to be subjective and might spur some debate. The Forem core
-team uses an internal RFC ("request for comments") process to assess and
-prioritize new features. This process is intended to provide a consistent and
-standardized path for new changes to enter the Forem ecosystem. If you'd like to
-propose a new feature, please visit [forem.dev](https://forem.dev) to start a
-discussion around a new feature (or chime in on a pre-existing discussion!).
-
-There may be some open issues in our repository that we think evolve into
-impactful features. For such issues, we use the
-[potential RFC](https://github.com/forem/forem/labels/potential%20RFC) label in
-order to highlight the potential feature to the Forem core team members so that
-someone from the team can champion that feature.
-
-You can learn more about our internal RFC process and how we use forem.dev
-[here](https://forem.dev/foremteam/internal-rfc-process-and-forem-dev-discussions-3gl4)
-
-### How to contribute
-
-1. [Fork the project](https://docs.forem.com/getting-started/forking/) and clone
- it to your local machine. Follow the
- [installation guide](https://docs.forem.com/installation/)!
-2. Create a branch with your GitHub username and the ID of the
- [issue](https://github.com/forem/forem/issues), for example:
- `git checkout -b USERNAME/some-new-feature-1234`
-3. Code and commit your changes. Bonus points if you write a
- [good commit message](https://chris.beams.io/posts/git-commit/):
- `git commit -m 'Add some feature'`
-4. Push to the branch: `git push -u origin USERNAME/some-new-feature-1234`
-5. [Create a pull request](https://docs.forem.com/getting-started/pull-request/)
- for your branch. 🎉
-
-## Contribution guidelines
-
-### Create an issue
-
-Nobody's perfect. Something doesn't work? Something could be better? Check to
-see if the issue already exists, and if it does, leave a comment to get our
-attention! If the issue doesn't already exist, feel free to create a new one. A
-core team member will triage incoming issues.
-
-_Please note: core team members may update the title of an issue to reflect the
-discussion._
-
-### Please include tests
-
-Some areas of the project could use updated tests, and new features should
-always include test coverage. Please give our
-[testing guide](https://docs.forem.com/tests/) a read!
-
-### Code quality
-
-We use [Code Climate](https://codeclimate.com/) to find code smells. If a pull
-request contains code smells, we might recommend a refactor before merging. We
-like readable code, and encourage DRY when it's reasonable!
-
-More importantly, we avoid
-[wrong abstractions](https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction).
-Code quality tools are not perfect, so don't obsess over your Code Climate
-score.
-
-### Consider accessibility in UI changes
-
-If the change you're proposing touches a user interface, include accessibility
-in your approach. This includes things like color contrast, keyboard
-accessibility, screen reader labels, and other common requirements. For more
-information, check out the
-[Forem Accessibility docs page](https://docs.forem.com/frontend/accessibility).
-
-### Please use inclusive language
-
-Inclusion and respect are core tenets of our
-[Code of Conduct](https://dev.to/code-of-conduct). We expect thoughtful language
-all the way down to the code. Some technical metaphors are alienating or
-triggering. We ask that contributors go the extra mile to submit code which is
-inclusive in nature.
-
-If you unintentionally use language deemed harmful, there is no shame. We will
-work together to find a better alternative. Being thoughtful about language also
-encourages more thoughtful code!
-
-### Create a pull request
-
-- Try to keep the pull requests small. A pull request should try its very best
- to address only a single concern.
-- For work in progress pull requests, please use the
- [Draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/)
- feature.
-- Make sure all tests pass and add additional tests for the code you submit.
- [More info here](https://docs.forem.com/tests/).
-- Document your reasoning behind the changes. Explain why you wrote the code in
- the way you did. The code should explain what it does.
-- If there's an existing issue, reference to it by adding something like
- `References/Closes/Fixes/Resolves #123`, where 123 is the issue number.
- [More info here](https://github.com/blog/1506-closing-issues-via-pull-requests).
-- Please fill out the PR Template when making a PR.
-- All commits in a pull request will be squashed when merged.
-
-_Please note: a core team member may close your PR if it has gone stale or if we
-don't plan to merge the code._
-
-### Pull request reviews
-
-All community pull requests are reviewed by our core team.
-
-- All contributors must sign the CLA.
-- All required checks are expected to pass on each PR.
- - In the case of flaky or unrelated test failures, a core team member will
- restart CI.
-- We require 2 approvals from core team members for each PR.
-- Requested Changes must be resolved (with code or discussion) before merging.
-- If you make changes to a PR, be sure to re-request a review.
-- Style discussions are generally discouraged in PR reviews; make a PR to the
- linter configurations instead.
-- Your code will be deployed shortly after it is merged.
-
-### A note on "force pushing"
-
-After you submit your pull request, one of the members of the core team will
-review your code.
-
-Please avoid force pushing unless you need to rebase with the main branch.
-
-If feedback is provided, any changes should be contained in new commits. Please
-don't force push or worry about squashing your commits.
-
-Force pushing (despite being useful) has some drawbacks. GitHub doesn't always
-keep the review history, which results in lost context for the reviewers.
-
-We squash every PR before merging, so there is no need to force push!
-
-## The bottom line
-
-We are all humans trying to work together to improve the community. Always be
-kind and appreciate the need for tradeoffs. ❤️
diff --git a/docs/contributing/readme.md b/docs/contributing/readme.md
deleted file mode 100644
index 9397e6c43..000000000
--- a/docs/contributing/readme.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: Contributing Guide
-items:
- - docs.md
- - forem.md
- - api.md
----
-
-# Contributing Guide
diff --git a/docs/creators/configure-forem.md b/docs/creators/configure-forem.md
deleted file mode 100644
index 53060fb2c..000000000
--- a/docs/creators/configure-forem.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: Configuring Forem
----
-
-# Basic Configuration Guide for Forem
-
-## Overview
-
-As a Forem admin, one of the first steps of managing your site will be to tailor
-your content, branding and other important details based on your community
-goals. This is made simple by the configuration page which can be found at
-https://your.forem.url/admin/customization/config.
-
-_We advise that you first complete the minimum set up before sending out your
-Forem link to your community._
-
-## Complete your Set Up, Configure your Forem
-
-Once your Forem instance is set up for the first time, you will most likely see
-the following banner:
-
-
-
-This banner indicates that the Forem configuration process hasn't been completed
-yet.
-
-When you click on the link on banner, it will take you to the configuration page
-(i.e. https://your.forem.url/admin/customization/config).
-
-On this page you will see that the Get Started section is expanded. It contains
-all the mandatory fields that need to be filled out in order for the site to be
-in a usable state. Once it is filled out and submitted, the banner will then
-disappear.
-
-## Access and Permissions
-
-The following permissions are required to be able to view and/or edit the config
-page:
-
-#### `Role: super_admin`
-
-When providing this role to a user they will be able to access the config page.
-However, this page will be a read only view for them. They will see the
-following:
-
-
-
-#### `Role: single_resource_admin`
-
-When providing this role to a user they will be able to access the config page,
-and they will be able to edit the config variables.
-
-
-
-The first admin of your Forem will be given the highest permissions. Thereafter,
-they can provide the necessary permissions to subsequent users via the
-https://your.forem.url/admin/permissions.
-
-## The Configuration Sections
-
-Currently, the configuration page is split into 3 sections. They are as follows:
-
-- A **Get Started section** that contains all required fields. These are the
- fields that are required to be filled out, in order to get your Forem in a
- usable state.
-- An **All Settings section** that contains all the possible variables that you
- can configure on the site. This section is broken down into sub sections,
- whereby each subsection will contain a description of what it does, and then
- list the fields that are available for configuration. Each field will also
- contain a concise description of what it is used for.
-- An **Environment Variables section** that provides a read-only view of the
- environment variables that are available to be set on the server. If your
- instance is hosted by Forem, please get in touch with customer support to
- change any of these variables.
-
-
-
-All required fields are marked as such. In addition, you will notice that we
-have set some defaults for certain fields, you may amend them as you see
-relevant for your Forem.
-
-## Updating your configurations
-
-In order to update any of the variables within the Get Started and All Settings
-sections, you will set the new value and then navigate to the end of the section
-where you will verify that you would like to make the change by typing the
-following sentence:
-
-```
-My username is and this action is 100% safe and appropriate.
-```
-
-You will now see your updated values and the changes on your site will be in
-effect.
-
-
diff --git a/docs/creators/readme.md b/docs/creators/readme.md
deleted file mode 100644
index 8e81498ea..000000000
--- a/docs/creators/readme.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: Forem Creators Guide
-items:
- - configure-forem.md
----
-
-# Forem Creators Guide
-
-This document contains basic instructions for new Forem creators. It's a work in-progress, but will provide Forem Creators with a guide on how to best make use of the tools and features available to them.
diff --git a/docs/design/branding.md b/docs/design/branding.md
deleted file mode 100644
index 126705b15..000000000
--- a/docs/design/branding.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Branding Guidelines
----
-
-# Branding Guidelines
-
-## Forem Theme
-
-Forem's design inspiration is meant to be a throwback. In personality and
-design, it is ATARI inspired. Magazines like PAPER are also an inspiration in
-terms of being a
-[bold contrast with some more indy](https://www.google.com/search?biw=1440&bih=780&tbm=isch&sa=1&ei=KSN8W5WVLoy55gLI77TgBA&q=paper+magazine+cover&oq=paper+magazine+cover).
-
-We also think in terms of how people use the Forem brand for their own purposes.
-Profiles are very much public-facing records of what people have put out into
-the world. `dev.to/{username}` is your developer identity.
-
-Imagine a developer's face with the DEV heading above them. If we existed in the
-80's, we would have been "DEV MAGAZINE," with the exact same branding.
-
-## Branding Rules
-
-- [Joystick](http://www.pixelsagas.com/?download=joystick) should be used for
- logos, not for headlines/phrases.
-- Black and white is our default logo, but the logo can be drawn in any color.
-- Forem/DEV is "old school cool."
-- We use bold shadows (no gradient) for boxes.
-- We have a minimal approach to importing dependencies, so few if any custom
- fonts on-site for that reason.
-- Refer to the `variables.scss`
- [file in our main repo](https://github.com/forem/forem/blob/main/app/assets/stylesheets/variables.scss)
- to reference commonly-used colors and fonts.
-
-## Design License Info
-
-- We use the [Joystick](http://www.pixelsagas.com/?download=joystick) font by
- Neale Davidson and [Pixel Sagas](http://www.pixelsagas.com/) for the DEV Logo.
- We have a commercial license.
-- We use [EmojiOne](https://www.emojione.com/) icons from JoyPixels. We have a
- commercial license.
diff --git a/docs/design/language.md b/docs/design/language.md
deleted file mode 100644
index d78c1f4e1..000000000
--- a/docs/design/language.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Human Language
-
-Forem is built on concepts, and those concepts have names. Here are some language concepts to be aware of and some known "gotchas" where there may be multiple terms currently being used.
-
-This is an incomplete first take. It is also written down _so that it can be changed when needed._ No language concept is set in stone. And no concept is exclusively _english_. As we internationalize we need to evolve our notion of this, and it will remain important that we settle on unified terms so that we limit conceptual sprawl.
-
-# Post
-
-A main published unit on sites are officially called posts. The gotcha is that they are currently called `Article` in the codebase. This is because the original version of the site had much more the concept of the pure "article" but as the site has evolved and the purposes of Forem have evolved, we have diversified the use of a post idea. Just as a "tweet" could be used for different things: An announcement, a question, the start of a thread, etc. we also have a broad idea of what a post is "for", and all concepts are built off of this.
-
-# Comment
-
-A single comment is the unit of follow up dialog that lives underneath a post. Comments have some associated terminology.
- - A Discussion is the collection of all comments under a post. Discussion is a word that implies a certain civility.
- - A thread is a single line of comments and their reply comments within a full discussion.
- - A comment within a thread may be thought of as a "reply" contextually, but it is still a comment.
-
-# Reaction
-
-The remotional responses to an article or comment, a click of a button to let the author know how one feels. The phrase "reaction" is used in the app, but should mostly be _implied_. Reactions are purposefully lightweight in nature.
-
-# Tag
-
-A tag is the main unit of organized content on a Forem.
-
-# User
-
-A signed up account is generically referred to as a "user", but contextually we've called them "members" or "people", there may be some need for unification here.
-
-# Listing
-
-The marketplace/classified-listing concept within a forem is called `/listings` and a single unit is a listing. Listings have categories for segmentation as well as tags, like posts do.
-
-# Connect
-
-Connect is the area of the site for synchronous conversation, closed group chat and/or video or audio conversation. It's generally not as site-wide or public, though they _can_ be public in some contexts.
-
-# Connect Channel
-
-A single unit of chat is called a "channel".
-
diff --git a/docs/design/readme.md b/docs/design/readme.md
deleted file mode 100644
index 46c44423c..000000000
--- a/docs/design/readme.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: Design Guide
-items:
- - branding.md
- - language.md
- - theming.md
----
-
-# Design Guide
diff --git a/docs/design/theming.md b/docs/design/theming.md
deleted file mode 100644
index 7d00d5bfb..000000000
--- a/docs/design/theming.md
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: Theming Guidelines
----
-
-# Theming Guidelines
-
-Forem supports different themes, such as Default, Night, Pink.
-
-You can switch the theme at in the "Style
-Customization" section.
-
-These themes are powered by
-[CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties),
-loaded at runtime by JavaScript via `layouts/_user_config.html.erb`.
-
-An example of how it works:
-
-```javascript
-try {
- const bodyClass = localStorage.getItem('config_body_class');
-
- if (bodyClass) {
- document.body.className = bodyClass;
-
- if (bodyClass.includes('night-theme')) {
- document.getElementById('body-styles').innerHTML = '';
- } else if (bodyClass.includes('ten-x-hacker-theme')) {
- document.getElementById('body-styles').innerHTML = ''
- } else if (bodyClass.includes('pink-theme')) {
- document.getElementById('body-styles').innerHTML = ''
- } else if(bodyClass.includes('minimal-light-theme')) {
- document.getElementById('body-styles').innerHTML = ''
- }
- ...
-```
-
-Within SCSS files located at `app/assets/stylesheets` you can use `var()`
-statements, which will call these CSS custom properties. If a CSS custom
-property is not defined `var()` will fall back on the second parameter provided,
-which can be a SCSS variable defined in `app/assets/stylesheets/variables.scss`.
-
-An example of how to use `var()`:
-
-```scss
-div {
- color: var(--theme-color, $black);
-}
-```
-
-Note that fallback values aren't used to fix the browser compatibility. If the
-browser doesn't support CSS custom Properties, the fallback value won't help. To
-prevent this issue on older browsers, we need to write our styles like this:
-
-```scss
-div {
- color: $black;
- color: var(--theme-color, $black);
-}
-```
-
-This can be too much work and browser fallback can be forgotten. For a better
-developer experience, you should use the two mixins defined in
-`app/assets/stylesheets/_mixins.scss` called `themeable` and
-`themeable-important`. They take three arguments. The first argument is the CSS
-property like `color` or `background`, the second argument is the CSS custom
-property name (without `--`) like `theme-color`, and the third argument is the
-CSS value, i.e., `$black` or `white`.
-
-Make sure to import the mixin in your SCSS file and use it like this:
-
-```scss
-div {
- @include themeable(color, theme-color, $black);
-}
-```
-
-`themeable-important` is used when a CSS variable requires `!important` as a
-postfix of the CSS property's value where the CSS variable is being used. You
-can use it the same way you would use `themeable` mixin, but you should avoid
-`!important` if possible.
-
-# Other user config
-
-In addition to themes, users can also directly configure their preferred fonts
-and their nav bar preferences. The implementation of these is similar to themes.
diff --git a/docs/faqs.md b/docs/faqs.md
deleted file mode 100644
index 0815f6a57..000000000
--- a/docs/faqs.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-title: FAQs
----
-
-# Frequently Asked Questions
-
-## How do I log in after starting up Forem for the first time?
-
-Seeding the database create an admin user (see
-[Database](/getting-started/db/#default-admin-user)) with the following
-credentials:
-
-```
-email: admin@forem.local
-password: password
-```
-
-Once logged in as this admin user, you can turn on any authentication methods
-you'd like (see [Authentication](/backend/authentication/))
-
-## How do I build my local copy of the Ruby source code documentation?
-
-```shell
-cd docs
-make ruby-doc
-```
-
-Then open `.static/ruby-doc/index.html` in the `docs` directory and browse the
-Ruby documentation
-
-## How do I enable logging to standard output in development?
-
-By default Rails logs to `log.development.log`.
-
-If, instead, you wish to log to `STDOUT` you can add the variable:
-
-```shell
-export RAILS_LOG_TO_STDOUT=true
-```
-
-to your own `.env` file.
-
-## How do I see comments in the Feed?
-
-On the home Feed, we only show comments above certain "score". It's likely the
-comments in the local environment will never meet this score. If you want to see
-comments locally, you will need to update the score of your local comments
-manually. Here's how:
-
-1. Open the terminal.
-2. Run `rails dbconsole` to open the PostgreSQL terminal. Alternatively, run
- `psql PracticalDeveloper_development` to open `psql`, the PostgreSQL
- terminal.
-3. Enter `update comments set score = 30;`.
-4. Type `exit` to leave the PostgreSQL terminal.
-
-> Note: dbconsole reads database information from config/database.yml which is
-> always better since database configs might change in the future.
-
-Once you refresh the app, you should be able to see some comments in the Feed.
-
-## How do I make someone follow me on my local environment?
-
-In certain cases, for example when testing various functionalities, you may need
-to be able to make some user follow you. Here's how:
-
-1. Open the rails console by running `rails c` in your terminal.
-2. Get any user you want to follow you, for example `user = User.first`.
-3. Then make this user follow you: `user.follow(your_username)`.
-
-Boom, you have a new follower!
-
-## How do I remove / leave organization I created?
-
-1. Open the rails console by running `rails c` in your terminal.
-2. Enter the following commands:
- ```ruby
- user = User.find_by(username: "your_username")
- organization_id = Organization.find_by(slug: "organization_slug").id
- user.organization_memberships.where(organization_id: organization_id).destroy_all
- ```
-
-## How do I add credits to my account?
-
-If you ever want to add Listings locally, you must have credits on your account
-to "pay" for listing. Here's how:
-
-1. Open the rails console `rails console`.
-2. Enter the following commands:
-
- ```ruby
- user = User.find_by(username: "your_username")
- Credit.add_to(user, 1000)
- ```
-
-^ This will add 1000 credits to your account. But you know, you can't really buy
-anything with it :D
diff --git a/docs/frontend/accessibility.md b/docs/frontend/accessibility.md
deleted file mode 100644
index 389eb76f1..000000000
--- a/docs/frontend/accessibility.md
+++ /dev/null
@@ -1,54 +0,0 @@
----
-title: Accessibility
----
-
-# Accessibility
-
-To make Forem the most inclusive community platform around, accessibility should
-be considered to enable people with disabilities to create and consume content.
-
-## The Basics
-
-Forem UI changes should consider accessibility wherever possible. Common issues
-to watch out for in frontend code:
-
-- [Adequate color contrast](https://webaim.org/articles/contrast/evaluating)
-- [Semantic structure and headings](https://webaim.org/techniques/semanticstructure/)
-- [Alternative text for images](https://webaim.org/techniques/alttext/)
-- [Unique button and link text](https://webaim.org/techniques/hypertext/link_text)
-- [Accessible forms with labels](https://webaim.org/techniques/forms/)
-- [Visible keyboard focus styles](https://www.washington.edu/accessibility/checklist/focus/)
-
-## More Advanced Things
-
-If you're working on something JavaScript-heavy or animated, there are a few
-additional considerations for accessibility:
-
-- [Forem Accessibility Tests](https://docs.forem.com/tests/accessibility-tests/)
-- [Intro to ARIA](https://webaim.org/techniques/aria/)
-- [Handle focus for client-side interactions](https://dev.to/robdodson/managing-focus-64l)
-- [Reducing motion with CSS media queries](https://css-tricks.com/introduction-reduced-motion-media-query/)
-- [Linting with eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)
-- [Testing with Jest-axe](https://dev.to/bdougieyo/accessibility-testing-in-react-with-jest-axe-l7k)
-
-## Accessibility Testing
-
-See a list of testing steps to follow during development or for a Pull Request
-review on the
-[Forem Accessibility Testing Docs](https://docs.forem.com/tests/accessibility-tests/).
-
-## Resources
-
-There's a wealth of information out there to learn about digital accessibility!
-Here are some resources:
-
-- [W3C's Web Accessibility Initiative](https://www.w3.org/WAI/)
-- [Web Content Accessibility Guidelines](https://www.w3.org/TR/WCAG21/)
-- [ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.1/)
-- [WebAIM](http://webaim.org/)
-- [A11y Project](https://a11yproject.com)
-- [Deque University](https://dequeuniversity.com/)
-- [React Accessibility Docs](https://reactjs.org/docs/accessibility.html) (most
- will apply to Preact)
-- [The Importance of Manual Accessibility Testing](https://www.smashingmagazine.com/2018/09/importance-manual-accessibility-testing/)
-- [Accessibility Insights extension](https://accessibilityinsights.com)
diff --git a/docs/frontend/debugging.md b/docs/frontend/debugging.md
deleted file mode 100644
index 4a325f42c..000000000
--- a/docs/frontend/debugging.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Debugging
----
-
-# Debugging
-
-## In Browser
-
-Browsers ship with their own developer tools. These are amazing tools to help
-you debug your web application. Consider learning how to use them.
-
-- [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools)
-- [Firefox Developer Tools](https://developer.mozilla.org/en-US/docs/Tools)
-- [Safari Developer Tools](https://support.apple.com/en-ca/guide/safari/sfri20948/mac)
-
-## Visual Studio Code
-
-[Visual Studio Code](https://code.visualstudio.com) (VS Code) is a popular
-editor that allows you to debug many languages including JavaScript. Thanks to
-remote debugging technologies, we can debug our frontend code in VS Code. When
-you clone the Forem repository and open the project in VS Code, you will be
-prompted to install recommended extensions which include the
-[Chrome Debugger](https://code.visualstudio.com/blogs/2016/02/23/introducing-chrome-debugger-for-vs-code)
-and the
-[Edge Debugger](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-edge).
-
-Setup:
-
-- Refer to the respective debugger extension documentation above to ensure that
- your browser is running with remote debugging enabled.
-- Once you have your local installation of Forem running, you can attach to
- either the Chrome or Edge Debugger.
-
- 
-
-- From there you can do all the usual stuff that you would do while debugging
- JavaScript in the browser: setting breakpoints, setting
- [logpoints](https://code.visualstudio.com/docs/editor/debugging#_logpoints),
- watches etc.
-
-## Where is My Editor Debug Configuration?
-
-If you do not see your editor here, consider contributing to the documentation.
-😉
-
-## Preact Developer Tools
-
-Preact has their
-[own developer tools](https://preactjs.github.io/preact-devtools/) in the form
-of a browser extension. The Forem codebase is configured out of the box to
-support the Preact Devtools.
diff --git a/docs/frontend/dynamic-imports.md b/docs/frontend/dynamic-imports.md
deleted file mode 100644
index c153fa05a..000000000
--- a/docs/frontend/dynamic-imports.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Dynamic Imports
----
-
-# Dynamic Imports
-
-[Dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import/#Dynamic_Imports)
-are supported in all major browsers except for Edge
-([EdgeHTML](https://en.wikipedia.org/wiki/EdgeHTML) version) and Internet
-Explorer which are both unsupported browsers for Forem. They allow you to import
-JavaScript dynamically instead of statically. Why is this important?
-Performance.
-
-Should you use them everywhere? No. They are a great tool when you need to load
-a JavaScript module on the fly for functionality that is not needed immediately
-for the page to be usable.
-
-Here are a couple of examples of dynamic import usage on Forem:
-
-- The
- [Onboarding flow](https://github.com/forem/forem/blob/0633d85b6b0e083bb7b21b11642b2b17d3fe9de6/app/javascript/packs/Onboarding.jsx#L21).
-- In
- [homepage](https://github.com/forem/forem/blob/0633d85b6b0e083bb7b21b11642b2b17d3fe9de6/app/javascript/packs/homePage.jsx#L59)
- (followed tags).
-
-Forem uses [webpacker](frontend/webpacker) (webpack), so what webpack will do is
-create separate bundles for code that is dynamically imported. So not only do we
-end up loading code only when we need it, we also end up with smaller bundle
-sizes in the frontend.
-
-For a great deep dive into dynamic imports, there is a great article from
-community member [@goenning](https://dev.to/goenning) about dynamic import
-usage,
-[How we reduced our initial JS/CSS size by 67%](https://dev.to/goenning/how-we-reduced-our-initial-jscss-size-by-67-3ac0).
diff --git a/docs/frontend/instant-click.md b/docs/frontend/instant-click.md
deleted file mode 100644
index cb379a8fb..000000000
--- a/docs/frontend/instant-click.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# InstantClick
-
-Like the [InstantClick](http://instantclick.io/) tag line says, “InstantClick is
-a JavaScript library that dramatically speeds up your website, making navigation
-effectively instant in most cases.”.
-
-The way it works is if a user hovers over a hyperlink, chances are their
-intentions are to click on it. InstantClick will start prefetching the page
-while a user is hovering over a hyperlink, so that by the time they do click on
-it, it's instantaneous. On mobile devices, preloading starts on
-[touchstart](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchstart_event).
-
-Aside from prefetching pages, InstantClick also allows you to customize what
-happens when an InstantClick page changes.
-
-```javascript
-// Found in https://github.com/forem/forem/blob/main/app/javascript/packs/githubRepos.jsx#L11)
-window.InstantClick.on('change', () => {
- loadElement();
-});
-```
-
-You can also decide whether or not to reevaluate a script in an InstantClick
-loaded page via the `data-no-instant` attribute.
-
-```javascript
-// Found in https://github.com/forem/forem/blob/main/app/assets/javascripts/utilities/buildCommentHTML.js.erb#L80
-function actions(comment) {
- if (comment.newly_created) {
- return '
';
- } else {
-...
-```
-
-For more information on this, see the
-[Events and script re-evaluation in InstantClick](http://instantclick.io/scripts)
-documentation.
diff --git a/docs/frontend/linting-formatting.md b/docs/frontend/linting-formatting.md
deleted file mode 100644
index b5744c632..000000000
--- a/docs/frontend/linting-formatting.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Linting and Formatting
----
-
-# Linting and Formatting
-
-The project uses [eslint](https://eslint.org/) with the
-[Prettier plugin](https://github.com/prettier/eslint-plugin-prettier). eslint
-handles linting, but eslint rules related to code formatting, they get handled
-by prettier. For the most part, out of the box rules provided by the
-configurations that are extended are used but there are some tweaks.
-
-Forem also has some objects that live in the global scope, e.g. Pusher. The
-eslint globals section of the eslint configuration is what enables these to be
-reported as existing when eslint runs.
-
-```javascript
-globals: {
- InstantClick: false,
- filterXSS: false,
- Pusher: false,
-}
-```
-
-## Husky and lint-staged
-
-The code base uses a pre-commit hook that is enabled by the
-[husky](https://github.com/typicode/husky) and
-[lint-staged](https://github.com/okonet/lint-staged) tools. The pre-commit hook
-runs eslint before frontend code is committed. If there are any issues that can
-automatically be fixed, eslint will fix them. If there are linting issues that
-cannot be resolved, the commit fails and the changes need to be handled
-manually. Prettier also runs during the pre-commit hook.
diff --git a/docs/frontend/liquid-tags.md b/docs/frontend/liquid-tags.md
deleted file mode 100644
index 0d7128d00..000000000
--- a/docs/frontend/liquid-tags.md
+++ /dev/null
@@ -1,160 +0,0 @@
----
-title: Liquid Tags
----
-
-# Liquid Tags
-
-Liquid tags are special elements of the
-[Forem Markdown editor](https://dev.to/new).
-
-They are custom embeds that are added via a `{% %}` syntax.
-[Liquid](https://shopify.github.io/liquid/) is a templating language developed
-by Shopify.
-
-Liquid embeds are for tweets, like `{% tweet 765282762081329153 %}` or a Forem
-user profile preview, like `{% user jess %}` etc.
-
-They make for good community contributions because they can be extended and
-improved consistently. It is truly how we extend the functionality of the
-editor. At the moment, there could be a lot of work refactoring and improving
-existing liquid tags, in addition to adding new ones.
-
-Liquid tags are sort of like functions, which have a name and take arguments.
-Develop them with that mindset in terms of naming things. They should be
-documented but also intuitive. They should also be fairly flexible in the
-arguments they take. Currently, this could use improvements.
-
-_Note: Liquid tags are "compiled" when an article is saved. So you will need to
-re-save articles to see HTML changes._
-
-Here is a bunch of liquid tags supported on Forem:
-
-```liquid
-{% link https://dev.to/kazz/boost-your-productivity-using-markdown-1be %}
-{% user jess %}
-{% tag git %}
-{% devcomment 2d1a %}
-{% podcast https://dev.to/basecspodcast/s2e2--queues-irl %}
-{% twitter 834439977220112384 %}
-{% glitch earthy-course %}
-{% github forem/forem %}
-{% youtube dQw4w9WgXcQ %}
-{% vimeo 193110695 %}
-{% twitch ClumsyPrettiestOilLitFam %}
-{% slideshare rdOzN9kr1yK5eE %}
-{% codepen https://codepen.io/twhite96/pen/XKqrJX %}
-{% stackblitz ball-demo %}
-{% codesandbox ppxnl191zx %}
-{% jsfiddle https://jsfiddle.net/link2twenty/v2kx9jcd %}
-{% dotnetfiddle https://dotnetfiddle.net/PmoDip %}
-{% replit @WigWog/PositiveFineOpensource %}
-{% stackery deeheber lambda-layer-example layer-resource %}
-{% nexttech https://nt.dev/s/6ba1fffbd09e %}
-{% instagram BXgGcAUjM39 %}
-{% speakerdeck 7e9f8c0fa0c949bd8025457181913fd0 %}
-{% soundcloud https://soundcloud.com/user-261265215/dev-to-review-episode-1 %}
-{% spotify spotify:episode:5V4XZWqZQJvbddd31n56mf %}
-{% blogcast 1234 %}
-{% kotlin https://pl.kotl.in/owreUFFUG %}
-{% wikipedia https://en.wikipedia.org/wiki/Wikipedia %}
-{% reddit https://www.reddit.com/r/aww/comments/ag3s4b/ive_waited_28_years_to_finally_havr_my_first_pet %}
-```
-
-## How liquid tags are developed
-
-Liquid tags are a matter of parsing the "arguments" and serving relevant
-JavaScript.
-
-Liquid tags go in the `app/liquid_tags` folder. All liquid tags inherit from the
-base, like so...
-
-```ruby
-class KotlinTag < LiquidTagBase
-```
-
-Each liquid tag contains an `initialize` method which takes arguments and calls
-`super`. It also has a `render` method which calls the appropriate view.
-
-```ruby
- def initialize(_tag_name, link, _parse_context)
- super
- stripped_link = ActionController::Base.helpers.strip_tags(link)
- the_link = stripped_link.split.first
- @embedded_url = KotlinTag.embedded_url(the_link)
- end
-
- def render(_context)
- ApplicationController.render(
- partial: PARTIAL,
- locals: {
- url: @embedded_url
- }
- )
- end
-```
-
-View files can be found in `app/views/liquids`.
-
-Each new liquid tag should be accompanied by instructions in
-`app/views/pages/_editor_guide_text.html.erb`.
-
-Liquid Tags should also be accompanied by tests in `spec/liquid_tags` which
-confirm expected behavior.
-
-Some Liquid Tags are constructed using HTML and CSS within the app, and some are
-constructed by displaying an iframe of an external site.
-
-CSS for Liquid Tags are found in `app/assets/stylesheets/ltags`. Liquid tag
-classes should generally be prepended by `ltag__`. e.g. `ltag__tag__content`
-etc.
-
-Here is an example of a good Liquid Tag pull request...
-https://github.com/forem/forem/pull/3801
-
-### Restricting liquid tags by roles
-
-To only allow users with specific roles to use a liquid tag, you need to define
-a `VALID_ROLES` constant on the liquid tag itself. It needs to be an `Array` of
-valid roles. For [single resource roles](/admin), it needs to be an `Array` with
-the role and the resource. Here's an example:
-
-```ruby
-class NewLiquidTag < LiquidTagBase
- VALID_ROLES = [
- :admin,
- [:restricted_liquid_tag, LiquidTags::UserSubscriptionTag]
- ].freeze
-end
-```
-
-Here we are saying that the `UserSubscriptionTag` is only usable by users with
-the `admin` role or with a role of `:restricted_liquid_tag` and a specified
-resource of `LiquidTags::UserSubscriptionTag`.
-
-`LiquidTags::UserSubscriptionTag` is a resource model so we that can play nicely
-with the [Rolify][rolify] gem. See [/admin](/admin) for more information.
-
-**REMINDER: if you do not define a `VALID_ROLES` constant, the liquid tag will
-be usable by all users by default.**
-
-### Restricting liquid tags by context
-
-Context, in terms of a liquid tag, is _where_ a liquid tag is being used (i.e.
-`Article`, `Comment`, etc.). In other words, if you want to make a liquid tag
-that can only be used in articles, you need to restrict the liquid tag by
-context.
-
-To do this you need to add a `VALID_CONTEXTS` constant on the liquid tag itself.
-It needs to be an `Array` of class names that are valid. For example, to
-restrict a liquid tag to only be usable in articles you would do:
-
-```ruby
-class NewLiquidTag < LiquidTagBase
- VALID_CONTEXTS = %w[Article].freeze
-end
-```
-
-**REMINDER: if you do not define a `VALID_CONTEXTS` constant the liquid tag will
-be usable in all contexts by default.**
-
-[rolify]: https://github.com/RolifyCommunity/rolify
diff --git a/docs/frontend/plain-js.md b/docs/frontend/plain-js.md
deleted file mode 100644
index bcb6d1d21..000000000
--- a/docs/frontend/plain-js.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: JavaScript and Initializers
----
-
-# JavaScript and Initializers
-
-Forem has two JavaScript codebases.
-
-One is located in the directory `app/assets/javascripts` and contains plain
-JavaScript (mostly ES5+) being served using
-[Sprockets](https://github.com/rails/sprockets-rails) which packages static
-assets.
-
-Webpacker manages the other one,
-[which you can read more about in this guide](/frontend/webpacker).
-
-This source code is not transpiled, only packaged and minified, and will be
-limited to whatever flavor of JavaScript can run on the user's web browser.
-
-`app/assets/javascripts/application.js` contains the manifest JavaScript file
-which is included globally in the primary template,
-`app/views/layouts/application.html.erb`.
-
-`application.js` automatically includes all JS files via the statement:
-
-```erb
-//= require_tree .
-```
-
-One JS file in particular, `app/assets/javascripts/initializePage.js`,
-bootstraps the majority of the functionality. You will notice, within this file,
-that major sections of the websites are bootstrapped, for example:
-
-```javascript
-initializeBaseTracking();
-initializeCommentsPage();
-initEditorResize();
-initLeaveEditorWarning();
-initializeArticleReactions();
-initNotifications();
-initializeSplitTestTracking();
-```
-
-All the "initializers" are in `/app/assets/javascripts/initializers`.
diff --git a/docs/frontend/preact.md b/docs/frontend/preact.md
deleted file mode 100644
index 288c242f2..000000000
--- a/docs/frontend/preact.md
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: Preact
----
-
-# Preact
-
-[Preact](https://preactjs.com/) is an alternative to React with the same modern
-API.
-
-Preact components are packaged using [Webpacker](/frontend/webpacker) and the
-Preact code is located in `app/javascript`.
-
-Preact components get loaded via webpacker's helper function
-`javascript_packs_with_chunks_tag`.
-
-## PropTypes
-
-Preact supports
-[PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html). When
-creating Preact components, please ensure that you have defined your PropTypes.
-
-### Common PropTypes
-
-Using PropTypes can be repetitive. Some duplication is normal, like when a
-PropType is a string or a number. But for commonly-used PropTypes, like the user
-entity, you can use the provided common PropTypes, located in the
-`/app/javascript/common-prop-types`, as shown below.
-
-```javascript
-import PropTypes from 'prop-types';
-
-export const userPropTypes = PropTypes.shape({
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- profile_image_url: PropTypes.string.isRequired,
- summary: PropTypes.string.isRequired,
-});
-```
-
-#### Using Common PropTypes
-
-Common PropTypes are imported just like any other
-[JavaScript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules).
-For example, here are two scenarios where a component needs to use the
-`tagPropTypes`.
-
-In the example below, our component `SomeComponentUsingTags` has a `tags` prop,
-which is an array of the tag entity. PropTypes have a built-in method called
-`arrayOf` that allows you to define a prop as an array of something. In our
-case, this is the tag entity, so we can use the `tagPropTypes` PropType.
-
-```jsx
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { tagPropTypes } from '../../../components/common-prop-types';
-
-const SomeComponentUsingTags = ({ tags = [] }) => (
-
- {tags.map((tag) => (
-
{tag.name}
- ))}
-
-);
-
-SomeComponentUsingTags.displayName = 'SomeComponentUsingTags';
-SomeComponentUsingTags.propTypes = {
- tags: PropTypes.arrayOf(tagPropTypes).isRequired,
-};
-```
-
-In the following example, the `SomeComponentUsingOneTag` component has a `tag`
-prop representing a single tag. In this case, we can just the `tagPropTypes` on
-their own to represent the shape of the `tag` prop.
-
-```jsx
-import { h } from 'preact';
-import { tagPropTypes } from '../../../components/common-prop-types';
-
-const SomeComponentUsingOneTag = ({ tag }) =>