Clean documentation

This commit is contained in:
Romaric Mourgues
2023-04-17 17:00:03 +02:00
parent a46c6ca0a8
commit 88bd3b2a32
80 changed files with 138 additions and 2492 deletions
@@ -2,16 +2,16 @@
description: >-
This page will document all the services implemented in the new NodeJS
backend. For all the PHP services not yet migrated, please ask us directly on
https://community.twake.app/
https://community.tdrive.app/
---
# 🧱 Backend and APIs
## Twake Services
## TDrive Services
As a frontend developer / connector developer to read our APIs, or to understand our data models or just for fun, here is all the details over Twake backend services.
As a frontend developer / connector developer to read our APIs, or to understand our data models or just for fun, here is all the details over TDrive backend services.
If document are empty, check out our Notion documentation: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b)
If document are empty, check out our Notion documentation: [https://www.notion.so/tdrive/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/tdrive/Backend-documentation-e219323593d2401c9887d0e11b2a597b)
### Services
@@ -25,12 +25,12 @@ If document are empty, check out our Notion documentation: [https://www.notion.s
[notifications/](notifications/README.md))
## Get started to code in Twake
## Get started to code in TDrive
Want to edit Twake code ? Congratulation ! You participate in the development of a great product 😃
Want to edit TDrive code ? Congratulation ! You participate in the development of a great product 😃
[start-working-into-a-service](intro/start-working-into-a-service.md)
[create-a-new-twake-service](intro/create-a-new-twake-service.md)
[create-a-new-tdrive-service](intro/create-a-new-tdrive-service.md)
[intro/platform/](intro/platform/README.md))
@@ -1,17 +1,17 @@
---
description: How applications are managed in Twake backend
description: How applications are managed in TDrive backend
---
# 🍎 Applications
#### Description
**Applications** is everything related to connectors in Twake.
**Applications** is everything related to connectors in TDrive.
An application is described by an identity sheet containing this information:
- **Identity** \(name, description, logo\)
- **API** **preferences** \(Twake→Connector events endpoint, API id and secret, and Connector→Twake allowed IPs\)
- **API** **preferences** \(TDrive→Connector events endpoint, API id and secret, and Connector→TDrive allowed IPs\)
- **Privileges and capabilities** \(List of things the connector can read and can write\)
- **Display information** \(Where the connector is visible, button in chat, configuration in application list etc\)
@@ -5,7 +5,7 @@ description: Application models for backend
# Database models
**applications**\
****Represent an application in the database
\*\*\*\*Represent an application in the database
```javascript
{
@@ -27,7 +27,7 @@ type ApplicationIdentity = {
description: string;
website: string;
categories: string[];
compatibility: "twake"[];
compatibility: "tdrive"[];
};
type ApplicationPublication = {
@@ -53,7 +53,7 @@ type ApplicationAccess = {
};
type ApplicationDisplay = {
twake: {
tdrive: {
"version": 1,
"files" : {
@@ -74,7 +74,7 @@ type ApplicationDisplay = {
//Chat plugin
"chat": {
"input": {
"icon": "", //If defined replace original icon url of your app
"icon": "", //If defined replace original icon url of your app
"type": "file" | "call" //To add in existing apps folder / default icon
},
"commands": [
@@ -113,18 +113,16 @@ type ApplicationDisplay = {
};
```
**company\_application**\
****Represent an application in a company
**company_application**\
\*\*\*\*Represent an application in a company
```javascript
{
"company_id": uuid;
"application_id": uuid;
"id": uuid;
"created_at": number;
"created_by": string; //Will be the default delegated user when doing actions on Twake
"created_by": string; //Will be the default delegated user when doing actions on TDrive
}
```
@@ -1,40 +0,0 @@
---
description: >-
Channels are topics in Twake, users can subscribe to them, can make them
private or can create them.
---
# 🎩 Channels and tabs
### Wording
**Member:** member in company without the tag "guest"
**Guest:** company member with the tag "guest"
**Channel member:** member in the channel
**Channels types:
→ Private:** Relative to a workspace but restricted to a defined group of members
**→ Public:** Relative to a workspace anyone can find the channel and join
**→ Direct:** Relative to a company, a discussion between a set of members but without defined topic
**To understand the routing** please read **"**Collections based rest api:" in "Wording and formating"
TODO [Wording and formatting](https://www.notion.so/Wording-and-formatting-24ef27e094a042aea4899ac6a8039dee)
### What it does
Channel component is **not** responsible of the red badge counter \(notification service is\).
Channel component **is** responsible of keeping track of the message from where the user need to start reading but can be override by notification service if there is a mention to start reading from.
TODO [Some process details and constant s](https://www.notion.so/Some-process-details-and-constant-s-fb5b2d4974da490aa87bb87082af8454)
### Models an APIs
[Database models](database-models.md)
TODO [REST Api / Websockets Api](https://www.notion.so/REST-Api-Websockets-Api-458b153a6a6e46c2925dfc1db3859d3b)
TODO [In/Out microservice](https://www.notion.so/In-Out-microservice-e721e72e542244a69ca3a913e0b405ad)
TODO [Activity models](https://www.notion.so/Activity-models-0fa3acb0a13f41fd98bc98709908eedf)
@@ -1,152 +0,0 @@
---
description: Database models of channel
---
# Database models
## Channels
#### **channels**
The main channel table, this table should only be used when changing things on the channel \(not frequently\) so we don't add counters or last\_activity or anything like that.
```javascript
{
//Primary key
"company_id": "uuid-v4",
"workspace_id": "string" // ("uuid-v4" | "direct")
"id": "uuid-v4",
//Content
"owner": "uuid-v4", //User-id of the channel owner (invisible but used on some access restriction-
"icon": "String",
"name": "String",
"description": "String",
"channel_group": "String",
"visibility": "private" | "public" | "direct"
"default": true | false, //The new members join by default this channel
"archived": false | true,
"archivation_date": 0, //Timestamp
}
```
#### **channel\_defaults**
Contain the default channels
```javascript
{
//Primary key
"company_id": "uuid-v4",
"workspace_id": "uuid-v4"
"id": "uuid-v4" //Channel id
}
```
#### **channel\_counters**
We use a separated table to manage counters for this channel. Currently this is not used to do statistics but can be used to this goal in the future.
```javascript
{
//Primary key
"company_id": "uuid-v4",
"workspace_id": "string", // "uuid-v4" | "direct"
"channel_id": "uuid-v4",
"type": "members" | "guests" | "messages",
"value": 0,
}
```
#### **channel\_last\_activity**
Store last channel activity for bold/not bold management
```javascript
{
//Primary key
"company_id": "uuid-v4",
"channel_id": "uuid-v4",
"last_activity": 0, //Timestamp in seconds
}
```
#### **direct\_channel\_identifiers**
This table is used to find an existing discussion with a group of members. The "identifier" is generated from the group of members.
```javascript
{
//Primary key
"company_id": "uuid-v4",
"identifier": "string", // ordered CSV list of user ids
"channel_id": "uuid-v4" //A way to find it in the channel table
}
```
## **Channels tabs**
#### **channel\_tabs**
Channels can have tabs that are connexion to other apps or different views.
```javascript
{
//Primary key
"company_id": "uuid-v4",
"workspace_id": "string", // "uuid-v4" | "direct"
"channel_id": "uuid-v4",
"tab_id": "uuid-v4",
"name": "String",
"configuration": JSON,
"application_id": "uuid-v4",
"owner": "uuid-v4",
"order": "string"
}
```
## **Channels members**
#### **channel\_members**
List of channels for an user
```javascript
{
//Primary key
"company_id": "uuid-v4", //Partition Key
"workspace_id": "string", // "uuid-v4" | "direct", //Clustering key
"user_id": "uuid-v4",
"channel_id": "uuid-v4",
"type": "member" | "guest" | "bot",
"last_access": 0, //Timestamp in seconds
"last_increment": 0, //Number
"favorite": false | true, //Did the user add this channel to its favorites
"notification_level": "all" | "none" | "group_mentions" | "user_mentions",
"expiration": false | Timestamp, //Member expiration in channel (only for guests)
}
```
#### **channel\_members\_reversed**
List of users in channel
**Not implemented:** We need to ensure this replication regularly \(on each user open channel\) ?
```javascript
{
//Primary key
"company_id": "uuid-v4",
"workspace_id": "string", // "uuid-v4" | "direct",
"channel_id": "uuid-v4",
"type": "guest" | "bot" | "member",
"user_id": "uuid-v4",
}
```
@@ -1,12 +1,12 @@
---
description: Drive on Twake
description: Drive on TDrive
---
# 📁 Drive
## description
**Drive** or **Documents** is the Nodejs drive implementation for twake, it contains drive items.
**Drive** or **Documents** is the Nodejs drive implementation for tdrive, it contains drive items.
A **Drive item** can be:
@@ -8,7 +8,7 @@ All the following routes require the usual authentication header. But you can al
- For the download routes, you can use a token generated by the `/internal/services/documents/v1/companies/:company_id/download/token` route (see bellow).
- All the routes can use a query string `?public_token=token` to authenticate the user.
- All the routes can use a query string `?twake_tab_token=token` to authenticate the user in the context of a channel tab for instance.
- All the routes can use a query string `?tdrive_tab_token=token` to authenticate the user in the context of a channel tab for instance.
# Navigation and drive capabilities
@@ -299,9 +299,9 @@ Used to create a zip archive containing the requested drive items ( files and fo
**Auth required** : Yes
# Tabs (for Twake)
# Tabs (for TDrive)
If you want to use the Twake tabs, you must store the configuration of the tabs in the database.
If you want to use the TDrive tabs, you must store the configuration of the tabs in the database.
## Get tab configuration
@@ -1,14 +1,14 @@
---
description: File on Twake
description: File on TDrive
---
# 📄 Files
## description
**Files** is everything related to file upload in Twake after the migration to Node.js. Note that the Twake Drive isn't part of this migration because it will be replaced by Linshare.
**Files** is everything related to file upload in TDrive after the migration to Node.js. Note that the TDrive Drive isn't part of this migration because it will be replaced by Linshare.
Twake Files upload support chunk upload and file encryption.
TDrive Files upload support chunk upload and file encryption.
## Wording
@@ -18,7 +18,7 @@ Twake Files upload support chunk upload and file encryption.
## Encryption
Files and Storage services in Twake feature encryption at rest in **aes-256-cbc**.
Files and Storage services in TDrive feature encryption at rest in **aes-256-cbc**.
Each file is encrypted with two layers:
@@ -1,5 +1,5 @@
---
description: How we use resumable on Twake
description: How we use resumable on TDrive
---
# Resumable.js
@@ -9,7 +9,7 @@ description: How we use resumable on Twake
## What is Resumable.js
::: info
Using Resumable is not mandatory to upload a file to Twake. You can do it manually, see REST APIs page.
Using Resumable is not mandatory to upload a file to TDrive. You can do it manually, see REST APIs page.
:::
Its a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API.
@@ -1,11 +1,11 @@
---
description: Get started with Twake service development
description: Get started with TDrive service development
---
# 🛠 Twake service development
# 🛠 TDrive service development
[start-working-into-a-service](start-working-into-a-service.md)
[create-a-new-twake-service](create-a-new-twake-service.md)
[create-a-new-tdrive-service](create-a-new-tdrive-service.md)
[platform/](platform/README.md))
@@ -1,7 +1,7 @@
---
description: >-
If you are here, you probably have a very great idea for Twake, like adding a
brand new feature into Twake, maybe a coffee maker service ? ☕️
If you are here, you probably have a very great idea for TDrive, like adding a
brand new feature into TDrive, maybe a coffee maker service ? ☕️
---
# Create a new service
@@ -19,10 +19,10 @@ In order to illustrate how to create a component, let's create a fake Notificati
```javascript
// File src/services/notification/index.ts
import { TwakeService } from "../../core/platform/framework";
import { TDriveService } from "../../core/platform/framework";
import NotificationServiceAPI from "./api.ts";
export default class NotificationService extends TwakeService<NotificationServiceAPI> {
export default class NotificationService extends TDriveService<NotificationServiceAPI> {
version = "1";
name = "notification";
service: NotificationServiceAPI;
@@ -33,15 +33,15 @@ export default class NotificationService extends TwakeService<NotificationServic
}
```
1. Our `NotificationService` class extends the generic `TwakeService` class and we defined the `NotificationServiceAPI` as its generic type parameter. It means that in the platform, the other components will be able to retrieve the component from its name and then consume the API defined in the `NotificationServiceAPI` interface and exposed by the `api` method.
1. Our `NotificationService` class extends the generic `TDriveService` class and we defined the `NotificationServiceAPI` as its generic type parameter. It means that in the platform, the other components will be able to retrieve the component from its name and then consume the API defined in the `NotificationServiceAPI` interface and exposed by the `api` method.
We need to create this `NotificationServiceAPI` interface which must extend the `TwakeServiceProvider` from the platform like:
We need to create this `NotificationServiceAPI` interface which must extend the `TDriveServiceProvider` from the platform like:
```javascript
// File src/services/notification/api.ts
import { TwakeServiceProvider } from "../../core/platform/framework/api";
import { TDriveServiceProvider } from "../../core/platform/framework/api";
export default interface NotificationServiceAPI extends TwakeServiceProvider {
export default interface NotificationServiceAPI extends TDriveServiceProvider {
/**
* Send a message to a list of recipients
@@ -65,17 +65,17 @@ export class NotificationServiceImpl implements NotificationServiceAPI {
}
```
1. `NotificationServiceImpl` now needs to be instanciated from the `NotificationService` class since this is where we choose to keep its reference and expose it. There are several places which can be used to instanciate it, in the constructor itself, or in one of the `TwakeService` lifecycle hooks. The `TwakeService` abstract class has several lifecycle hooks which can be extended by the service implementation for customization pusposes:
1. `NotificationServiceImpl` now needs to be instanciated from the `NotificationService` class since this is where we choose to keep its reference and expose it. There are several places which can be used to instanciate it, in the constructor itself, or in one of the `TDriveService` lifecycle hooks. The `TDriveService` abstract class has several lifecycle hooks which can be extended by the service implementation for customization pusposes:
2. `public async doInit(): Promise<this>;` Customize the `init` step of the component. This is generally the place where services are instanciated. From this step, you can retrieve services consumed by the current component which have been already initialized by the platform.
3. `public async doStart(): Promise<this>;` Customize the `start` step of the component. You have access to all other services which are already started.
```javascript
// File src/services/notification/index.ts
import { TwakeService } from "../../core/platform/framework";
import { TDriveService } from "../../core/platform/framework";
import NotificationServiceAPI from "./api.ts";
import NotificationServiceImpl from "./services/api.ts";
export default class NotificationService extends TwakeService<NotificationServiceAPI> {
export default class NotificationService extends TDriveService<NotificationServiceAPI> {
version = "1";
name = "notification";
service: NotificationServiceAPI;
@@ -95,12 +95,12 @@ export default class NotificationService extends TwakeService<NotificationServic
1. Now that the service is fully created, we can consume it from any other service in the platform. To do this, we rely on Typescript decorators to define the links between components. For example, let's say that the a `MessageService` needs to call the `NotificationServiceAPI`, we can create the link with the help of the `@Consumes` decorator and get a reference to the `NotificationServiceAPI` by calling the `getProvider` on the component context like:
```javascript
import { TwakeService, Consumes } from "../../core/platform/framework";
import { TDriveService, Consumes } from "../../core/platform/framework";
import MessageServiceAPI from "./providapier";
import NotificationServiceAPI from "../notification/api";
@Consumes(["notification"])
export default class MessageService extends TwakeService<MessageServiceAPI> {
export default class MessageService extends TDriveService<MessageServiceAPI> {
public async doInit(): Promise<this> {
const notificationService = this.context.getProvider<NotificationServiceAPI>("notification");
@@ -143,7 +143,7 @@ Then each service can have its own configuration block which is accessible from
On the component class side, the configuration object is directly accessible from the `configuration` property like:
```javascript
export default class WebSocket extends TwakeService<WebSocketAPI> {
export default class WebSocket extends TDriveService<WebSocketAPI> {
async doInit(): Promise<this> {
// get the "path" value, defaults to "/socket" if not defined
const path = this.configuration.get < string > ("path", "/socket");
@@ -166,7 +166,7 @@ After creating a new service, you can add controllers, business services and ent
## Create a new technical service
Now you are bringing things a step further, you are going to add new core services in Twake, like for instance a new database connector or encryption system.
Now you are bringing things a step further, you are going to add new core services in TDrive, like for instance a new database connector or encryption system.
Creating a new core service is as easy as creating a functional service. But it must be in `src/core/platform/services` .
@@ -1,6 +1,6 @@
---
description: >-
List of core shared components in Twake backend, available in
List of core shared components in TDrive backend, available in
src/core/platform/services
---
@@ -8,7 +8,7 @@ description: >-
## **Database Technical Service**
Twake uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB.
TDrive uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB.
::: info
This paragraph is not ready yet, you can contribute to this documentation on our Github!
@@ -108,7 +108,7 @@ Services annotated as described above automatically publish events to WebSockets
```javascript
const io = require("socket.io-client");
// Get a JWT token from the Twake API first
// Get a JWT token from the TDrive API first
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8";
const socket = io.connect("http://localhost:3000", { path: "/socket" });
@@ -150,7 +150,7 @@ socket.on("connect", () => {
.emit("authenticate", { token })
.on("authenticated", () => {
// join the /channels room
socket.emit("realtime:join", { name: "/channels", token: "twake" });
socket.emit("realtime:join", { name: "/channels", token: "tdrive" });
socket.on("realtime:join:error", (message) => {
// will fire when join does not provide a valid token
console.log("Error on join", message);
@@ -231,7 +231,7 @@ socket.on("connect", () => {
.emit("authenticate", { token })
.on("authenticated", () => {
// join the "/channels" room
socket.emit("realtime:join", { name: "/channels", token: "twake" });
socket.emit("realtime:join", { name: "/channels", token: "tdrive" });
// will only occur when an action occured on a resource
// and if and only if the client joined the room
@@ -1,6 +1,6 @@
---
description: >-
List of core shared components in Twake backend, available in
List of core shared components in TDrive backend, available in
src/core/platform/services
---
@@ -8,7 +8,7 @@ description: >-
## **Database Technical Service**
Twake uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB.
TDrive uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB.
[database-orm-platform-service](database-orm-platform-service.md)
@@ -106,7 +106,7 @@ Services annotated as described above automatically publish events to WebSockets
```javascript
const io = require("socket.io-client");
// Get a JWT token from the Twake API first
// Get a JWT token from the TDrive API first
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8";
const socket = io.connect("http://localhost:3000", { path: "/socket" });
@@ -148,7 +148,7 @@ socket.on("connect", () => {
.emit("authenticate", { token })
.on("authenticated", () => {
// join the /channels room
socket.emit("realtime:join", { name: "/channels", token: "twake" });
socket.emit("realtime:join", { name: "/channels", token: "tdrive" });
socket.on("realtime:join:error", (message) => {
// will fire when join does not provide a valid token
console.log("Error on join", message);
@@ -229,7 +229,7 @@ socket.on("connect", () => {
.emit("authenticate", { token })
.on("authenticated", () => {
// join the "/channels" room
socket.emit("realtime:join", { name: "/channels", token: "twake" });
socket.emit("realtime:join", { name: "/channels", token: "tdrive" });
// will only occur when an action occured on a resource
// and if and only if the client joined the room
@@ -5,7 +5,10 @@
A. Create an entity and put it anywhere in the code
```typescript
import { Entity, Column } from "../../../core/platform/services/database/services/orm/decorators";
import {
Entity,
Column,
} from "../../../core/platform/services/database/services/orm/decorators";
@Entity("my_entity", {
primaryKey: [["company_id"], "id"], //Primary key, see Cassandra documentation for more details
@@ -45,25 +48,24 @@ await repository.remove({company_id: "", id: ""});
#### I set a column to a type but I get an other type on code. Why for two identical definitions it created fields of different types?
It depends on what database you use \(mongo or scylladb\) for development. Here is the process for each:
It depends on what database you use \(mongo or scylladb\) for development. Here is the process for each:
Scylla:
* on startup it creates the tables with the requested types, in this case twake\_boolean =&gt; tinyint on scylla side
* on save entity it will convert the node type \(boolean\) to the good cql request: "{bool: false}" =&gt; "SET bool = 0", it happens in the transformValueToDbString method
* on find entity it will convert the database raw value \(a tinyint\) to the nodejs type \(boolean\): 1 =&gt; true, 0 =&gt; false.
- on startup it creates the tables with the requested types, in this case tdrive_boolean =&gt; tinyint on scylla side
- on save entity it will convert the node type \(boolean\) to the good cql request: "{bool: false}" =&gt; "SET bool = 0", it happens in the transformValueToDbString method
- on find entity it will convert the database raw value \(a tinyint\) to the nodejs type \(boolean\): 1 =&gt; true, 0 =&gt; false.
Mongo:
* on startup it does nothing \(mongo don't need to initialise columns
* on save entity it will create a document, it means in mongo we just store json for each entity, there is no really a column concept.
* on find entity we just get back the saved json and map it to the entity in node.
- on startup it does nothing \(mongo don't need to initialise columns
- on save entity it will create a document, it means in mongo we just store json for each entity, there is no really a column concept.
- on find entity we just get back the saved json and map it to the entity in node.
Even if mongo just store json directly from mongo, we sometime do some changes to the data before to save in mongo, it will also be in the typeTransforms.ts file.
So what could have happened in you case ?
* \(1\) if you use mongodb and we did not enforce the type before to save to mongo, then maybe you used a string instead of a boolean at some point in time while working and mongo just saved it as it was \(without checking the requested type on entity\)
* \(2\) other possibility is that we incorrectly get the information from the database on the typeTransforms.ts file, from cassandra for instance I think we don't convert tinyint back to clean boolean, so you could get 0 and 1 instead of false and true. And maybe instead of 0 and 1 sometime undefined values can convert to ''.
* To fix all this just enforce the types in typeTransforms.ts for the twake\_boolean type.
- \(1\) if you use mongodb and we did not enforce the type before to save to mongo, then maybe you used a string instead of a boolean at some point in time while working and mongo just saved it as it was \(without checking the requested type on entity\)
- \(2\) other possibility is that we incorrectly get the information from the database on the typeTransforms.ts file, from cassandra for instance I think we don't convert tinyint back to clean boolean, so you could get 0 and 1 instead of false and true. And maybe instead of 0 and 1 sometime undefined values can convert to ''.
- To fix all this just enforce the types in typeTransforms.ts for the tdrive_boolean type.
@@ -4,7 +4,7 @@ description: >-
to our channel service ? You are in the right place !
---
# What is a service in Twake ?
# What is a service in TDrive ?
The backend is developed using a **software component approach** in order to compose and adapt the platform based on needs and constraints. The current section describes this approach, and how to extend it by creating new components.
@@ -25,9 +25,9 @@ The platform currently have some limitations:
## Discover what is in a service
To unfold the internal ways of services in Twake, we will follow a simple request journey into our framework.
To unfold the internal ways of services in TDrive, we will follow a simple request journey into our framework.
1. The requests starts from Twake Frontend or Postman for instance,
1. The requests starts from TDrive Frontend or Postman for instance,
2. it then goes to a controller which validate the request parameters and extract them for the services,
3. the services uses the given parameters to get/set entities in database and returns a proper reply.
@@ -1,49 +0,0 @@
# Knowledge-graph
## Twake to Knowledge-graph events
Twake can send events to the knowledge graph following this documentation:
[Events from Twake](./pushed-from-twake.md)
## Knowledge-graph to Twake REST
The knowledge graph can send us event at the following endpoint:
`POST https://api.twake.app/internal/services/knowledge-graph/v1/push`
Authorized by a Token authorization header:
`Authorization: Token {some token defined together}`
And with the following data in JSON:
```
{
events: [KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, ...]
}
type KnowledgeGraphCallbackEvent = {
recipients: {
type: "user";
id: string; // KG user id which is a md5 of the email
}[];
event: {
type: "user_tags"; //More events will be added later
data: {
//For user_tags event only
tags?: {
value: string;
weight: number;
}[];
};
};
};
```
The reply will be if everything was alright:
```
{
"status": "success"
}
```
@@ -1,172 +0,0 @@
# Knowledge-graph
## Knowledge-graph to Twake events
[Send events to Twake](./README.md)
## Events sent by twake to the knowledge graph
### User created / updated
```typescript
{
records: [
{
key: "null",
value: {
id: "User",
properties: {
_kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one
_kg_email_id: string; //Console wide user id (based on the email md5)
_kg_company_all_id: string[]; //All console wide companies_ids for this user
user_id: string; //Twake internal user id
company_id: string; //Company internal id
user_created_at: number;
user_last_activity: string;
email: string;
first_name: string;
last_name: string;
},
},
},
]
}
```
### Channel created / updated
```typescript
{
records: [
{
key: "null",
value: {
id: "Channel",
properties: {
_kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one
_kg_email_id: string; //Console wide user id (based on the email md5)
_kg_company_id: string; //Console wide company id
channel_id: string;
channel_name: string;
channel_owner: string;
workspace_id: string;
company_id: string;
},
},
},
],
}
```
### Message created / updated
```typescript
{
records: [
{
key: "null",
value: {
id: "Message",
properties: {
_kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one
_kg_email_id: string; //Console wide user id (based on the email md5)
_kg_company_id: string; //Console wide company id
message_thread_id: message.thread_id,
message_content: string; //Empty if user requested not to share data to KG
message_created_at: number;
message_updated_at: number;
type_message: string;
company_id: string; //Internal to Twake company id
workspace_id: string;
channel_id: string;
user_id: string; //Internal to Twake user id
},
},
},
],
}
```
### Company created / updated
```typescript
{
records: [
{
key: "null",
value: {
id: "Company",
properties: {
_kg_company_id: string; //Console wide company id
company_id: string; //Internal to Twake company id
company_name: string;
},
},
},
],
}
```
### Workspace created / updated
```typescript
{
records: [
{
key: "null",
value: {
id: "Workspace",
properties: {
_kg_company_id: string; //Console wide company id
company_id: string; //Internal to Twake company id
workspace_id: string; //Internal to Twake workspace id
workspace_name: string;
},
},
},
],
}
```
## Sending events to Twake from the KG
Twake listen at at:
`POST https://domain/internal/services/knowledge-graph/v1/push`
Authorised by a Token authorization header:
`Authorization: Token {some token defined together}`
And with the following data in JSON:
```typescript
{
events: [KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, ...]
}
type KnowledgeGraphCallbackEvent = {
recipients: {
type: "user";
id: string; // KG user id which is a md5 of the email
}[];
event: {
type: "user_tags"; //More events will be added later
data: {
//For user_tags event only
tags?: {
value: string;
weight: number;
}[];
};
};
};
```
The reply will be if everything was alright:
```typescript
{
"status": "success"
}
```
@@ -1,8 +0,0 @@
---
description: Message api
---
# 💬 Messages
Document still on Notion: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b)
@@ -1,6 +0,0 @@
---
description: Message database models
---
# Database models
@@ -1,6 +0,0 @@
---
description: Notifications on Twake
---
# 📲 Notifications
@@ -1,59 +0,0 @@
---
description: Notification database model
---
# Database models
#### **channel\_members\_notification\_preferences**
```javascript
{
//Primary key
"company_id": "uuid-v4",
"channel_id": "uuid-v4",
"user_id": "uuid-v4",
"preferences": "all" | "mentions" | "me" | "none",
"last_read": 16000000, //Timestamp in seconds
}
```
#### **channel\_thread\_users**
```javascript
{
//Primary key
"company_id": "uuid-v4",
"channel_id": "uuid-v4",
"thread_id": "uuid-v4",
"user_id": "uuid-v4"
}
```
#### **user\_notifications\_badges \(this is not a counter like scylladb counters here, just classic table\)**
```javascript
{
//Primary key
"company_id": "uuid-v4", (partition key)
"user_id": "uuid-v4", (clustering key)
"workspace_id": "uuid-v4", (clustering key)
"channel_id": "uuid-v4", (clustering key)
"thread_id": "uuid-v4", (clustering key)
}
```
#### **user\_notifications\_general\_preferences**
```javascript
{
//Primary key
"company_id": "uuid-v4",
"user_id": "uuid-v4",
"workspace_id": "uuid-v4",
"preferences": PreferencesObject
}
```
@@ -1,12 +1,12 @@
---
description: Tags on Twake
description: Tags on TDrive
---
# 📁 Tags
## description
**Tags** is everything related to tafs in Twake after the migration to Node.js.
**Tags** is everything related to tafs in TDrive after the migration to Node.js.
## Models and APIs
@@ -4,5 +4,4 @@ description: How users and workspaces are managed in backend
# 👥 Users and workspaces
Document still on notion: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b)
Document still on notion: [https://www.notion.so/tdrive/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/tdrive/Backend-documentation-e219323593d2401c9887d0e11b2a597b)
@@ -1,9 +1,9 @@
---
description: Get started with Twake frontend.
description: Get started with TDrive frontend.
---
# Storybook
Twake components are available through our Storybook. You can find it here:
TDrive components are available through our Storybook. You can find it here:
[https://web.twake.app/storybook/index.html](https://web.twake.app/storybook/index.html)
[https://web.tdrive.app/storybook/index.html](https://web.tdrive.app/storybook/index.html)
@@ -4,14 +4,14 @@ description: Here is the list of our middlewares and their usages.
# 📚 Our stack
Write an article describing our stack at Twake composed of:
Write an article describing our stack at TDrive composed of:
- In full mode a docker containing: node, react behind nginx, elasticsearch, scylladb, redis, rabbitmq
- In simple mode a docker containing: node, react and mongodb for db and search
### Simple mode
The simple mode of Twake messaging app is designed for quick setup and development purposes. It is a more straightforward mode that uses a single container to deploy the components. The technical stack of this mode includes the following components:
The simple mode of TDrive messaging app is designed for quick setup and development purposes. It is a more straightforward mode that uses a single container to deploy the components. The technical stack of this mode includes the following components:
- Node: A JavaScript runtime environment used to develop server-side applications.
- React: A JavaScript library used to build user interfaces.
@@ -21,7 +21,7 @@ The simple mode is great for companies that want a quick and easy setup for thei
### Full mode
The full mode of Twake messaging app is designed to handle large-scale production loads with more than 1000 active users. It uses a container-based approach to deploy the components and ensure scalability. The technical stack of this mode includes the following components:
The full mode of TDrive messaging app is designed to handle large-scale production loads with more than 1000 active users. It uses a container-based approach to deploy the components and ensure scalability. The technical stack of this mode includes the following components:
- Node: A JavaScript runtime environment used to develop server-side applications.
- React: A JavaScript library used to build user interfaces.
@@ -1,18 +1,18 @@
---
description: Want to translate Twake ?
description: Want to translate TDrive ?
---
# 🎭 Translation
## Translation process
Twake is built for everyone. That means we support languages that user want. If we do not already support your language, or you find a mistake in the translation, you have a simply way to do that.
TDrive is built for everyone. That means we support languages that user want. If we do not already support your language, or you find a mistake in the translation, you have a simply way to do that.
Send us a mail to this address saying that you want to help us on the translation : [sales@twake.app](mailto:sales@twake.app). After, you'll have to follow the bellow steps.
Send us a mail to this address saying that you want to help us on the translation : [sales@tdrive.app](mailto:sales@tdrive.app). After, you'll have to follow the bellow steps.
## Join weblate server
At Twake, we use [weblate](https://hosted.weblate.org/), a tool that allow you to translate Twake without working on the code. After you sent an email, we'll invite you to the project. Inside the Twake project you can find [twake-web-frontend](https://hosted.weblate.org/projects/twake/twake-web-frontend/) that contains all translation for the web version.
At TDrive, we use [weblate](https://hosted.weblate.org/), a tool that allow you to translate TDrive without working on the code. After you sent an email, we'll invite you to the project. Inside the TDrive project you can find [tdrive-web-frontend](https://hosted.weblate.org/projects/tdrive/tdrive-web-frontend/) that contains all translation for the web version.
## Start to translate
@@ -22,4 +22,4 @@ After choosing the language you want to contribute, you can click on categories
## Thank you!
Twake is build by and for the community. Your commitment is highly appreciate! In reward, we can offer you a year on our SaaS version. You just have to contact us through this email : [sales@twake.app](mailto:sales@twake.app)
TDrive is build by and for the community. Your commitment is highly appreciate! In reward, we can offer you a year on our SaaS version. You just have to contact us through this email : [sales@tdrive.app](mailto:sales@tdrive.app)
@@ -1,85 +0,0 @@
---
description: >-
Global guidelines for any new projects around Twake, Frontend and Backend
guidelines are discussed here.
---
# 🎨 Twake Ecosystem Guidelines
## Frontend guidelines
### Logo, UI and UX guidelines
#### Logos
{% file src="../assets/logo\_shape.svg" caption="Logo shape in SVG format" %}
#### Colors and fonts
The fonts and colors to use are defined in the document bellow, scroll down for the hexadecimal codes of each color.
![](../assets/screenshot-2021-03-31-at-14.51.23.png)
Colors code extracted from the Twake theme [https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less](https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less)
```css
// Circular Std = France
// Helvetica Neue = Vietnam
// TT Norms = Russia
// --- Twake fonts --- //
@main-font: "Circular Std", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue",
"Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
// --- Twake colors --- //
@primary: #3840f7;
@primary-background: #3842f723;
@primary-hover: #3850f7;
@secondary: #0d0f38;
@black: #000000;
@black-alpha-50: #18295288;
@black-alpha-70: #18295255;
@grey-background: #f5f5f7;
@grey-light: #eeeeee;
@grey-dark: #6a6a6a;
@error: #ff5154;
@success: #04aa11;
@warning: #ff8607;
@white: #fff;
```
#### Icons and emojis \(⚠️ not validated by UX designer yet\)
Twake is currently using feather icons [https://feathericons.com/](https://feathericons.com/) and can fallback to Material Icons or FontAwesome.
Emojis on web must use the Apple emojis set preferably. On device, prefer to use the device emoji set.
### Frameworks and component system
#### Languages and frameworks
We recommend **TypeScript** and **VueJS** for any new projects around Twake. \(But Twake itself currently uses ReactJS with typescript.\)
#### **Components system**
We strongly recommend using Antd design system: [https://ant.design/](https://ant.design/) for 3 reasons:
1. We want to **differ from Material** UI that is too recognisable
2. Antd is very customisable, and **we provide a Twake theme here:** [**https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less**](https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less)\*\*\*\*
3. Antd contain more components than Material UI
### Libraries for common use cases
Feel free to add any library in this table.
| Use case | used by | prefered library |
| :-------------- | :----------------- | :------------------------------------------------------- |
| Infinite scroll | Twake message feed | [https://virtuoso.dev/](https://virtuoso.dev/) \(React\) |
## Backend guidelines
### Programmation languages
### Databases and middlewares