|
18 | 18 | subscribe to the Redux store without React, but this would be more complicated.
|
19 | 19 |
|
20 | 20 | ## Back-end architecture
|
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +### Dataset files |
| 25 | + |
| 26 | +All persistent data is stored on the back-end server as JSON files, in the following folder structure |
| 27 | +as seen from the SERVER_DATA_ROOT location: |
| 28 | + |
| 29 | +``` |
| 30 | +├── datasets |
| 31 | +│ ├── some-dataset |
| 32 | +│ │ ├── locations.json (array of lng-lat coordinates for each initiative) |
| 33 | +│ │ ├── searchable.json (array of the property values and searchable strings for each initiative) |
| 34 | +│ │ ├── initiatives |
| 35 | +│ │ | ├── 0.json (full info of first initiative in the above aggregate JSONs) |
| 36 | +│ │ | ├── 1.json |
| 37 | +│ │ | ├── ... |
| 38 | +│ ├── other-dataset |
| 39 | +│ │ ├── ... |
| 40 | +│ ├── ... |
| 41 | +``` |
| 42 | + |
| 43 | +Additionally, for each dataset there's a `config.json`. This contains config for displaying the map |
| 44 | +in the UI, including the vocabs (translations of data IDs), default sidebar panel, and popup |
| 45 | +appearance. This config is not generated into the above folder structure, but kept in source control |
| 46 | +in the `@mykomap/config` library. |
| 47 | + |
| 48 | +### Example file contents |
| 49 | + |
| 50 | +`locations.json`: |
| 51 | + |
| 52 | +``` |
| 53 | +[ [1.21419, 50.45254], [0.21002, 49.33954], … ] |
| 54 | +``` |
| 55 | + |
| 56 | +`searchable.json`: |
| 57 | + |
| 58 | +``` |
| 59 | +{ |
| 60 | + "fields": ["coun", "sz", "searchString"], |
| 61 | + "values": [ |
| 62 | + ["GB", "Small", "some co-op 2 green lane london n4 9qr"], |
| 63 | + ["GB", "Large", "another co-op 15 brown street sheffield s7 0hg"], |
| 64 | + ... |
| 65 | + ] |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +#### Potential optimisation: |
| 70 | + |
| 71 | +Since there will be one row per item, with 100k items, every 10 characters adds a new megabyte. The really bulky bit is the text searchString part, so maybe it could be kept in its own plain text file, with one line per item. Searching it could be done by streaming it from disk, which avoids loading the entire file permanently into memory (for each dataset). |
| 72 | + |
| 73 | +For instance, this [SO thread](https://stackoverflow.com/questions/20187145/how-to-search-stream-for-string-in-node-js) has some sample stream-searching code, and a reference to a module which performs the streaming by what appears to be a fast non-buffering algorithm. |
| 74 | + |
| 75 | +`0.json`: |
| 76 | + |
| 77 | +``` |
| 78 | +{ name: "Some Co-op", "desc": "A co-op that sells stuff", "lng": 1.21419, "lat": 50.45254, "coun": "GB", "sz": "Small", ... } |
| 79 | +``` |
| 80 | + |
| 81 | +`config.json`: |
| 82 | + |
| 83 | +``` |
| 84 | +{ |
| 85 | + "prefixes": { |
| 86 | + "https://example.com/sizes/1.1/": "sz", |
| 87 | + ... |
| 88 | + }, |
| 89 | + "vocabs": { |
| 90 | + "sz": { |
| 91 | + "EN": { |
| 92 | + "title": "Sizes", |
| 93 | + "terms": { |
| 94 | + "large": "Large", |
| 95 | + "medium": "Medium", |
| 96 | + "small": "Small" |
| 97 | + } |
| 98 | + } |
| 99 | + }, |
| 100 | + ... |
| 101 | + }, |
| 102 | + "popupFields": { |
| 103 | + "sz": "text", |
| 104 | + "websites": "clickable-list", |
| 105 | + ... |
| 106 | + }, |
| 107 | + "ui": { ... }, |
| 108 | + ... |
| 109 | +} |
| 110 | +
|
| 111 | +``` |
| 112 | + |
| 113 | +### Data generation |
| 114 | + |
| 115 | +These directories of JSONs, including the searchable strings in the `searchable.json` files, need to be pre-generated by a script. This script will be written in JS/TS and live in the monorepo, to be run on the back-end server. |
| 116 | + |
| 117 | +The script will take the full data CSV for a map (generated by the data factory) as inputs, and write the full data into the required JSON files in the directory structure specified above. |
| 118 | + |
| 119 | +#### Note: |
| 120 | + |
| 121 | +We will need to manually copy the `standard.csv` from the data factory server to the back-end. Maybe in the future, the data factory pipeline can be enhanced to write the JSON files to the back-end server so that no manual duplication is necessary (and maybe we can eventually get rid of the separate data server altogether). Or, the bacl-end server could be given a URL to the appropriate `standard.csv` file(s) as published by the data factory and download it from there as part of a `build-data` script (possibly when notified by a webhook, or possibly polling and checking the file modification date) |
| 122 | + |
| 123 | +### Dataset instances |
| 124 | + |
| 125 | +- For each dataset available in the `datasets` directory on server start, a dataset instance is created |
| 126 | + by the Dataset service. Each Dataset instance has a: |
| 127 | + - `searchable` property, which is just the `searchable.json` loaded as an in-memory object |
| 128 | + - `getItem` method |
| 129 | + - `getConfig` method, which includes the vocabs |
| 130 | + - `getLocations` method, which returns a stream of the data |
| 131 | + - `search` method, which involves iterating through `searchable` to find matching initiatives |
0 commit comments