src
: Common part and the desktop client codeapp-android
: Android specific partsapp-ios
: iOS specific partsflow: contains
implicitly imported Flow typing definitions. Avoid putting something there, it is buggy.libs
: "vendor" directory containing our dependencies in non-minified and minified form. May be improved. We take security seriously so we review diff between each version.resources
: some resources (mostly images) which are used in the project. Most of the are embedded to the code.test
: test codeandroid.js
: script for building Android appmake.js
: script for building dev versiondist.js
: script for building release versions of the web & desktop clientsfdroid-fix-deps
: script for removing some binary dependencies (iOS, Flow & Electron) so that we pass F-Droid checksfdroid-metadata-workaround
: is a link inside app-android so that F-Droid can find our metadata because our Android project is not in the root. Can be removed once it's fixed in F-Droid.server
: dev server to serve code (you still need to connect to real backend)tutao-pub.pem
: public key which is used to verify desktop clients
Web part of the app is split in three parts: client, worker and common.
All code in the src
except for the api
directory is intended for GUI and system interaction. Code in the api
contains most of the logic for server communication, encryption, indexing etc.
SomethingView
: Big part of the app, corresponds to the URL, e.g.mail
,contact
,settings
,search
SomehingListView
: Component which displays things in the list, usually in the second columnSomethingViewer
: Component which usually displays one element (e.g. selected email or contact)SomethingModel
: Logic for some part of the app, lives in the main partSomethingController
: Something that does some bookkeeping or general action but is not tied to the specific partSomethingFacade
: Logic for one domain, lives in the api partSomethingApp
: Something that communicates with native part to execute tasks in certain domainapp
: Part of the bigger domain structure. Currently there'ssystem
app for accounts and such andtutanota
app for mails and contactsEntity
: Object corresponding to the server database entityTypeModel
: Describes entity typeTypeRef
: Small object which lets us know which entity it is and findTypeModel
if needed
Worker, main thread & apps communicate through the messages. Protocol is described in the WorkerProtocol. See WorkerClient and WorkerImpl for the client and server part.
Native code communicates through the NativeWrapper.
UI code uses Mithril. It is a tiny framework which does routing & implement virtual DOM.
It uses a "hyperscript" language (m(ComponentOrDomElement, {param: value}, [children]
). It may seem intimidating
at first but it's actually quite simple.
Our preferred way of making Mithril components is through the ES6 classes. Before we've been creating instances of
these classes manually but that's not how Mithril should be used. Preferred way is to pass class and attributes
("props" if you come from React) to hyperscript and let it do its thing. Because of that we sometimes have two versions
of the components, newer one has "N" suffix like ButtonN
. It is almost always preferable to use new-style components.
Current preferred way looks roughly like that:
// Defining
type Attrs = {param1: string, paramTwo?: number}
class MyComponent implements MComponent<Attrs> {
view(vnode: Vnode<Attrs>) {
return m(".h1", "Hello " + vnode.attrs.param1)
}
}
// Usage
// ...
m(MyComponent, {param1: "Mithril", param2: 1})
For working with entities it is preferable to use injected EntityWorker
whenever possible and not using freestanding
functions. It makes easier to substitute network interfaces when needed.
One level below EntityWorker
lays EntityRestInterface
which is either EntityRestClient
or EntityRestCache
currently. Caches saves requested entities is the memory and updates them with WebSocket events.
If you're listening for WebSocket updates in the worker part (and you should justify doing that) then you should change EventBus to do that. For the main thread you can subscribe to the EventController.
EventBus
and EntityRestClient
make sure that entities are automatically encrypted/decrypted when needed. See
decryptAndMapToInstance().
Most of the server database changes are reflected in the EntityUpdate
s we receive from server. They describe
operation which happened to the entity. Updates are grouped into EntityEventBatch
es. These batches are ordered and
client tries tp stay up-to-date with the server (for caching and indexing).
node make -w prod
and in parallel
node server
Point browser of your choice to the localhost:9000
and you should be good to go.
To run tests:
cd test
and
node test api
or node test client