Architectural notes

Specter Desktop and Specter Cloud are flask applications and follow typical model-view-controller 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.
  • 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.
  • A DeviceManager mainly manages the persistence of a device-json structure compliant to helper.load_jsons.py.
  • NodeManager manages internal and external nodes.
  • UserManager manages all stuff regarding Users.
  • Similarly, the WalletManager manages all wallet stuff.

Views and blueprints

The controller part 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 extends 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 integrate it in the core architecture. When we started to make exchange specific functionality, we wanted to protect the core architecture. Therefore, we created a plugin concept which allows to have the above concepts replicated in their own self-contained standalone units.

We now try to implement bigger chunks of functionality in plugins. Maybe, even core functionality might be implemented in "core plugins" in the future. Internal plugins 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. For more information about plugins see Third Party Service Integrations where we also discuss the nuances between plugins and extensions.