Following document goes through usual project structure used for a district codebase. In future we'll provide lein template to generate suggested project structure.
Main purpose of server side code is to crawl application data from blockchain and IPFS and restructure it into regular database, so users can perform searchings & filterings over the data.
Files for server side are located at /src/<project-name>/server/
.
Contains configuration for running server in dev mode by starting mount. Also, contains function redeploy
that redeploys smart contracts and restarts all related mount modules.
Contains configuration for running server in prod mode.
Contains mount module, that deploys and initializes application smart contracts.
Mount module that listens to application related events on blockchain and inserts data into traditional database.
Contains mount module to setup a traditional database and provide functions for simpler operating. Currently our preferred DB is SQLite, for which we use wrapper module district-server-db. Therefore the main purpose of db.cljs is to create SQL tables at mount start.
Contains mount module that generates blockchain transactions in order to initialize application with mock data.
We use contract folder for defining namespaces that reflect API of smart contracts. For example contract/my-great-contract.cljs
will contain functions for calling methods in MyGreatContract.sol.
Contains mount module that listens to blockchain events and sends out notification emails accordingly.
Here's list of mount modules we usually use to reuse same logic across districts.
- district-server-config - Reads configuration from file on mount start.
- district-server-db - Sets up SQLite DB and provides helper functions.
- district-server-graphql - Sets up GraphQL server.t
- district-server-smart-contracts - Keeps track of smart-contract addresses and provides helper functions.
- district-server-web3 - Provides Web3 instance.
- district-server-web3-watcher - Watches connection to Ethereum blockchain.
- district-server-logging - Sets up server logging.
Here's full list of district-server-modules.
UI part of a district is made using re-mount modularisation pattern.
Files for front-end side are located at /src/<project-name>/ui/
.
Includes all re-mount modules and starts mount.
Each page or logical module has own folder inside /src/<project-name>/ui/
and contains one or more of following files:
Note, there isn't difference if the folder represents re-mount module, page or just some set of events and subscriptions.
Defines multimethod page + subcomponents.
re-frame events related to the page or module.
re-frame subscription related to the page or module.
Used when folder is re-mount module to define module with defstate
Reagent components provided by the module or used on the page.
- district-ui-graphql - Client-side solution for GraphQL.
- district-ui-web3 - Provides Web3 Instance
- district-ui-router - Provides routing functionality.
- district-ui-smart-contracts - Loads smart contract files.
- district-ui-web3-accounts - Loads web3 accounts.
- district-ui-web3-balances - Loads web3 balances.
- district-ui-web3-tx - Manages web3 transactions.
- district-ui-web3-tx-log - Provides Transaction Log functionality.
- district-ui-web3 - Provides Web3 instance
Here's full list of district-ui-modules.
Contains all code that's supposed to be shared between server and UI.
Files for are located at /src/<project-name>/shared/
.
Contains map defining smart contracts addresses. This file is usually edited programatically when deployer deploys contracts and writes new addresses into it.
Definition of routes for UI. It's in shared namespace, because server usually also needs to form URLs when sending email notifications.
Contains definition for GraphQL schema.
Contract folder contains namespaces providing parser functions when loading data from blockchain contract.
For visual styling we use garden with files being located at /src/<project-name>/styles/
. Our recommended way of naming classes is to use noun-like definitions, that semantically express what the component is, not how it looks. For example:
[:div.meme-card]
[:div.nav-link.active]
Here we have 'div.meme-card' as a single "type" identificator, with optional status class. A necessary and sufficient to be identified in CSS. This should prevent styling concerns leaking into the code and avoiding "clash of classes" in responsive design.
Example of adjective-like classes to avoid:
;; this is not recommended naming, it's expressing how component looks
[:div.meme.padded.small.elevated]
Adjective-like "classes" are perfectly good as a class mixins in the styles layer of the applications:
[:.meme
(merge
(box-rounded 5)
{:background "color"})]
Solidity smart contract files are located at resources/public/contracts/src
and by using lein-solc they're usually compiled into resources/public/contracts/build
.