mirror of
https://github.com/cryptoadvance/specter-desktop.git
synced 2026-08-13 12:33:29 +02:00
Docs: Architectural Notes (#1673)
* Docs: Architectural Notes * including Service Diagram * minor changes
This commit is contained in:
parent
732225e846
commit
406dfefe67
3 changed files with 41 additions and 3 deletions
31
docs/architecture.md
Normal file
31
docs/architecture.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Architectural Notes
|
||||
|
||||
specter-desktop and specter-cloud are flask-applications and follow typical Model-View-Control-principles. The model-part is covered by a number of business-objects and managers who are responsible for maintaining/managing those. Currently we have these managers:
|
||||
|
||||
## Managers
|
||||
|
||||
* GenericDataManager is abstracting persistence-aspects and most managers which are persisting json-data are derived from this one.
|
||||
* ConfigManager where the api-docs tells us: "The ConfigManager manages the configuration persisted in config.json. It's not supposed to have any side-effects. Setting and getting only with a lot of validation and computing while setting/getting."
|
||||
* DeviceManager where the api-docs tells us: "A DeviceManager mainly manages the persistence of a device-json-structures compliant to helper.load_jsons.py".
|
||||
* NodeManager manages internal and external nodes.
|
||||
* UserManager manages all stuff regarding Users.
|
||||
* Similarly the WalletManager
|
||||
|
||||
## Views / Blueprints
|
||||
The controller is covered by "server_endpoints". Those are split up in “blueprints”. This is a way to split the urls in sub-urls. These sub-urls are loosely related to the business-objects: `/welcome`, `/auth`, `/devices`, `/nodes`, `/price`, `/services` (should be renamed "`/plugins`"), `/settings`, `/setup`, `/wallets`.
|
||||
|
||||
## Views
|
||||
The views are effectively jinja2 templates which can extend from higher order ones and have placeholders which templates can then override. The `base.jinja` lays out the basic layout having a block for the `sidebar` and a `main` block (plus `head` and `scripts` ). Some blueprints (`/settings`,`/wallets`) span up a top-level-navigation. In that case, the template extend from its specific blueprint-base-template which in turn provides a block called `content` and the template decides which menu-point is active:
|
||||
```
|
||||
{% extends "wallet/components/wallet_tab.jinja" %}
|
||||
{% set tab = 'receive' %}
|
||||
{% block content %}
|
||||
...
|
||||
```
|
||||
This is also a pattern used for plugins.
|
||||
|
||||
# Plugins
|
||||
|
||||
The more specific a functionality became, the more awkward it felt to be integrated in the above core-Architecture. When we started to make exchange specific functionality, we wanted to protect the core-Architecture from deluting. Therefore we created a plugin-concept which allows to have the above concepts replicated in it there own self-contained standalone units.
|
||||
|
||||
We try now to implement bigger chunks of functionality in plugins. Maybe even core-functionality might be placed with "core-plugins" in the future. Those are placed in `src/specterext`. But plugins can also live in there own repos, have their own release-lifecycle and be used by Specter like any other dependency as well. For more information about plugins see [Third Party Service Integrations](./services/services.md).
|
||||
|
|
@ -55,7 +55,7 @@ Users can also manually associate an existing `Address` with a `Service` (this i
|
|||
_Note: TODO: manually un-reserve an `Address` from a `Service`._
|
||||
|
||||
|
||||
### `Service` Configuration
|
||||
### Service Configuration
|
||||
In order to separate the service-configuration from the main-configuration, you can specify your config in a file called `config.py`. It's structure is similiar to the specter-wide `config.py`, e.g.:
|
||||
```
|
||||
class BaseConfig():
|
||||
|
|
@ -66,7 +66,7 @@ class ProductionConfig(BaseConfig):
|
|||
```
|
||||
In your code, you can access the correct value as in any other flask-code, like `api_url = app.config.get("SWAN_API_URL")`. If the instance is running a config (e.g. `DevelopmentConfig`) which is not available in your service-specific config (as above), the inheritance-hirarchy from the mainconfig will get traversed and the first hit will get get configured. In this example, it would be `BaseConfig`.
|
||||
|
||||
### `ServiceEncryptedStorage`
|
||||
### ServiceEncryptedStorage
|
||||
Most `Service`s will require user secrets (e.g. API key and secret). Each Specter `User` will have their own on-disk encrypted `ServiceEncryptedStorage` with filename `<username>_services.json`. Note that the user's secrets for all `Service`s will be stored in this one file.
|
||||
|
||||
This is built upon the `GenericDataManager` class which supports optional encrypted fields. In this case all fields are encrypted. The `GenericDataManager` encryption can only be unlocked by each `User`'s individual `user_secret` that itself is stored encrypted on-disk; it is decrypted to memory when the `User` logs in.
|
||||
|
|
@ -79,7 +79,7 @@ It is up to each `Service` implementation to decide what data is stored; the `Se
|
|||
|
||||
This is also where `Service`-wide configuration or other information should be stored, _**even if it is not secret**_ (see above intro about not polluting other existing data stores).
|
||||
|
||||
### `ServiceEncryptedStorageManager`
|
||||
### ServiceEncryptedStorageManager
|
||||
Because the `ServiceEncryptedStorage` is specific to each individual user, this manager provides convenient access to automatically retrieve the `current_user` from the Flask context and provide the correct user's `ServiceEncryptedStorage`. It is implemented as a `Singleton` which can be retrieved simply by importing the class and calling `get_instance()`.
|
||||
|
||||
This simplifies code to just asking for:
|
||||
|
|
@ -110,6 +110,12 @@ Annotations are stored on a per-wallet and per-`Service` basis as _unencrypted_
|
|||
|
||||
_Note: current `Service` implementations have not yet needed this feature so displaying annotations is not yet implemented._
|
||||
|
||||
## Data Storage Class Diagram
|
||||
|
||||
Unfortunately, the two unencrypted classes are derived from the encrypted one rather than having it the other way around or having abstract classes. This makes the diagram maybe a bit confusing.
|
||||
|
||||
[](https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqVVMFuwjAM_ZUqJzaVw66IIU0D7bRd0G6VItO4LFvqoCRlqhj_PpeWASLduhyiqH7v-dlOsxO5VSgmIjfg_VzD2kGZUcKr3Z-Q0Ol8DgGegWCNLpl-jcfJEt1W57ig3NWbgGoZrONoS-oJXjBfCaPcPxI-ENkAQVvyF7RHS4VeVw5WBpea1gaDpZbZZ6eT_9VyzMK18_8oZeIuE8l4fMsn4tOQRvZm7FPra24XZgLjK4--38BFTe1-uCORAe3acLOk1KSDlCOPpkgTxSBZWKPQpUlniUcnP7C-f7GENycmQYnSFvLdc7zQBk-hn1r4OxrlTxFjQY3ORKSHbUfcn3vuqTFm_MIyt4h3pX1zraTCA_0sX0b9ya5varxPB7DUKk0-wfC1HSh_PeJdFB7_Mc6sTKf--Hk2G96769lHhJrlW7xc1bJp538qGpQjJnVqhUhFia4ErfiROwhlIrxhiZmY8FFhAZUJmciogVYbHj8ulOb8YlKA8ZgKqIJd1pSLSXAVHkHdW9mh9t9YNMxZ)
|
||||
|
||||
### callback methods
|
||||
Your service-class will inherit a callback-method which will get called for various reasons with the "reason" being a string as the first parameter. Checkout the `cryptoadvance.specter.services.callbacks` file for the specific callbacks.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ nav:
|
|||
- 'Continuous Integration': continuous-integration.md
|
||||
- cypress-testing.md
|
||||
- services/services.md
|
||||
- 'Architectural Notes': architecture.md
|
||||
- 'Some Random Dev Thoughts': archblog.md
|
||||
- API:
|
||||
- api/README.md
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue