PeerDoc is a collaborative real-time rich-text editor with undo/redo, cursor tracking, inline comments, permissions/sharing control over documents, a change history. Things you would expect from a modern collaborative editor on the web.
But the main difference is that it provides two types of collaboration:
- real-time collaboration between collaborators on the draft of the document
- fork and merge request style of collaboration with others, allowing collaboration to scale beyond a small group of collaborators
For more information about PeerDoc, what it can do and how it works, see this blog post.
PeerDoc is a stable prototype. It has been already used in production. All features described above are implemented, but some of them are implemented in its basic form. For example, authentication and registration is currently very simple. Merge requests just show a diff but do not offer discussion. Or decision making to approve merge requests. You cannot add attachments to documents. And so on. See issues for more details.
PeerDoc is distributed as a Docker image. To get the latest stable version,
use registry.gitlab.com/peer/doc/branch/main:latest
.
The Docker image is based on tozd/meteor
Docker image so see there
more details how to run and configure the image.
PeerDoc can be configured using settings.json
file. See example settings file.
tokenSharedSecret
: PeerDoc can be embedded and can acceptuser
query string parameter with a token about the user currently signed in into the parent app. Thatuser
token is encrypted and signed usingtokenSharedSecret
. Used also for authentication of calls to the API.appCivistIntegration
: An object withendpoint
,email
, andpassword
fields. Used when embedded inside Appcivist to notify Appcivist when documents are updated or comments made.apiControlled
: When set totrue
, then creation of documents, forking, merging, etc., can be done only through the API and not through the web interface. Useful when PeerDoc is embedded and the parent app controls the collaboration process.passwordlessAuthDisabled
: By default, PeerDoc comes with simple password less authentication (anyone can just pick an username). Probably you want to disable that in production.mergingForkingOfAllDocuments
: By default, PeerDoc allows forking only published documents (and merging back). (Published documents are those which you cannot edit anymore in real-time.) But you can enable that all documents (including those which are still being edited in real-time) can be forked and merged back to. Depends on what type of collaborative process you want.defaultLanguage
: Default language of the user interface to use, if user does not have its preferred language set.defaultPermissions
: Default permissions to give to new users. By default new users can create documents and view and create comments (but first they have to have access to a documents to comment).
PeerDoc can be embedded in an iframe. You should provide the following query string parameters in the URL you are embedding:
embed
: Set it totrue
to ask PeerDoc to not render toolbar and padding around the main area of the app (it is assumed that the parent app provides those).user
: Provide a JSON-encoded, AES-128-GCM encrypted and signed, base64 encoded token with information about the user. It is not a JWT but a custom token. If user does not yet exist, it is created by PeerDoc internally. JSON has the following fields:avatar
,username
,id
,email
, andlanguage
.
When being embedded (embed
is set to true
) PeerDoc uses window.parent.postMessage
to send a {size: {width, height}}
messages to the parent app
with the size of the embedded content. This allows the parent app to resize
iframe accordingly.
PeerDoc can be controlled through an API. Authentication is done using the user
query string parameter which should contain
user token as described for embedding. Available endpoints:
- POST
/document
: Creates a new document. On success returns a JSON with{status: "success", documentId, path}
. On error returns a JSON with{status: "error"}
. - POST
/document/export/<document id>
: Exports a document to HTML. On success returns a JSON with{status: "success", html}
. On error returns a JSON with{status: "error"}
. - POST
/document/publish/<document id>
: Publishes the document. On success returns a JSON with{status: "success"}
. On error returns a JSON with{status: "error"}
. - POST
/document/share/<document id>
: Configures permissions/sharing control of the document. Accepts a JSON with{visibility, token_users: {admin, edit}}
.visibility
can betrue
orfalse
, corresponding to public and private visibility levels.admin
andedit
are lists of user tokens for which corresponding permission should be set. All other permissions are removed. On success returns a JSON with{status: "success"}
. On error returns a JSON with{status: "error"}
. - POST
/document/fork/<document id>
: Forks the document. On success returns a JSON with{status: "success", documentId, path}
. On error returns a JSON with{status: "error"}
. - POST
/document/merge/<document id>
: Merges the document. On success returns a JSON with{status: "success"}
. On error returns a JSON with{status: "error"}
.
The application uses Meteor web framework. Install it:
$ curl https://install.meteor.com/ | sh
Clone the repository recursively:
$ git clone --recursive https://gitlab.com/peer/doc.git
Install dependencies:
$ meteor npm install
Add and configure settings:
$ cp settings.example.json settings.json
Run it:
$ meteor --settings settings.json
And open http:https://localhost:3000/.
- Meteor
- JavaScript
- SCSS
- Vue + Vuetify
- ProseMirror
See code style guide for more information.
To run a linting tool to check the code style, run:
$ meteor npm run lint
The translations are handled by the vue-gettext package.
To generate translations:
- Run
meteor npm run extract-strings
to extract user-visible strings. - Go to
translations/locale
and find the.po
file associated with the language you want to translate. - Update the
.po
file with translations for extracted strings. - Generate an updated translations JSON file by running
meteor npm run translations
.
$ meteor npm run test-watch
This will watch for any code changes and rerun unit tests. Test results for both server-side and client-side are provided in the terminal.
If you want to run unit tests only once, run:
$ meteor npm run test
If you prefer to see client-side test results in a browser, run:
$ meteor npm run test-watch-browser
And open http:https://localhost:3100/ (note a different port).
Run in one terminal:
$ meteor npm run test-app
This will run the full app in test mode on http:https://localhost:3000/, but you do not have to open it. Run in another terminal:
$ meteor npm run cypress
This will open Cypress runner which we use for acceptance tests. You can select tests to run or run all of them and you will see how they are run in testing browser, and be able to inspect results. It will watch for any changes and rerun tests, too.
If you want to run acceptance tests only once, and see results in the terminal, run:
$ meteor npm run cypress-run
During CI testing acceptance tests are run as well. Results are recorded and available in Cypress Dashboard. Moreover, results are also submitted for visual diffing and are available in Percy.
You can find links to a particular Cypress recording and Percy build for a CI run in GitLab CI's run output.