summaryrefslogtreecommitdiffstatshomepage
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/README.md30
-rw-r--r--doc/assets/bridge-workflow.pngbin0 -> 24172 bytes
-rw-r--r--doc/assets/bug-graph.png (renamed from doc/bug-graph-1.png)bin56863 -> 56863 bytes
-rw-r--r--doc/assets/merge-1.png (renamed from doc/merge1.png)bin56989 -> 56989 bytes
-rw-r--r--doc/assets/merge-2.png (renamed from doc/merge2.png)bin65479 -> 65479 bytes
-rw-r--r--doc/assets/native-workflow.pngbin0 -> 26582 bytes
-rw-r--r--doc/assets/operations.png (renamed from doc/operations.png)bin12842 -> 12842 bytes
-rw-r--r--doc/assets/tui-recording.gifbin0 -> 879036 bytes
-rw-r--r--doc/assets/web-screenshot-comments.pngbin0 -> 109054 bytes
-rw-r--r--doc/assets/web-screenshot-feed.pngbin0 -> 92028 bytes
-rw-r--r--doc/assets/webui-workflow.pngbin0 -> 27271 bytes
-rw-r--r--doc/design/architecture.md (renamed from doc/architecture.md)100
-rw-r--r--doc/design/bridges/jira.md (renamed from doc/jira_bridge.md)78
-rw-r--r--doc/design/cli-convention.md (renamed from doc/cli-convention.md)2
-rw-r--r--doc/design/data-model.md215
-rw-r--r--doc/feature-matrix.md151
-rw-r--r--doc/feature_matrix.md137
-rw-r--r--doc/generate.go (renamed from doc/gen_docs.go)32
-rw-r--r--doc/howto-github.md80
-rw-r--r--doc/model.md145
-rw-r--r--doc/queries.md113
-rw-r--r--doc/usage/interfaces.md66
-rw-r--r--doc/usage/query-language.md167
-rw-r--r--doc/usage/third-party.md113
-rw-r--r--doc/usage/workflows.md62
25 files changed, 938 insertions, 553 deletions
diff --git a/doc/README.md b/doc/README.md
index e172ffd6..ed9c0bf3 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,15 +1,27 @@
# Documentation
-## For users
+## Usage
-- [data model](model.md) describes how the data model works and why.
-- [query language](queries.md) describes git-bug's query language.
-- [How-to: Read and edit offline your Github/Gitlab/Jira issues with git-bug](howto-github.md)
+The documentation listed below aims to help provide insight into the usage of
+`git-bug`.
+
+- Read about the different [types of workflows](./usage/workflows.md) and check
+ the [feature matrix](./feature-matrix.md) to learn about `git-bug`
+- Check the [CLI documentation](./md/git-bug.md) for commands and options (or
+ run `man git-bug` after [installation](../INSTALLATION.md))
+- Filter results using the [query language](./usage/query-language.md)
+- Learn how to [sync third party issues](./usage/third-party.md) for offline
+ reading and editing
## For developers
-- :exclamation: [data model](model.md) describes how the data model works and why.
-- :exclamation: [internal bird-view](architecture.md) gives an overview of the project architecture.
-- :exclamation: [Entity/DAG](../entity/dag/example_test.go) explains how to easily make your own distributed entity in git.
-- [query language](queries.md) describes git-bug's query language.
-- [JIRA bridge dev notes](jira_bridge.md)
+- Read through [`//:CONTRIBUTING.md`][contrib]
+- See an [overview of the internal architecture](./design/architecture.md)
+- Read about the [data model](./design/data-model.md) to gain a deeper
+ understanding of the internals that comprise `git-bug`
+- [`//entity/dag:example_test.go`](../entity/dag/example_test.go) is a good
+ reference to learn how to create a new distributed entity
+- Read the [bridge design documents](./design/bridges) to learn more about each
+ bridge
+
+[contrib]: ../CONTRIBUTING.md
diff --git a/doc/assets/bridge-workflow.png b/doc/assets/bridge-workflow.png
new file mode 100644
index 00000000..18fb8a77
--- /dev/null
+++ b/doc/assets/bridge-workflow.png
Binary files differ
diff --git a/doc/bug-graph-1.png b/doc/assets/bug-graph.png
index 5f6f931f..5f6f931f 100644
--- a/doc/bug-graph-1.png
+++ b/doc/assets/bug-graph.png
Binary files differ
diff --git a/doc/merge1.png b/doc/assets/merge-1.png
index 7ba24173..7ba24173 100644
--- a/doc/merge1.png
+++ b/doc/assets/merge-1.png
Binary files differ
diff --git a/doc/merge2.png b/doc/assets/merge-2.png
index 614be5e8..614be5e8 100644
--- a/doc/merge2.png
+++ b/doc/assets/merge-2.png
Binary files differ
diff --git a/doc/assets/native-workflow.png b/doc/assets/native-workflow.png
new file mode 100644
index 00000000..8fa9d46c
--- /dev/null
+++ b/doc/assets/native-workflow.png
Binary files differ
diff --git a/doc/operations.png b/doc/assets/operations.png
index 79b6c8e7..79b6c8e7 100644
--- a/doc/operations.png
+++ b/doc/assets/operations.png
Binary files differ
diff --git a/doc/assets/tui-recording.gif b/doc/assets/tui-recording.gif
new file mode 100644
index 00000000..43ba6eec
--- /dev/null
+++ b/doc/assets/tui-recording.gif
Binary files differ
diff --git a/doc/assets/web-screenshot-comments.png b/doc/assets/web-screenshot-comments.png
new file mode 100644
index 00000000..f4b8dceb
--- /dev/null
+++ b/doc/assets/web-screenshot-comments.png
Binary files differ
diff --git a/doc/assets/web-screenshot-feed.png b/doc/assets/web-screenshot-feed.png
new file mode 100644
index 00000000..502e71f0
--- /dev/null
+++ b/doc/assets/web-screenshot-feed.png
Binary files differ
diff --git a/doc/assets/webui-workflow.png b/doc/assets/webui-workflow.png
new file mode 100644
index 00000000..83d20d84
--- /dev/null
+++ b/doc/assets/webui-workflow.png
Binary files differ
diff --git a/doc/architecture.md b/doc/design/architecture.md
index e3a7f0b0..b63c149d 100644
--- a/doc/architecture.md
+++ b/doc/design/architecture.md
@@ -1,8 +1,10 @@
# Internal architecture
-This documentation only provides a bird's-eye view of git-bug's internals. For more details, you should read the other documentation and the various comment/documentation scattered in the codebase.
+This documentation only provides a bird's-eye view of git-bug's internals. For
+more details, you should read the other documentation and the various
+comment/documentation scattered in the codebase.
-## Overview
+## Overview
```
.--------------.
@@ -26,31 +28,46 @@ This documentation only provides a bird's-eye view of git-bug's internals. For m
'----------------------------------------------------------'
```
-Here is the internal architecture of git-bug. As you can see, it's a layered architecture.
+Here is the internal architecture of git-bug. As you can see, it's a layered
+architecture.
-As a general rule of thumb, each layer uses the directly underlying layer to access and interact with the data. As an example, the `commands` package will not directly use the `bug` or `repository` package. It will request the data from the `cache` layer and go from there. Of course, the `commands` package will ultimately use types defined in the lower level package like `Bug`, but retrieving and changing the data has to go through the `cache` layer to ensure that bugs are properly deduplicated in memory.
+As a general rule of thumb, each layer uses the directly underlying layer to
+access and interact with the data. As an example, the `commands` package will
+not directly use the `bug` or `repository` package. It will request the data
+from the `cache` layer and go from there. Of course, the `commands` package will
+ultimately use types defined in the lower level package like `Bug`, but
+retrieving and changing the data has to go through the `cache` layer to ensure
+that bugs are properly deduplicated in memory.
## repository
-The package `repository` implement the interaction with the git repository on disk.
+The package `repository` implement the interaction with the git repository on
+disk.
-A series of interfaces (`RepoCommon`, `Repo` and `ClockedRepo`) define convenient for our usage access and manipulation methods for the data stored in git.
+A series of interfaces (`RepoCommon`, `Repo` and `ClockedRepo`) define
+convenient for our usage access and manipulation methods for the data stored in
+git.
Those interfaces are implemented by `GitRepo` as well as a mock for testing.
## identity
-The package `entities/identity` contains the identity data model and the related low-level functions.
+The package `entities/identity` contains the identity data model and the related
+low-level functions.
In particular, this package contains:
-- `Identity`, the fully-featured identity, holding a series of `Version` stored in its dedicated structure in git
+
+- `Identity`, the fully-featured identity, holding a series of `Version` stored
+ in its dedicated structure in git
- `Bare`, the simple legacy identity, stored directly in a bug `Operation`
## bug
-The package `entities/bug` contains the bug data model and the related low-level functions.
+The package `entities/bug` contains the bug data model and the related low-level
+functions.
In particular, this package contains:
+
- `Operation`, the interface to fulfill for an edit operation of a Bug
- `OpBase`, implementing the common code for all operations
- `OperationPack`, an array of `Operation`
@@ -61,43 +78,72 @@ In particular, this package contains:
## cache
-The package `cache` implements a caching layer on top of the low-level `bug` and `identity`package to provide efficient querying, filtering, sorting.
+The package `cache` implements a caching layer on top of the low-level `bug` and
+`identity`package to provide efficient querying, filtering, sorting.
-This cache main function is to provide some guarantee and features for the upper layers:
-1. After being loaded, a Bug is kept in memory in the cache, allowing for fast access later.
-2. The cache maintain in memory and on disk a pre-digested excerpt for each bug, allowing for fast querying the whole set of bugs without having to load them individually.
-3. The cache guarantee that a single instance of a Bug is loaded at once, avoiding loss of data that we could have with multiple copies in the same process.
-4. The same way, the cache maintain in memory a single copy of the loaded identities.
+This cache main function is to provide some guarantee and features for the upper
+layers:
-The cache also protect the on-disk data by locking the git repository for its own usage, by writing a lock file. Of course, normal git operations are not affected, only git-bug related one.
+1. After being loaded, a Bug is kept in memory in the cache, allowing for fast
+ access later.
+2. The cache maintain in memory and on disk a pre-digested excerpt for each bug,
+ allowing for fast querying the whole set of bugs without having to load them
+ individually.
+3. The cache guarantee that a single instance of a Bug is loaded at once,
+ avoiding loss of data that we could have with multiple copies in the same
+ process.
+4. The same way, the cache maintain in memory a single copy of the loaded
+ identities.
+
+The cache also protect the on-disk data by locking the git repository for its
+own usage, by writing a lock file. Of course, normal git operations are not
+affected, only git-bug related one.
In particular, this package contains:
-- `BugCache`, wrapping a `Bug` in a cached version in memory, maintaining efficiently a `Snapshot` and providing a simplified API
-- `BugExcerpt`, holding a small subset of data for each bug, allowing for a very fast indexing, filtering, sorting and querying
-- `IdentityCache`, wrapping an `Identity` in a cached version in memory and providing a simplified API
-- `IdentityExcerpt`, holding a small subset of data for each identity, allowing for a very fast indexing, filtering, sorting and querying.
+
+- `BugCache`, wrapping a `Bug` in a cached version in memory, maintaining
+ efficiently a `Snapshot` and providing a simplified API
+- `BugExcerpt`, holding a small subset of data for each bug, allowing for a very
+ fast indexing, filtering, sorting and querying
+- `IdentityCache`, wrapping an `Identity` in a cached version in memory and
+ providing a simplified API
+- `IdentityExcerpt`, holding a small subset of data for each identity, allowing
+ for a very fast indexing, filtering, sorting and querying.
- `Query` and a series of `Filter` to implement the query language
## commands
-The package `commands` contains all the CLI commands and subcommands, implemented with the [cobra](https://github.com/spf13/cobra) library. Thanks to this library, bash and zsh completion, manpages and markdown documentation are automatically generated.
+The package `commands` contains all the CLI commands and subcommands,
+implemented with the [cobra](https://github.com/spf13/cobra) library. Thanks to
+this library, bash and zsh completion, manpages and markdown documentation are
+automatically generated.
## termui
-The package `termui` contains the interactive terminal user interface, implemented with the [gocui](https://github.com/jroimartin/gocui) library.
+The package `termui` contains the interactive terminal user interface,
+implemented with the [gocui](https://github.com/jroimartin/gocui) library.
## graphql
-The package `graphql` implement the GraphQL API, mapping the data model and providing read/write access from outside the process. This API is in particular used by the webUI but could be used to implement other user interfaces or bridges with other systems.
+The package `graphql` implement the GraphQL API, mapping the data model and
+providing read/write access from outside the process. This API is in particular
+used by the webUI but could be used to implement other user interfaces or
+bridges with other systems.
## webui
-The package `webui` hold the web based user interface, implemented in both go and javascript.
+The package `webui` hold the web based user interface, implemented in both go
+and javascript.
-The javascript code is compiled and packaged inside the go binary, allowing for a single file distribution of git-bug.
+The javascript code is compiled and packaged inside the go binary, allowing for
+a single file distribution of git-bug.
-When the webUI is started from the CLI command, a localhost HTTP server is started to serve the webUI resources (html, js, css), as well as the GraphQL API. When the webUI is loaded in the browser, it interacts with the git-bug process through the GraphQL API to load and edit bugs.
+When the webUI is started from the CLI command, a localhost HTTP server is
+started to serve the webUI resources (html, js, css), as well as the GraphQL
+API. When the webUI is loaded in the browser, it interacts with the git-bug
+process through the GraphQL API to load and edit bugs.
## bridge
-The package `bridge` contains the various bridge implementation with other external bug trackers.
+The package `bridge` contains the various bridge implementation with other
+external bug trackers.
diff --git a/doc/jira_bridge.md b/doc/design/bridges/jira.md
index bf3c1a8b..c3a7f29f 100644
--- a/doc/jira_bridge.md
+++ b/doc/design/bridges/jira.md
@@ -19,18 +19,18 @@ Hopefully the bridge will be able to enable synchronization of these soon.
### Credentials
JIRA does not support user/personal access tokens. They have experimental
-3-legged oauth support but that requires an API token for the app configured
-by the server administrator. The only reliable authentication mechanism then is
-the username/password and session-token mechanism. We can acquire a session
-token programmatically from the username/password but these are very short lived
-(i.e. hours or less). As such the bridge currently requires an actual username
-and password as user credentials. It supports three options:
-
-1. Storing both username and password in a separate file referred to by
- the `git-config` (I like to use `.git/jira-credentials.json`)
+3-legged oauth support but that requires an API token for the app configured by
+the server administrator. The only reliable authentication mechanism then is the
+username/password and session-token mechanism. We can acquire a session token
+programmatically from the username/password but these are very short lived (i.e.
+hours or less). As such the bridge currently requires an actual username and
+password as user credentials. It supports three options:
+
+1. Storing both username and password in a separate file referred to by the
+ `git-config` (I like to use `.git/jira-credentials.json`)
2. Storing the username and password in clear-text in the git config
-3. Storing the username only in the git config and asking for the password
- on each `push` or `pull`.
+3. Storing the username only in the git config and asking for the password on
+ each `push` or `pull`.
### Issue Creation Defaults
@@ -63,7 +63,6 @@ integration activities become easier.
See the configuration section below on how to specify the custom field where the
JIRA bridge should write this information.
-
### Workflows and Transitions
JIRA issue states are subject to customizable "workflows" (project managers
@@ -128,14 +127,14 @@ identified the match.
### Unlogged Changes
Comments (creation and edition) do not show up in the JIRA changelog. However
-JIRA reports both a `created` and `updated` date for each comment. If we
-import a comment which has an `updated` and `created` field which do not match,
-then we treat that as a new comment edition. If we do not already have the
-comment imported, then we import an empty comment followed by a comment edition.
+JIRA reports both a `created` and `updated` date for each comment. If we import
+a comment which has an `updated` and `created` field which do not match, then we
+treat that as a new comment edition. If we do not already have the comment
+imported, then we import an empty comment followed by a comment edition.
-Because comment editions are not uniquely identified in JIRA we identify them
-in `git-bug` by concatenating the JIRA issue `id` with the `updated` time of
-the edition.
+Because comment editions are not uniquely identified in JIRA we identify them in
+`git-bug` by concatenating the JIRA issue `id` with the `updated` time of the
+edition.
### Workflow Validation (future)
@@ -171,8 +170,8 @@ configuration. You can set these options in your `.git/config` file:
The format for this config entry is a JSON object containing fields you wish to
set during issue creation when exporting bugs. If you provide a value for this
-configuration option, it must include at least the `"issuetype"` field, or
-the bridge will not be able to export any new issues.
+configuration option, it must include at least the `"issuetype"` field, or the
+bridge will not be able to export any new issues.
Let's say that we want bugs exported to JIRA to have a default issue type of
"Story" which is `issuetype` with id `10001`. Then we will add the following
@@ -193,7 +192,6 @@ create-issue-defaults = {"issuetype":"10001","customfield_1234":"default"}
Note that the content of this value is merged verbatim to the JSON object that
is `POST`ed to the JIRA rest API, so you can use arbitrary valid JSON.
-
### Assign git-bug id to field
If you want the bridge to fill a JIRA field with the `git-bug` id when exporting
@@ -207,6 +205,7 @@ create-issue-gitbug-id = "customfield_5678"
You can specify the mapping between `git-bug` status and JIRA status id's using
the following:
+
```
bug-id-map = {\"open\": \"1\", \"closed\": \"6\"}
```
@@ -215,6 +214,7 @@ The format of the map is `<git-bug-status-name>: <jira-status-id>`. In general
your jira instance will have more statuses than `git-bug` will and you may map
more than one jira-status to a git-bug status. You can do this with
`bug-id-revmap`:
+
```
bug-id-revmap = {\"10109\": \"open\", \"10006\": \"open\", \"10814\": \"open\"}
```
@@ -230,6 +230,7 @@ requires doublequotes to be escaped (as in the examples above).
### Full example
Here is an example configuration with all optional fields set
+
```
[git-bug "bridge.default"]
project = PROJ
@@ -244,22 +245,21 @@ Here is an example configuration with all optional fields set
## To-Do list
-* [0cf5c71] Assign git-bug to jira field on import
-* [8acce9c] Download and cache workflow representation
-* [95e3d45] Implement workflow gui
-* [c70e22a] Implement additional query filters for import
-* [9ecefaa] Create JIRA mock and add REST unit tests
-* [67bf520] Create import/export integration tests
-* [1121826] Add unit tests for utilities
-* [0597088] Use OS keyring for credentials
-* [d3e8f79] Don't count on the `Total` value in paginations
-
+- \[0cf5c71\] Assign git-bug to jira field on import
+- \[8acce9c\] Download and cache workflow representation
+- \[95e3d45\] Implement workflow gui
+- \[c70e22a\] Implement additional query filters for import
+- \[9ecefaa\] Create JIRA mock and add REST unit tests
+- \[67bf520\] Create import/export integration tests
+- \[1121826\] Add unit tests for utilities
+- \[0597088\] Use OS keyring for credentials
+- \[d3e8f79\] Don't count on the `Total` value in paginations
## Using CURL to poke at your JIRA's REST API
If you need to lookup the `id` for any `status`es or the `schema` for any
-creation metadata, you can use CURL to query the API from the command line.
-Here are a couple of examples to get you started.
+creation metadata, you can use CURL to query the API from the command line. Here
+are a couple of examples to get you started.
### Getting a session token
@@ -271,8 +271,9 @@ curl \
<serverUrl>/rest/auth/1/session
```
-**Note**: If you have a json pretty printer installed (`sudo apt install jq`),
-pipe the output through through that to make things more readable:
+[!NOTE]
+If you have a json pretty printer installed (`sudo apt install jq`), pipe the
+output through through that to make things more readable:
```
curl --silent \
@@ -283,6 +284,7 @@ curl --silent \
```
example output:
+
```
{
"session": {
@@ -316,6 +318,7 @@ curl --silent \
```
**example output**:
+
```
{
"self": "https://jira.example.com/rest/api/2/issuetype/13105",
@@ -338,10 +341,8 @@ curl --silent \
...
```
-
### Get a list of statuses
-
```
curl --silent \
--cookie "JSESSIONID={sessionToken}" \
@@ -351,6 +352,7 @@ curl --silent \
```
**example output:**
+
```
[
{
diff --git a/doc/cli-convention.md b/doc/design/cli-convention.md
index 47eccf69..d65e48db 100644
--- a/doc/cli-convention.md
+++ b/doc/design/cli-convention.md
@@ -1,6 +1,6 @@
## Pattern
-CLI commands should consistently follow this pattern:
+CLI commands should consistently follow this pattern:
```
xxx --> list xxx things if list, otherwise show one
diff --git a/doc/design/data-model.md b/doc/design/data-model.md
new file mode 100644
index 00000000..0553ed25
--- /dev/null
+++ b/doc/design/data-model.md
@@ -0,0 +1,215 @@
+# git-bug's reusable entity data model
+
+This document explains how git-bug's reusable distributed data structure in git
+is working. This data structure is capable of:
+
+- storing an entity (bug, pull-request, config...) and its complete history in
+ git
+- carry signed authorship of editions
+- use git remotes as a medium for synchronisation and collaboration
+- merge conflicts
+- respect the rules you define as to what edition are possible
+- carry attached media
+
+If you are looking for a different writing format or to see how you can easily
+make your own, checkout [the example code](../../entity/dag/example_test.go).
+
+If you are not familiar with
+[git internals](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects), you
+might first want to read about them, as the `git-bug` data model is built on top
+of them.
+
+## Entities (bug, author, ...) are a series of edit operations
+
+As entities are stored and edited in multiple processes at the same time, it's
+not possible to store the current state like it would be done in a normal
+application. If two processes change the same entity and later try to merge the
+states, we wouldn't know which change takes precedence or how to merge those
+states.
+
+To deal with this problem, you need a way to merge these changes in a meaningful
+way. Instead of storing the final bug data directly, we store a series of edit
+`Operation`s. This is a common idea, notably with
+[Operation-based CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#Operation-based_CRDTs).
+
+![ordered operations](../assets/operations.png)
+
+To get the final state of an entity, we apply these `Operation`s in the correct
+order on an empty state, to compute (aka "compile") our view.
+
+## Entities are stored in git objects
+
+An `Operation` is a piece of data, including:
+
+- a type identifier
+- an author (a reference to another entity)
+- a timestamp (there is also one or two [Lamport time](#time-is-unreliable))
+- all the data required by that operation type (a message, a status ...)
+- a random [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) to ensure
+ we have enough entropy, as the operation identifier is a hash of that data
+ (more on that later)
+
+These `Operation`s are aggregated in an `OperationPack`, a simple array. An
+`OperationPack` represents an edit session of the entity. As the operation's
+author is the same for all the `OperationPack` we only store it once.
+
+We store this pack in git as a git `Blob`; that consists of a string containing
+a JSON array of operations. One such pack -- here with two operations -- might
+look like this:
+
+```json
+{
+ "author": {
+ "id": "04bf6c1a69bb8e9679644874c85f82e337b40d92df9d8d4176f1c5e5c6627058"
+ },
+ "ops": [
+ {
+ "type": 3,
+ "timestamp": 1647377254,
+ "nonce": "SRQwUWTJCXAmQBIS+1ctKgOcbF0=",
+ "message": "Adding a comment",
+ "files": null
+ },
+ {
+ "type": 4,
+ "timestamp": 1647377257,
+ "nonce": "la/HaRPMvD77/cJSJOUzKWuJdY8=",
+ "status": 1
+ }
+ ]
+}
+```
+
+To reference our `OperationPack`, we create a git `Tree`; it references our
+`OperationPack` `Blob` under `"/ops"`. If any edit operation includes a media
+(for instance in a text message), we can store that media as a `Blob` and
+reference it here under `"/media"`.
+
+To complete the picture, we create a git `Commit` that references our `Tree`.
+Each time we add more `Operation`s to our bug, we add a new `Commit` with the
+same data-structure to form a chain of `Commit`s.
+
+This chain of `Commit`s is made available as a git `Reference` under
+`refs/<namespace>/<id>`. We can later use this reference to push our data to a
+git remote. As git will push any data needed as well, everything will be pushed
+to the remote, including the media.
+
+Here is the complete picture:
+
+![git graph of a simple bug](../assets/bug-graph.png)
+
+## Time is unreliable
+
+Before being able to merge conflicts, let's start with some building blocks.
+
+It would be very tempting to use the `Operation`'s timestamp to give us the
+order to compile the final state. However, you can't rely on the time provided
+by other people (their clock might be off) for anything other than just display.
+This is a fundamental limitation of distributed system, and even more so when
+actors might want to game the system.
+
+Instead, we are going to use
+[Lamport logical clock](https://en.wikipedia.org/wiki/Lamport_timestamps). A
+Lamport clock is a simple counter of events. This logical clock gives us a
+partial ordering:
+
+- if L1 \< L2, L1 happened before L2
+- if L1 > L2, L1 happened after L2
+- if L1 == L2, we can't tell which happened first: it's a concurrent edition
+
+Each time we are appending something to the data (create an `Entity`, add an
+`Operation`) a logical time will be attached, with the highest time value we are
+aware of, plus one. This declares a causality in the events and allows ordering
+entities and operations.
+
+The first commit of an `Entity` will have both a creation time and edit time
+clock, while a later commit will only have an edit time clock. These clocks
+value are serialized directly in the `Tree` entry name (for example:
+`"create-clock-4"`). As a `Tree` entry needs to reference something, we
+reference the git `Blob` with an empty content. As all of these entries will
+reference the same `Blob`, no network transfer is needed as long as you already
+have any entity in your repository.
+
+Example of a `Tree` of the first commit of an entity:
+
+```
+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 create-clock-14
+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 edit-clock-137
+100644 blob a020a85baa788e12699a4d83dd735578f0d78c75 ops
+```
+
+Example of a `Tree` of a later commit of an entity:
+
+```
+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 edit-clock-154
+100644 blob 68383346c1a9503f28eec888efd300e9fc179ca0 ops
+```
+
+## Entities and Operation's ID
+
+`Operation`s can be referenced - in the data model or by users - with an
+identifier. This identifier is computed from the `Operation`'s data itself, with
+a hash of that data: `id = hash(json(op))`
+
+For entities, `git-bug` uses as identifier the hash of the first `Operation` of
+the entity, as serialized on disk.
+
+The same way as git does, this hash is displayed truncated to a 7 characters
+string to a human user. Note that when specifying a bug id in a command, you can
+enter as few characters as you want, as long as there is no ambiguity. If
+multiple entities match your prefix, `git-bug` will complain and display the
+potential matches.
+
+## Entities support conflict resolution
+
+Now that we have all that, we can finally merge our entities without conflict,
+and collaborate with other users. Let's start by getting rid of two simple
+scenarios:
+
+- if we simply pull updates, we move forward our local reference. We get an
+ update of our graph that we read as usual.
+- if we push fast-forward updates, we move forward the remote reference and
+ other users can update their reference as well.
+
+The tricky part happens when we have concurrent editions. If we pull updates
+while we have local changes (non-straightforward in git term), `git-bug` creates
+the equivalent of a merge commit to merge both branches into a DAG. This DAG has
+a single root containing the first operation, but can have branches that get
+merged back into a single head pointed by the reference.
+
+As we don't have a purely linear series of commits/`Operations`s, we need a
+deterministic ordering to always apply operations in the same order.
+
+`git-bug` applies the following algorithm:
+
+1. load and read all the commits and the associated `OperationPack`s
+2. make sure that the Lamport clocks respect the DAG structure: a parent
+ commit/`OperationPack` (that is, towards the head) cannot have a clock that
+ is higher or equal than its direct child. If such a problem happens, the
+ commit is refused/discarded.
+3. individual `Operation`s are assembled together and ordered given the
+ following priorities:
+ 1. the edition's lamport clock if not concurrent
+ 2. the lexicographic order of the `OperationPack`'s identifier
+
+Step 2 is providing and enforcing a constraint over the `Operation`'s logical
+clocks. What that means, is that **we inherit the implicit ordering given by the
+DAG**. Later, logical clocks refine that ordering. This - coupled with signed
+commits - has the nice property of limiting how this data model can be abused.
+
+Here is an example of such an ordering:
+
+![merge scenario 1](../assets/merge-1.png)
+
+We can see that:
+
+- Lamport clocks respect the DAG structure
+- the final `Operation` order is \[A,B,C,D,E,F\], according to those clocks
+
+When we have concurrent editions, we apply a secondary ordering, based on the
+`OperationPack`'s identifier:
+
+![merge scenario 2](../assets/merge-2.png)
+
+This secondary ordering doesn't carry much meaning, but it's unbiased and hard
+to abuse.
diff --git a/doc/feature-matrix.md b/doc/feature-matrix.md
new file mode 100644
index 00000000..18e37c18
--- /dev/null
+++ b/doc/feature-matrix.md
@@ -0,0 +1,151 @@
+# User facing capabilities
+
+This document tries to give an overview of what is currently supported, and by
+extension where effort can be focused to bring feature completion and parity.
+
+As git-bug is a free software project, accept and rely on contributor, those
+feature matrices kinda define a roadmap, in the sense that anything mentioned
+below is a planned feature and can be worked on. This does not mean that a
+feature not mentioned here should not be considered, just maybe check the issue
+tracker and come talk about it.
+
+This document however does not show all the untold work required to support
+those user-facing capabilities. There has been a ton of work behind the scene
+and more will be required over time.
+
+βœ…: working 🟠: partial implementation ❌: not working
+
+## Other goals
+
+Some goals don't really fit below, so I'll mention them here:
+
+- have the webUI accept external OAuth (Github, ...) and act as a public portal
+ where user outside the project can browse and interact with the project
+- project configuration (valid labels, ...)
+- commit signature to fully authenticate user's interaction
+- interface with the system keyring, to distribute and expose known public keys
+ and allow checking signed commit in normal git workflow
+- privileged roles (admin, ...) and enforcing the corresponding rules
+- package the webui as a desktop app
+
+Additionally, some other are captured as
+[Github issues](https://github.com/git-bug/git-bug/issues) or
+[Discussions](https://github.com/git-bug/git-bug/discussions).
+
+## Entities
+
+The most high level overview of what kind of entities are supported and where.
+
+| | Core | CLI | TermUI | WebUI |
+| -------------- | :--: | :-: | :----: | :---: |
+| Identities | βœ… | βœ… | βœ… | βœ… |
+| Bug | βœ… | βœ… | βœ… | βœ… |
+| Board | 🟠 | 🟠 | ❌ | ❌ |
+| Pull-request | ❌ | ❌ | ❌ | ❌ |
+| Project Config | ❌ | ❌ | ❌ | ❌ |
+
+More specific features across the board.
+
+| | Core | CLI | TermUI | WebUI |
+| ------------------ | :--: | :-: | :----: | :---: |
+| Media embedding | 🟠 | ❌ | ❌ | ❌ |
+| Fast indexing | βœ… | βœ… | βœ… | βœ… |
+| Markdown rendering | N/A | ❌ | ❌ | βœ… |
+
+#### Identities
+
+| | Core | CLI | TermUI | WebUI |
+| ----------------------- | :--: | :-: | :----: | :---: |
+| Public keys | 🟠 | ❌ | ❌ | ❌ |
+| Private keys management | 🟠 | ❌ | ❌ | ❌ |
+| Identity edition | βœ… | βœ… | ❌ | ❌ |
+| Identity adoption | βœ… | βœ… | ❌ | ❌ |
+| Identity protection | 🟠 | ❌ | ❌ | ❌ |
+
+#### Bugs
+
+| | Core | CLI | TermUI | WebUI |
+| ----------------- | :--: | :-: | :----: | :---: |
+| Comments | βœ… | βœ… | βœ… | βœ… |
+| Comments edition | βœ… | βœ… | βœ… | βœ… |
+| Comments deletion | βœ… | ❌ | ❌ | ❌ |
+| Labels | βœ… | βœ… | βœ… | βœ… |
+| Status | βœ… | βœ… | βœ… | βœ… |
+| Title edition | βœ… | βœ… | βœ… | βœ… |
+| Assignee | ❌ | ❌ | ❌ | ❌ |
+| Milestone | ❌ | ❌ | ❌ | ❌ |
+
+## Bridges
+
+### Importers
+
+General capabilities of importers:
+
+| | Github | Gitlab | Jira | Launchpad |
+| ----------------------------------------------- | :----: | :----: | :--: | :-------: |
+| **incremental**<br/>(can import more than once) | βœ… | βœ… | βœ… | ❌ |
+| **with resume**<br/>(download only new data) | βœ… | βœ… | βœ… | ❌ |
+| **media/files** | ❌ | ❌ | ❌ | ❌ |
+| **automated test suite** | βœ… | βœ… | ❌ | ❌ |
+
+Identity support:
+
+| | Github | Gitlab | Jira | Launchpad |
+| ----------------- | :----: | :----: | :--: | :-------: |
+| **identities** | βœ… | βœ… | βœ… | βœ… |
+| identities update | ❌ | ❌ | ❌ | ❌ |
+| public keys | ❌ | ❌ | ❌ | ❌ |
+
+Bug support:
+
+| | Github | Gitlab | Jira | Launchpad |
+| ---------------- | :----: | :----: | :--: | :-------: |
+| **bug** | βœ… | βœ… | βœ… | βœ… |
+| comments | βœ… | βœ… | βœ… | βœ… |
+| comment editions | βœ… | ❌ | βœ… | ❌ |
+| labels | βœ… | βœ… | βœ… | ❌ |
+| status | βœ… | βœ… | βœ… | ❌ |
+| title edition | βœ… | βœ… | βœ… | ❌ |
+| Assignee | ❌ | ❌ | ❌ | ❌ |
+| Milestone | ❌ | ❌ | ❌ | ❌ |
+
+Board support:
+
+| | Github | Gitlab | Jira | Launchpad |
+| --------- | :----: | :----: | :--: | :-------: |
+| **board** | ❌ | ❌ | ❌ | ❌ |
+
+### Exporters
+
+**General capabilities of exporters**:
+
+| | Github | Gitlab | Jira |
+| ----------------------------------------------- | :----: | :----: | :--: |
+| **incremental**<br/>(can export more than once) | βœ… | βœ… | βœ… |
+| **with resume**<br/>(upload only new data) | βœ… | βœ… | βœ… |
+| **automated test suite** | βœ… | βœ… | ❌ |
+
+**Identity support**:
+
+| | Github | Gitlab | Jira |
+| ----------------- | :----: | :----: | :--: |
+| **identities** | βœ… | βœ… | βœ… |
+| identities update | ❌ | ❌ | ❌ |
+
+Note: as the target bug tracker require accounts and credentials, there is only
+so much that an exporter can do about identities. A bridge should be able to
+load and use credentials for multiple remote account, but when they are not
+available, the corresponding changes can't be replicated.
+
+**Bug support**:
+
+| | Github | Gitlab | Jira |
+| ---------------- | :----: | :----: | :--: |
+| **bugs** | βœ… | βœ… | βœ… |
+| comments | βœ… | βœ… | βœ… |
+| comment editions | βœ… | βœ… | βœ… |
+| labels | βœ… | βœ… | βœ… |
+| status | βœ… | βœ… | βœ… |
+| title edition | βœ… | βœ… | βœ… |
+| Assignee | ❌ | ❌ | ❌ |
+| Milestone | ❌ | ❌ | ❌ |
diff --git a/doc/feature_matrix.md b/doc/feature_matrix.md
deleted file mode 100644
index a0e19232..00000000
--- a/doc/feature_matrix.md
+++ /dev/null
@@ -1,137 +0,0 @@
-# User facing capabilities
-
-This document tries to give an overview of what is currently supported, and by extension where effort can be focused to bring feature completion and parity.
-
-As git-bug is a free software project, accept and rely on contributor, those feature matrices kinda define a roadmap, in the sense that anything mentioned below is a planned feature and can be worked on. This does not mean that a feature not mentioned here should not be considered, just maybe check the issue tracker and come talk about it.
-
-This document however does not show all the untold work required to support those user-facing capabilities. There has been a ton of work behind the scene and more will be required over time.
-
-βœ…: working 🟠: partial implementation ❌: not working
-
-## Other goals
-
-Some goals don't really fit below, so I'll mention them here:
-- have the webUI accept external OAuth (Github, ...) and act as a public portal where user outside the project can browse and interact with the project
-- project configuration (valid labels, ...)
-- commit signature to fully authenticate user's interaction
-- interface with the system keyring, to distribute and expose known public keys and allow checking signed commit in normal git workflow
-- privileged roles (admin, ...) and enforcing the corresponding rules
-- package the webui as a desktop app
-
-Additionally, some other are captured as [Github issues](https://github.com/git-bug/git-bug/issues) or [Discussions](https://github.com/git-bug/git-bug/discussions).
-
-## Entities
-
-The most high level overview of what kind of entities are supported and where.
-
-| | Core | CLI | TermUI | WebUI |
-|----------------|:----:|:---:|:------:|:-----:|
-| Identities | βœ… | βœ… | βœ… | βœ… |
-| Bug | βœ… | βœ… | βœ… | βœ… |
-| Board | 🟠 | 🟠 | ❌ | ❌ |
-| Pull-request | ❌ | ❌ | ❌ | ❌ |
-| Project Config | ❌ | ❌ | ❌ | ❌ |
-
-More specific features across the board.
-
-| | Core | CLI | TermUI | WebUI |
-|--------------------|:----:|:---:|:------:|:-----:|
-| Media embedding | 🟠 | ❌ | ❌ | ❌ |
-| Fast indexing | βœ… | βœ… | βœ… | βœ… |
-| Markdown rendering | N/A | ❌ | ❌ | βœ… |
-
-#### Identities
-
-| | Core | CLI | TermUI | WebUI |
-|-------------------------|:----:|:---:|:------:|:-----:|
-| Public keys | 🟠 | ❌ | ❌ | ❌ |
-| Private keys management | 🟠 | ❌ | ❌ | ❌ |
-| Identity edition | βœ… | βœ… | ❌ | ❌ |
-| Identity adoption | βœ… | βœ… | ❌ | ❌ |
-| Identity protection | 🟠 | ❌ | ❌ | ❌ |
-
-#### Bugs
-
-| | Core | CLI | TermUI | WebUI |
-|-------------------|:----:|:---:|:------:|:-----:|
-| Comments | βœ… | βœ… | βœ… | βœ… |
-| Comments edition | βœ… | βœ… | βœ… | βœ… |
-| Comments deletion | βœ… | ❌ | ❌ | ❌ |
-| Labels | βœ… | βœ… | βœ… | βœ… |
-| Status | βœ… | βœ… | βœ… | βœ… |
-| Title edition | βœ… | βœ… | βœ… | βœ… |
-| Assignee | ❌ | ❌ | ❌ | ❌ |
-| Milestone | ❌ | ❌ | ❌ | ❌ |
-
-
-## Bridges
-
-### Importers
-
-General capabilities of importers:
-
-| | Github | Gitlab | Jira | Launchpad |
-|-------------------------------------------------|:------:|:------:|:----:|:---------:|
-| **incremental**<br/>(can import more than once) | βœ… | βœ… | βœ… | ❌ |
-| **with resume**<br/>(download only new data) | βœ… | βœ… | βœ… | ❌ |
-| **media/files** | ❌ | ❌ | ❌ | ❌ |
-| **automated test suite** | βœ… | βœ… | ❌ | ❌ |
-
-Identity support:
-
-| | Github | Gitlab | Jira | Launchpad |
-|-------------------|:------:|:------:|:----:|:---------:|
-| **identities** | βœ… | βœ… | βœ… | βœ… |
-| identities update | ❌ | ❌ | ❌ | ❌ |
-| public keys | ❌ | ❌ | ❌ | ❌ |
-
-Bug support:
-
-| | Github | Gitlab | Jira | Launchpad |
-|------------------|:------:|:------:|:----:|:---------:|
-| **bug** | βœ… | βœ… | βœ… | βœ… |
-| comments | βœ… | βœ… | βœ… | βœ… |
-| comment editions | βœ… | ❌ | βœ… | ❌ |
-| labels | βœ… | βœ… | βœ… | ❌ |
-| status | βœ… | βœ… | βœ… | ❌ |
-| title edition | βœ… | βœ… | βœ… | ❌ |
-| Assignee | ❌ | ❌ | ❌ | ❌ |
-| Milestone | ❌ | ❌ | ❌ | ❌ |
-
-Board support:
-
-| | Github | Gitlab | Jira | Launchpad |
-|-----------|:------:|:------:|:----:|:---------:|
-| **board** | ❌ | ❌ | ❌ | ❌ |
-
-### Exporters
-
-**General capabilities of exporters**:
-
-| | Github | Gitlab | Jira |
-|-------------------------------------------------|:------:|:------:|:----:|
-| **incremental**<br/>(can export more than once) | βœ… | βœ… | βœ… |
-| **with resume**<br/>(upload only new data) | βœ… | βœ… | βœ… |
-| **automated test suite** | βœ… | βœ… | ❌ |
-
-**Identity support**:
-
-| | Github | Gitlab | Jira |
-|-------------------|:------:|:------:|:----:|
-| **identities** | βœ… | βœ… | βœ… |
-| identities update | ❌ | ❌ | ❌ |
-
-Note: as the target bug tracker require accounts and credentials, there is only so much that an exporter can do about identities. A bridge should be able to load and use credentials for multiple remote account, but when they are not available, the corresponding changes can't be replicated.
-
-**Bug support**:
-
-| | Github | Gitlab | Jira |
-|------------------|:------:|:------:|:----:|
-| **bugs** | βœ… | βœ… | βœ… |
-| comments | βœ… | βœ… | βœ… |
-| comment editions | βœ… | βœ… | βœ… |
-| labels | βœ… | βœ… | βœ… |
-| status | βœ… | βœ… | βœ… |
-| title edition | βœ… | βœ… | βœ… |
-| Assignee | ❌ | ❌ | ❌ |
-| Milestone | ❌ | ❌ | ❌ |
diff --git a/doc/gen_docs.go b/doc/generate.go
index ac5417d8..0001f1a7 100644
--- a/doc/gen_docs.go
+++ b/doc/generate.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "strings"
"sync"
"time"
@@ -13,8 +14,14 @@ import (
"github.com/git-bug/git-bug/commands"
)
+// TaskError holds a given task name and the error it returned (if any)
+type TaskError struct {
+ name string
+ err error
+}
+
func main() {
- fmt.Println("Generating documentation ...")
+ fmt.Println("Generating documentation...")
tasks := map[string]func(*cobra.Command) error{
"ManPage": genManPage,
@@ -22,6 +29,7 @@ func main() {
}
var wg sync.WaitGroup
+ errs := make(chan TaskError, len(tasks))
for name, f := range tasks {
wg.Add(1)
go func(name string, f func(*cobra.Command) error) {
@@ -29,7 +37,8 @@ func main() {
root := commands.NewRootCommand()
err := f(root)
if err != nil {
- fmt.Printf(" - %s: %v\n", name, err)
+ fmt.Printf(" - %s: FATAL\n", name)
+ errs <- TaskError{name: name, err: err}
return
}
fmt.Printf(" - %s: ok\n", name)
@@ -37,6 +46,19 @@ func main() {
}
wg.Wait()
+ close(errs)
+
+ if len(errs) > 0 {
+ fmt.Println()
+ for e := range errs {
+ fmt.Printf(" Error generating %s:\n", strings.ToLower(e.name))
+ for _, line := range strings.Split(e.err.Error(), "\n") {
+ fmt.Printf(" %s\n", line)
+ }
+ fmt.Println()
+ }
+ os.Exit(1)
+ }
}
func genManPage(root *cobra.Command) error {
@@ -80,5 +102,9 @@ func genMarkdown(root *cobra.Command) error {
}
}
- return doc.GenMarkdownTree(root, dir)
+ if err := doc.GenMarkdownTree(root, dir); err != nil {
+ return err
+ }
+
+ return nil
}
diff --git a/doc/howto-github.md b/doc/howto-github.md
deleted file mode 100644
index c5668e82..00000000
--- a/doc/howto-github.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# How-to: Read and edit offline your Github/Gitlab/Jira issues with git-bug
-
-[git-bug](https://github.com/git-bug/git-bug) is a standalone distributed bug-tracker that is embedded in git. In short, if you have a git repository you can use it to store bugs alongside your code (without mixing them though!), push and pull them to/from a normal git remote to collaborate.
-
-<p align="center">
- <img src="../misc/diagrams/native_workflow.png" alt="Native workflow">
-</p>
-
-Bridges with other bug-trackers are first-class citizen in `git-bug`. Notably, they are bidirectional, incremental and relatively fast. This means that a perfectly valid way to use `git-bug` is as a sort of remote for Github where you synchronize all the issues of a repository to later read and edit them and then propagate your changes back to Github.
-
-<p align="center">
- <img src="../misc/diagrams/bridge_workflow.png" alt="Bridge workflow">
-</p>
-
-This has several upsides:
-- works offline, including edition
-- browsing is pretty much instant
-- you get to choose the UI you prefer between CLI, interactive terminal UI or web UI
-- you get a near complete backup in case Github is down or no longer fit your needs
-
-Note: at the moment, Gitlab and Jira are also fully supported.
-
-## Installation
-
-Follow the [installation instruction](https://github.com/git-bug/git-bug#installation). The simplest way is to download a pre-compiled binary from [the latest release](https://github.com/git-bug/git-bug/releases/latest) and to put it anywhere in your `$PATH`.
-
-Check that `git-bug` is properly installed by running `git bug version`. If everything is alright, the version of the binary will be displayed.
-
-## Configuration
-
-1. From within the git repository you care about, run `git bug bridge configure` and follow the wizard's steps:
- 1. Choose `github`.
- 1. Type a name for the bridge configuration. As you can configure multiple bridges, this name will allow you to choose when there is an ambiguity.
- 1. Setup the remote Github project. The wizard is smart enough to inspect the git remote and detect the potential project. Otherwise, enter the project URL like this: `https://github.com/git-bug/git-bug`
- 1. Enter your login on Github
- 1. Setup an authentication token. You can either use the interactive token creation, enter your own token or select an existing token, if any.
-1. Run `git bug bridge pull` and let it run to import the issues and identities.
-
-## Basic usage
-
-You can interact with `git-bug` through the command line (see the [Readme](../README.md#cli-usage) for more details):
-```bash
-# Create a new bug
-git bug add
-# List existing bugs
-git bug ls
-# Display a bug's detail
-git bug show <bugId>
-# Add a new comment
-git bug comment <bugId>
-# Push everything to a normal git remote
-git bug push [<remote>]
-# Pull updates from a git remote
-git bug pull [<remote>]
-```
-
-In particular, the key commands to interact with Github are:
-```bash
-# Replicate your changes to the remote bug-tracker
-git bug bridge push [<bridge>]
-# Retrieve updates from the remote bug-tracker
-git bug bridge pull [<bridge>]
-```
-
-The command line tools are really meant for programmatic usage or to integrate `git-bug` into your editor of choice. For day to day usage, the recommended way is the interactive terminal UI. You can start it with `git bug termui`:
-
-![termui recording](../misc/termui_recording.gif)
-
-For a richer and more user friendly UI, `git-bug` proposes a web UI (read-only at the moment). You can start it with `git bug webui`:
-
-![web UI screenshot](../misc/webui2.png)
-
-## Want more?
-
-If you interested to read more about `git-bug`, have a look at the following:
-- [the project itself, with a more complete readme](https://github.com/git-bug/git-bug)
-- [a bird view of the internals](https://github.com/git-bug/git-bug/blob/master/doc/architecture.md)
-- [a description of the data model](https://github.com/git-bug/git-bug/blob/master/doc/model.md)
-
-Of course, if you want to contribute the door is way open :-)
diff --git a/doc/model.md b/doc/model.md
deleted file mode 100644
index 266aa3ed..00000000
--- a/doc/model.md
+++ /dev/null
@@ -1,145 +0,0 @@
-git-bug's reusable entity data model
-====================================
-
-This document explains how git-bug's reusable distributed data structure in git is working. This data structure is capable of:
-- storing an entity (bug, pull-request, config...) and its complete history in git
-- carry signed authorship of editions
-- use git remotes as a medium for synchronisation and collaboration
-- merge conflicts
-- respect the rules you define as to what edition are possible
-- carry attached media
-
-If you are looking for a different writing format or to see how you can easily make your own, checkout [the example code](../entity/dag/example_test.go).
-
-If you are not familiar with [git internals](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects), you might first want to read about them, as the `git-bug` data model is built on top of them.
-
-## Entities (bug, author, ...) are a series of edit operations
-
-As entities are stored and edited in multiple processes at the same time, it's not possible to store the current state like it would be done in a normal application. If two processes change the same entity and later try to merge the states, we wouldn't know which change takes precedence or how to merge those states.
-
-To deal with this problem, you need a way to merge these changes in a meaningful way. Instead of storing the final bug data directly, we store a series of edit `Operation`s. This is a common idea, notably with [Operation-based CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#Operation-based_CRDTs).
-
-![ordered operations](operations.png)
-
-To get the final state of an entity, we apply these `Operation`s in the correct order on an empty state, to compute (aka "compile") our view.
-
-## Entities are stored in git objects
-
-An `Operation` is a piece of data, including:
-
-- a type identifier
-- an author (a reference to another entity)
-- a timestamp (there is also one or two [Lamport time](#time-is-unreliable))
-- all the data required by that operation type (a message, a status ...)
-- a random [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) to ensure we have enough entropy, as the operation identifier is a hash of that data (more on that later)
-
-These `Operation`s are aggregated in an `OperationPack`, a simple array. An `OperationPack` represents an edit session of the entity. As the operation's author is the same for all the `OperationPack` we only store it once.
-
-We store this pack in git as a git `Blob`; that consists of a string containing a JSON array of operations. One such pack -- here with two operations -- might look like this:
-
-```json
-{
- "author": {
- "id": "04bf6c1a69bb8e9679644874c85f82e337b40d92df9d8d4176f1c5e5c6627058"
- },
- "ops": [
- {
- "type": 3,
- "timestamp": 1647377254,
- "nonce": "SRQwUWTJCXAmQBIS+1ctKgOcbF0=",
- "message": "Adding a comment",
- "files": null
- },
- {
- "type": 4,
- "timestamp": 1647377257,
- "nonce": "la/HaRPMvD77/cJSJOUzKWuJdY8=",
- "status": 1
- }
- ]
-}
-```
-
-To reference our `OperationPack`, we create a git `Tree`; it references our `OperationPack` `Blob` under `"/ops"`. If any edit operation includes a media (for instance in a text message), we can store that media as a `Blob` and reference it here under `"/media"`.
-
-To complete the picture, we create a git `Commit` that references our `Tree`. Each time we add more `Operation`s to our bug, we add a new `Commit` with the same data-structure to form a chain of `Commit`s.
-
-This chain of `Commit`s is made available as a git `Reference` under `refs/<namespace>/<id>`. We can later use this reference to push our data to a git remote. As git will push any data needed as well, everything will be pushed to the remote, including the media.
-
-Here is the complete picture:
-
-![git graph of a simple bug](bug-graph-1.png)
-
-## Time is unreliable
-
-Before being able to merge conflicts, let's start with some building blocks.
-
-It would be very tempting to use the `Operation`'s timestamp to give us the order to compile the final state. However, you can't rely on the time provided by other people (their clock might be off) for anything other than just display. This is a fundamental limitation of distributed system, and even more so when actors might want to game the system.
-
-Instead, we are going to use [Lamport logical clock](https://en.wikipedia.org/wiki/Lamport_timestamps). A Lamport clock is a simple counter of events. This logical clock gives us a partial ordering:
-
-- if L1 < L2, L1 happened before L2
-- if L1 > L2, L1 happened after L2
-- if L1 == L2, we can't tell which happened first: it's a concurrent edition
-
-
-Each time we are appending something to the data (create an `Entity`, add an `Operation`) a logical time will be attached, with the highest time value we are aware of, plus one. This declares a causality in the events and allows ordering entities and operations.
-
-The first commit of an `Entity` will have both a creation time and edit time clock, while a later commit will only have an edit time clock. These clocks value are serialized directly in the `Tree` entry name (for example: `"create-clock-4"`). As a `Tree` entry needs to reference something, we reference the git `Blob` with an empty content. As all of these entries will reference the same `Blob`, no network transfer is needed as long as you already have any entity in your repository.
-
-Example of a `Tree` of the first commit of an entity:
-```
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 create-clock-14
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 edit-clock-137
-100644 blob a020a85baa788e12699a4d83dd735578f0d78c75 ops
-```
-
-Example of a `Tree` of a later commit of an entity:
-```
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 edit-clock-154
-100644 blob 68383346c1a9503f28eec888efd300e9fc179ca0 ops
-```
-
-## Entities and Operation's ID
-
-`Operation`s can be referenced - in the data model or by users - with an identifier. This identifier is computed from the `Operation`'s data itself, with a hash of that data: `id = hash(json(op))`
-
-For entities, `git-bug` uses as identifier the hash of the first `Operation` of the entity, as serialized on disk.
-
-The same way as git does, this hash is displayed truncated to a 7 characters string to a human user. Note that when specifying a bug id in a command, you can enter as few characters as you want, as long as there is no ambiguity. If multiple entities match your prefix, `git-bug` will complain and display the potential matches.
-
-## Entities support conflict resolution
-
-Now that we have all that, we can finally merge our entities without conflict, and collaborate with other users. Let's start by getting rid of two simple scenarios:
-
-- if we simply pull updates, we move forward our local reference. We get an update of our graph that we read as usual.
-- if we push fast-forward updates, we move forward the remote reference and other users can update their reference as well.
-
-The tricky part happens when we have concurrent editions. If we pull updates while we have local changes (non-straightforward in git term), `git-bug` creates the equivalent of a merge commit to merge both branches into a DAG. This DAG has a single root containing the first operation, but can have branches that get merged back into a single head pointed by the reference.
-
-As we don't have a purely linear series of commits/`Operations`s, we need a deterministic ordering to always apply operations in the same order.
-
-`git-bug` applies the following algorithm:
-
-1. load and read all the commits and the associated `OperationPack`s
-2. make sure that the Lamport clocks respect the DAG structure: a parent commit/`OperationPack` (that is, towards the head) cannot have a clock that is higher or equal than its direct child. If such a problem happens, the commit is refused/discarded.
-3. individual `Operation`s are assembled together and ordered given the following priorities:
- 1. the edition's lamport clock if not concurrent
- 2. the lexicographic order of the `OperationPack`'s identifier
-
-Step 2 is providing and enforcing a constraint over the `Operation`'s logical clocks. What that means, is that **we inherit the implicit ordering given by the DAG**. Later, logical clocks refine that ordering. This - coupled with signed commits - has the nice property of limiting how this data model can be abused.
-
-Here is an example of such an ordering:
-
-![merge scenario 1](merge1.png)
-
-We can see that:
-
-- Lamport clocks respect the DAG structure
-- the final `Operation` order is [A,B,C,D,E,F], according to those clocks
-
-When we have concurrent editions, we apply a secondary ordering, based on the `OperationPack`'s identifier:
-
-![merge scenario 2](merge2.png)
-
-This secondary ordering doesn't carry much meaning, but it's unbiased and hard to abuse.
diff --git a/doc/queries.md b/doc/queries.md
deleted file mode 100644
index 358948eb..00000000
--- a/doc/queries.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# Searching bugs
-
-You can search bugs using a micro query language for both filtering and sorting. A query could look like this:
-
-```
-status:open sort:edit
-```
-
-A few tips:
-
-- queries are case insensitive.
-- you can combine as many qualifiers as you want.
-- you can use double quotes for multi-word search terms. For example, `author:"RenΓ© Descartes"` searches for bugs opened by RenΓ© Descartes, whereas `author:RenΓ© Descartes` will search for bug with RenΓ© as the author and containing Descartes in a text.
-- instead of a complete ID, you can use any prefix length, as long as there is no ambiguity. For example `participant=9ed1a`.
-
-
-## Filtering
-
-### Filtering by status
-
-You can filter bugs based on their status.
-
-| Qualifier | Example |
-|-----------------|-------------------------------------|
-| `status:open` | `status:open` matches open bugs |
-| `status:closed` | `status:closed` matches closed bugs |
-
-### Filtering by author
-
-You can filter based on the person who opened the bug.
-
-| Qualifier | Example |
-|----------------|----------------------------------------------------------------------------------|
-| `author:QUERY` | `author:descartes` matches bugs opened by `RenΓ© Descartes` or `Robert Descartes` |
-| | `author:"renΓ© descartes"` matches bugs opened by `RenΓ© Descartes` |
-
-### Filtering by participant
-
-You can filter based on the person who participated in any activity related to the bug (opened bug or added a comment).
-
-| Qualifier | Example |
-|---------------------|----------------------------------------------------------------------------------------------------|
-| `participant:QUERY` | `participant:descartes` matches bugs opened or commented by `RenΓ© Descartes` or `Robert Descartes` |
-| | `participant:"renΓ© descartes"` matches bugs opened or commented by `RenΓ© Descartes` |
-
-### Filtering by actor
-
-You can filter based on the person who interacted with the bug.
-
-| Qualifier | Example |
-|---------------|---------------------------------------------------------------------------------|
-| `actor:QUERY` | `actor:descartes` matches bugs edited by `RenΓ© Descartes` or `Robert Descartes` |
-| | `actor:"renΓ© descartes"` matches bugs edited by `RenΓ© Descartes` |
-
-**NOTE**: interaction with bugs include: opening the bug, adding comments, adding/removing labels etc...
-
-### Filtering by label
-
-You can filter based on the bug's label.
-
-| Qualifier | Example |
-|---------------|---------------------------------------------------------------------------|
-| `label:LABEL` | `label:prod` matches bugs with the label `prod` |
-| | `label:"Good first issue"` matches bugs with the label `Good first issue` |
-
-### Filtering by title
-
-You can filter based on the bug's title.
-
-| Qualifier | Example |
-|---------------|--------------------------------------------------------------------------------|
-| `title:TITLE` | `title:Critical` matches bugs with a title containing `Critical` |
-| | `title:"Typo in string"` matches bugs with a title containing `Typo in string` |
-
-
-### Filtering by missing feature
-
-You can filter bugs based on the absence of something.
-
-| Qualifier | Example |
-|------------|----------------------------------------|
-| `no:label` | `no:label` matches bugs with no labels |
-
-## Sorting
-
-You can sort results by adding a `sort:` qualifier to your query. β€œDescending” means most recent time or largest ID first, whereas β€œAscending” means oldest time or smallest ID first.
-
-Note: to deal with differently-set clocks on distributed computers, `git-bug` uses a logical clock internally rather than timestamps to order bug changes over time. That means that the timestamps recorded might not match the returned ordering. More on that in [the documentation](model.md#you-cant-rely-on-the-time-provided-by-other-people-their-clock-might-by-off-for-anything-other-than-just-display)
-
-### Sort by Id
-
-| Qualifier | Example |
-|----------------------------|-------------------------------------------------------|
-| `sort:id-desc` | `sort:id-desc` will sort bugs by their descending Ids |
-| `sort:id` or `sort:id-asc` | `sort:id` will sort bugs by their ascending Ids |
-
-### Sort by Creation time
-
-You can sort bugs by their creation time.
-
-| Qualifier | Example |
-|-----------------------------------------|---------------------------------------------------------------------|
-| `sort:creation` or `sort:creation-desc` | `sort:creation` will sort bugs by their descending creation time |
-| `sort:creation-asc` | `sort:creation-asc` will sort bugs by their ascending creation time |
-
-### Sort by Edit time
-
-You can sort bugs by their edit time.
-
-| Qualifier | Example |
-|---------------------------------|---------------------------------------------------------------------|
-| `sort:edit` or `sort:edit-desc` | `sort:edit` will sort bugs by their descending last edition time |
-| `sort:edit-asc` | `sort:edit-asc` will sort bugs by their ascending last edition time |
diff --git a/doc/usage/interfaces.md b/doc/usage/interfaces.md
new file mode 100644
index 00000000..9df342c3
--- /dev/null
+++ b/doc/usage/interfaces.md
@@ -0,0 +1,66 @@
+# Native interfaces
+
+This page provides an overview of the different interfaces `git-bug` supports.
+
+<!-- mdformat-toc start --slug=github --maxlevel=4 --minlevel=2 -->
+
+- [TUI](#tui)
+- [Web UI](#web-ui)
+
+<!-- mdformat-toc end -->
+
+## TUI<a name="tui"></a>
+
+The integrated TUI (text-based user interface) is the recommended way to
+interface with `git-bug` issues in your repository.
+
+To start it, run `git bug termui` in your terminal.
+
+![TUI recording](../assets/tui-recording.gif)
+
+## Web UI<a name="web-ui"></a>
+
+The web UI is packed inside the same binary and serves static content through an
+http server running on the local machine. The frontend interacts with the
+backend through a GraphQL API. [View the schema][gql-schema] for more
+information.
+
+To serve the website locally, run `git bug webui` in your terminal.
+
+> [!NOTE]
+> The web interface is alpha-level software and does not support all of the
+> features of `git-bug`. We recommend using the TUI for most day-to-day
+> operations at the moment.
+
+<details>
+<summary><strong>View the issue feed</strong></summary>
+<center> <img
+ alt="An example of viewing the issue feed in the web interface"
+ src="../assets/web-screenshot-feed.png"
+ width="880"
+/></center>
+</details>
+
+<details>
+<summary><strong>View the discussion for an issue</strong></summary>
+<center><img
+ alt="An example of viewing the discussion for an issue in the web interface"
+ src="../assets/web-screenshot-comments.png"
+ width="880"
+/></center>
+</details>
+
+______________________________________________________________________
+
+##### See more
+
+- [Filtering query results][docs/usage/filter]
+- [How to use bridges][docs/usage/bridges]
+- [Understanding the workflow models][docs/usage/workflows]
+- :house: [Documentation home][docs/home]
+
+[docs/home]: ../README.md
+[docs/usage/bridges]: ./third-party.md
+[docs/usage/filter]: ./query-language.md
+[docs/usage/workflows]: ./workflows.md
+[gql-schema]: ../../api/graphql/schema
diff --git a/doc/usage/query-language.md b/doc/usage/query-language.md
new file mode 100644
index 00000000..c513e0b0
--- /dev/null
+++ b/doc/usage/query-language.md
@@ -0,0 +1,167 @@
+# Search filters
+
+When performing a search (e.g. listing issues), you can use different qualifiers
+to narrow the results. This page provides an overview of these filters, and how
+to use them.
+
+<!-- mdformat-toc start --slug=github --maxlevel=4 --minlevel=2 -->
+
+- [Overview](#overview)
+- [Filtering](#filtering)
+ - [Filtering by status](#filtering-by-status)
+ - [Filtering by author](#filtering-by-author)
+ - [Filtering by participant](#filtering-by-participant)
+ - [Filtering by actor](#filtering-by-actor)
+ - [Filtering by label](#filtering-by-label)
+ - [Filtering by title](#filtering-by-title)
+ - [Filtering by missing feature](#filtering-by-missing-feature)
+- [Sorting](#sorting)
+ - [Sort by Id](#sort-by-id)
+ - [Sort by Creation time](#sort-by-creation-time)
+ - [Sort by Edit time](#sort-by-edit-time)
+
+<!-- mdformat-toc end -->
+
+## Overview<a name="overview"></a>
+
+The query filters in `git-bug` have a familiar look and feel:
+
+```
+status:open sort:edit
+```
+
+**Key things to know**
+
+- All queries are case insensitive
+- You can combine as many qualifiers as you want
+- If you have a space in your qualifier, be sure to wrap it in double quotes. As
+ an example, `author:"RenΓ© Descartes"` would filter for issues opened by
+ `RenΓ© Descartes`, whereas `author:RenΓ© Descartes` filter for `RenΓ©` as the
+ author and return issues that contain `Descartes` somewhere in the title,
+ description, or comments.
+- Instead of a complete ID, you can use any prefix length, as long as it is long
+ enough to be unique (similar to git commit hashes). For example,
+ `participant=9ed1a` would match against participants with an ID of
+ `9ed1af428...` and `9ed1ae24a...`
+
+## Filtering<a name="filtering"></a>
+
+### Filtering by status<a name="filtering-by-status"></a>
+
+You can filter bugs based on their status.
+
+| Qualifier | Example |
+| --------------- | ----------------------------------- |
+| `status:open` | `status:open` matches open bugs |
+| `status:closed` | `status:closed` matches closed bugs |
+
+### Filtering by author<a name="filtering-by-author"></a>
+
+You can filter based on the person who opened the bug.
+
+| Qualifier | Example |
+| -------------- | -------------------------------------------------------------------------------- |
+| `author:QUERY` | `author:descartes` matches bugs opened by `RenΓ© Descartes` or `Robert Descartes` |
+| | `author:"renΓ© descartes"` matches bugs opened by `RenΓ© Descartes` |
+
+### Filtering by participant<a name="filtering-by-participant"></a>
+
+You can filter based on the person who participated in any activity related to
+the bug (opened bug or added a comment).
+
+| Qualifier | Example |
+| ------------------- | -------------------------------------------------------------------------------------------------- |
+| `participant:QUERY` | `participant:descartes` matches bugs opened or commented by `RenΓ© Descartes` or `Robert Descartes` |
+| | `participant:"renΓ© descartes"` matches bugs opened or commented by `RenΓ© Descartes` |
+
+### Filtering by actor<a name="filtering-by-actor"></a>
+
+You can filter based on the person who interacted with the bug.
+
+| Qualifier | Example |
+| ------------- | ------------------------------------------------------------------------------- |
+| `actor:QUERY` | `actor:descartes` matches bugs edited by `RenΓ© Descartes` or `Robert Descartes` |
+| | `actor:"renΓ© descartes"` matches bugs edited by `RenΓ© Descartes` |
+
+> [!NOTE]
+> Interactions with issues include opening the bug, adding comments, adding or
+> removing labels, etc.
+
+### Filtering by label<a name="filtering-by-label"></a>
+
+You can filter based on the bug's label.
+
+| Qualifier | Example |
+| ------------- | ------------------------------------------------------------------------- |
+| `label:LABEL` | `label:prod` matches bugs with the label `prod` |
+| | `label:"Good first issue"` matches bugs with the label `Good first issue` |
+
+### Filtering by title<a name="filtering-by-title"></a>
+
+You can filter based on the bug's title.
+
+| Qualifier | Example |
+| ------------- | ------------------------------------------------------------------------------ |
+| `title:TITLE` | `title:Critical` matches bugs with a title containing `Critical` |
+| | `title:"Typo in string"` matches bugs with a title containing `Typo in string` |
+
+### Filtering by missing feature<a name="filtering-by-missing-feature"></a>
+
+You can filter bugs based on the absence of something.
+
+| Qualifier | Example |
+| ---------- | -------------------------------------- |
+| `no:label` | `no:label` matches bugs with no labels |
+
+## Sorting<a name="sorting"></a>
+
+You can sort results by adding a `sort:` qualifier to your query. β€œDescending”
+means most recent time or largest ID first, whereas β€œAscending” means oldest
+time or smallest ID first.
+
+Note: to deal with differently-set clocks on distributed computers, `git-bug`
+uses a logical clock internally rather than timestamps to order bug changes over
+time. That means that the timestamps recorded might not match the returned
+ordering. To learn more, we encourage you to read about why
+[time is unreliable][docs/design/model].
+
+### Sort by Id<a name="sort-by-id"></a>
+
+| Qualifier | Example |
+| -------------------------- | ----------------------------------------------------- |
+| `sort:id-desc` | `sort:id-desc` will sort bugs by their descending Ids |
+| `sort:id` or `sort:id-asc` | `sort:id` will sort bugs by their ascending Ids |
+
+### Sort by Creation time<a name="sort-by-creation-time"></a>
+
+You can sort bugs by their creation time.
+
+| Qualifier | Example |
+| --------------------------------------- | ------------------------------------------------------------------- |
+| `sort:creation` or `sort:creation-desc` | `sort:creation` will sort bugs by their descending creation time |
+| `sort:creation-asc` | `sort:creation-asc` will sort bugs by their ascending creation time |
+
+### Sort by Edit time<a name="sort-by-edit-time"></a>
+
+You can sort bugs by their edit time.
+
+| Qualifier | Example |
+| ------------------------------- | ------------------------------------------------------------------- |
+| `sort:edit` or `sort:edit-desc` | `sort:edit` will sort bugs by their descending last edition time |
+| `sort:edit-asc` | `sort:edit-asc` will sort bugs by their ascending last edition time |
+
+______________________________________________________________________
+
+##### See more
+
+- [A description of the data model][docs/design/model]
+- [How to use bridges][docs/usage/bridges]
+- [Learn about the native interfaces][docs/usage/interfaces]
+- [Understanding the workflow models][docs/usage/workflows]
+- :house: [Documentation home][docs/home]
+
+[docs/design/model]: ../design/data-model.md#you-cant-rely-on-the-time-provided-by-other-people-their-clock-might-by-off-for-anything-other-than-just-display
+[docs/home]: ../README.md
+[docs/usage/bridges]: ./third-party.md
+[docs/usage/interfaces]: ./interfaces.md
+[docs/usage/workflows]: ./workflows.md
diff --git a/doc/usage/third-party.md b/doc/usage/third-party.md
new file mode 100644
index 00000000..39a09187
--- /dev/null
+++ b/doc/usage/third-party.md
@@ -0,0 +1,113 @@
+# Using third-party platforms via bridges<a name="using-bridges"></a>
+
+This page provides an overview of how to use _bridges_ to sync issues to and
+from third-party platforms.
+
+<!-- mdformat-toc start --slug=github --maxlevel=4 --minlevel=2 -->
+
+- [Overview](#overview)
+- [Supported bridges](#supported-bridges)
+- [Getting started](#getting-started)
+- [Interacting with the bridge](#interacting-with-the-bridge)
+
+<!-- mdformat-toc end -->
+
+## Overview<a name="overview"></a>
+
+Bridges within `git-bug` are bi-directional, incremental, and speedy gateways to
+third-party platforms. Configuring a bridge allows you to push and pull issues
+to and from a third party platform.
+
+This expands the utility and function of `git-bug`: because issues are just
+objects in your git repository, you can import issues from a bridge to work on
+them in bulk, offline, in your preferred environment, at your own pace. When
+you're ready to push your issues back to the external platform again, you'll be
+able to synchronize the changes you made with one simple command.
+
+<p align="center">
+ <img src="../assets/bridge-workflow.png" alt="Bridge workflow">
+</p>
+
+This has several benefits:
+
+- works offline, including edition
+- browsing is pretty much instant
+- you get to choose the UI you prefer between CLI, interactive TUI or in your
+ browser with the WEBUI
+- you have a near-complete archive of issues locally, embedded in your git
+ repository, in case the external platform becomes inaccessible
+- you are free to move to another platform -- your issues follow wherever your
+ repo goes!
+
+## Supported bridges<a name="supported-bridges"></a>
+
+We support a number of bridges:
+
+- Jira
+- GitHub
+- GitLab
+- Launchpad
+
+_For a full list of the features enabled for each bridge, see the
+[feature matrix][docs/feature-matrix]._
+
+## Getting started<a name="getting-started"></a>
+
+1. From within a git repository, run `git bug bridge configure` to start the
+ configuration wizard
+2. Choose the type of bridge you want to configure, e.g. `github`
+3. Type a name for the bridge configuration. As you can configure multiple
+ bridges, this name will allow you to choose when there is an ambiguity.
+4. If you already have a repository created on the external platform, and your
+ local git repository has that as a remote, the configuration wizard will
+ automatically detect the URL. Otherwise, please ensure you enter the
+ appropriate URL for the remote project: something like
+ `https://github.com/git-bug/git-bug`
+5. Create an access token. You can either use the interactive token creation,
+ enter it on your own token, or use an existing token if you already have one
+
+That's it! Once you've completed the wizard, you'll have successfully configured
+a bridge.
+
+## Interacting with the bridge<a name="interacting-with-the-bridge"></a>
+
+To push issues out to the bridge, run:
+
+```bash
+git bug bridge push [NAME]
+```
+
+To pull and integrate updates for issues from the bridge:
+
+```bash
+git bug bridge pull [NAME]
+```
+
+> [!TIP]
+> See the [CLI documentation][doc/cli/bridge] for more information on the
+> command line arguments and options.
+
+The command line is primarily meant for programmatic usage or to interface with
+`git-bug` with scripts or other tools. For day to day usage, we recommend taking
+a look at [the supported interfaces][docs/usage/interfaces], which include a
+robust TUI and an in-progress Web UI.
+
+______________________________________________________________________
+
+##### See more
+
+- [A bird's-eye view of the internal architecture][docs/design/arch]
+- [A description of the data model][docs/design/model]
+- [An overview of the native interfaces][docs/usage/interfaces]
+- [Filtering query results][docs/usage/filter]
+- [Understanding the workflow models][docs/usage/workflows]
+- :house: [Documentation home][docs/home]
+
+[doc/cli/bridge]: ../md/git-bug_bridge.md
+[docs/design/arch]: ../design/architecture.md
+[docs/design/model]: ../design/data-model.md
+[docs/feature-matrix]: ../feature-matrix.md
+[docs/home]: ../README.md
+[docs/usage/filter]: ./query-language.md
+[docs/usage/interfaces]: ./interfaces.md
+[docs/usage/workflows]: ./workflows.md
diff --git a/doc/usage/workflows.md b/doc/usage/workflows.md
new file mode 100644
index 00000000..50477847
--- /dev/null
+++ b/doc/usage/workflows.md
@@ -0,0 +1,62 @@
+# Workflows
+
+This document provides an overview of different workflows that `git-bug`
+supports.
+
+<!-- mdformat-start --slug=github --maxlevel=4 --minlevel=2 -->
+
+## Native workflow
+
+<p align="center">
+ <img src="../assets/native-workflow.png" alt="Native workflow">
+</p>
+
+This is the pure `git-bug` experience. In a similar fashion as with code, use
+`git bug push` and `git bug pull` to push and pull your bugs between git remotes
+and collaborate with your teammate.
+
+_Recommended reading: [CLI documentation][docs/cli]_
+
+## Bridge workflow
+
+<p align="center">
+ <img src="../assets/bridge-workflow.png" alt="Bridge workflow">
+</p>
+
+`git-bug` supports syncing issues with third-party platforms, such as GitHub,
+GitLab, and Jira. This lets you work on issues offline, editing issues in bulk
+with your preferred editor, or to build an archive of any project's issues --
+it's up to you!
+
+_Recommended reading: [How to use bridges][docs/usage/bridges]_
+
+## Web UI workflow
+
+<p align="center">
+ <img src="../assets/webui-workflow.png" alt="Web UI workflow">
+</p>
+
+> [!NOTE]
+> The web UI is a work in progress, and is not feature-complete. To utilize
+> `git-bug` to its full potential, we recommend using the TUI or CLI.
+
+Often, projects needs to have their bug-tracker public and accept editions from
+anyone facing a problem. To support this workflow, `git-bug` aims to have the
+web UI accept external OAuth authentication and act as a public portal. However
+the web UI is not up to speed for that yet. Contributions are very much welcome!
+
+______________________________________________________________________
+
+##### See also<a name="see-also"></a>
+
+- [CLI documentation][docs/cli]
+- [Filtering query results][docs/usage/filter]
+- [How to use bridges][docs/usage/bridges]
+- [Learn about the native interfaces][docs/usage/interfaces]
+- :house: [Documentation home][docs/home]
+
+[docs/cli]: ../md/git-bug.md
+[docs/home]: ../README.md
+[docs/usage/bridges]: ./third-party.md
+[docs/usage/filter]: ./query-language.md
+[docs/usage/interfaces]: ./interfaces.md