adapt-authoring-docs 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/releases.yml +1 -1
- package/.github/workflows/standardjs.yml +1 -2
- package/.github/workflows/tests.yml +1 -2
- package/docs/architecture.md +175 -0
- package/docsify/docsify.js +1 -1
- package/jsdoc3/.jsdocConfig.json +57 -0
- package/package.json +1 -1
- package/tests/docsify.spec.js +3 -16
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Adapt Authoring Tool — Architecture
|
|
2
|
+
|
|
3
|
+
## System Architecture
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart TB
|
|
7
|
+
subgraph Client["Client Layer"]
|
|
8
|
+
UI["Backbone.js UI · 18 pluggable modules · Rollup · Babel · Handlebars · LESS"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
subgraph Server["Server & API Layer"]
|
|
12
|
+
direction LR
|
|
13
|
+
express["Express.js 5.1 · Helmet · Compression · Body Parser · Rate Limiter"]
|
|
14
|
+
apiCore["REST API · JSON Schema Validation (AJV)"]
|
|
15
|
+
corefw["Core Framework · App Singleton · AbstractModule · DependencyLoader · Hook System"]
|
|
16
|
+
express -- "routes" --> apiCore -- "loads" --> corefw
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subgraph Services["Service Modules"]
|
|
20
|
+
direction LR
|
|
21
|
+
subgraph AuthGroup["Authentication & Authorization"]
|
|
22
|
+
direction TB
|
|
23
|
+
auth["Auth"]
|
|
24
|
+
authLocal["Auth Local (bcrypt)"]
|
|
25
|
+
jwt["JWT Tokens"]
|
|
26
|
+
sessions["Sessions"]
|
|
27
|
+
roles["Roles (RBAC)"]
|
|
28
|
+
users["Users"]
|
|
29
|
+
usergroups["User Groups"]
|
|
30
|
+
auth ~~~ authLocal ~~~ jwt ~~~ sessions ~~~ roles ~~~ users ~~~ usergroups
|
|
31
|
+
end
|
|
32
|
+
subgraph ContentGroup["Content & Authoring"]
|
|
33
|
+
direction TB
|
|
34
|
+
content["Content"]
|
|
35
|
+
authored["Authored"]
|
|
36
|
+
tags["Tags"]
|
|
37
|
+
assets["Assets"]
|
|
38
|
+
courseAssets["Course Assets"]
|
|
39
|
+
courseTheme["Course Theme"]
|
|
40
|
+
defaultPlugins["Default Plugins"]
|
|
41
|
+
adaptFW["Adapt Framework"]
|
|
42
|
+
content ~~~ authored ~~~ tags ~~~ assets ~~~ courseAssets ~~~ courseTheme ~~~ defaultPlugins ~~~ adaptFW
|
|
43
|
+
end
|
|
44
|
+
subgraph SupportGroup["Support Services"]
|
|
45
|
+
direction TB
|
|
46
|
+
config["Config"]
|
|
47
|
+
logger["Logger"]
|
|
48
|
+
mongoLogger["MongoDB Logger"]
|
|
49
|
+
lang["Lang (i18n)"]
|
|
50
|
+
langpack["Language Pack (EN)"]
|
|
51
|
+
mailer["Mailer"]
|
|
52
|
+
collab["Collab (WebSocket)"]
|
|
53
|
+
errors["Errors"]
|
|
54
|
+
config ~~~ logger ~~~ mongoLogger ~~~ lang ~~~ langpack ~~~ mailer ~~~ collab ~~~ errors
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subgraph Data["Data Layer"]
|
|
59
|
+
direction LR
|
|
60
|
+
mongodb[("MongoDB 7.0")]
|
|
61
|
+
sessionStore[("Session Store")]
|
|
62
|
+
logStore[("Log Store")]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
Client -- "HTTP / REST" --> Server
|
|
66
|
+
Server -- "validates & dispatches" --> Services
|
|
67
|
+
Services -- "persists" --> Data
|
|
68
|
+
|
|
69
|
+
classDef clientStyle fill:#4A90D9,stroke:#2C5F8A,color:#fff
|
|
70
|
+
classDef serverStyle fill:#5BAE5B,stroke:#3A7A3A,color:#fff
|
|
71
|
+
classDef serviceStyle fill:#E67E22,stroke:#BA6518,color:#fff
|
|
72
|
+
classDef dataStyle fill:#3498DB,stroke:#2471A3,color:#fff
|
|
73
|
+
|
|
74
|
+
class Client clientStyle
|
|
75
|
+
class Server serverStyle
|
|
76
|
+
class Services serviceStyle
|
|
77
|
+
class Data dataStyle
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Module Dependency Hierarchy
|
|
81
|
+
|
|
82
|
+
```mermaid
|
|
83
|
+
flowchart TD
|
|
84
|
+
core["core\n(App, AbstractModule,\nDependencyLoader, Hook)"]
|
|
85
|
+
|
|
86
|
+
core --> config
|
|
87
|
+
core --> logger
|
|
88
|
+
core --> errors
|
|
89
|
+
core --> server["server\n(Express.js)"]
|
|
90
|
+
core --> mongodb["mongodb\n(Native Driver)"]
|
|
91
|
+
|
|
92
|
+
server --> middleware["middleware\n(helmet, compression,\nbody-parser, rate-limiter)"]
|
|
93
|
+
|
|
94
|
+
core --> jsonschema["jsonschema\n(AJV)"]
|
|
95
|
+
core --> api["api\n(Abstract REST API)"]
|
|
96
|
+
|
|
97
|
+
api --> auth
|
|
98
|
+
api --> jsonschema
|
|
99
|
+
api --> mongodb
|
|
100
|
+
|
|
101
|
+
auth --> authLocal["auth-local\n(bcrypt)"]
|
|
102
|
+
auth --> sessions["sessions\n(connect-mongo)"]
|
|
103
|
+
auth --> roles
|
|
104
|
+
auth --> users
|
|
105
|
+
users --> usergroups
|
|
106
|
+
|
|
107
|
+
core --> lang
|
|
108
|
+
lang --> langpack["langpack-en"]
|
|
109
|
+
|
|
110
|
+
core --> content
|
|
111
|
+
content --> authored
|
|
112
|
+
content --> tags
|
|
113
|
+
content --> assets
|
|
114
|
+
content --> courseAssets["courseassets\n(FFmpeg)"]
|
|
115
|
+
content --> courseTheme["coursetheme"]
|
|
116
|
+
content --> defaultPlugins["defaultplugins"]
|
|
117
|
+
|
|
118
|
+
core --> adaptframework["adaptframework\n(adapt-cli)"]
|
|
119
|
+
adaptframework --> contentPlugin["contentplugin"]
|
|
120
|
+
adaptframework --> spoor["spoortracking\n(SCORM)"]
|
|
121
|
+
adaptframework --> browserslist
|
|
122
|
+
adaptframework --> zipper["_zipper\n(JSZip)"]
|
|
123
|
+
|
|
124
|
+
core --> mailer["mailer\n(Nodemailer)"]
|
|
125
|
+
core --> collab["collab\n(WebSocket)"]
|
|
126
|
+
|
|
127
|
+
logger --> mongodblogger["mongodblogger"]
|
|
128
|
+
mongodblogger --> mongodb
|
|
129
|
+
|
|
130
|
+
sessions --> mongodb
|
|
131
|
+
|
|
132
|
+
classDef coreNode fill:#9B59B6,stroke:#6C3483,color:#fff
|
|
133
|
+
classDef infraNode fill:#5BAE5B,stroke:#3A7A3A,color:#fff
|
|
134
|
+
classDef apiNode fill:#D4A843,stroke:#A07D2E,color:#fff
|
|
135
|
+
classDef authNode fill:#E74C3C,stroke:#B03A2E,color:#fff
|
|
136
|
+
classDef contentNode fill:#E67E22,stroke:#BA6518,color:#fff
|
|
137
|
+
classDef adaptNode fill:#3498DB,stroke:#2471A3,color:#fff
|
|
138
|
+
classDef supportNode fill:#1ABC9C,stroke:#148F77,color:#fff
|
|
139
|
+
|
|
140
|
+
class core coreNode
|
|
141
|
+
class config,logger,errors,server,middleware,mongodb infraNode
|
|
142
|
+
class api,jsonschema apiNode
|
|
143
|
+
class auth,authLocal,sessions,roles,users,usergroups authNode
|
|
144
|
+
class content,authored,tags,assets,courseAssets,courseTheme,defaultPlugins contentNode
|
|
145
|
+
class adaptframework,contentPlugin,spoor,browserslist,zipper adaptNode
|
|
146
|
+
class lang,langpack,mailer,collab,mongodblogger supportNode
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Technology Stack
|
|
150
|
+
|
|
151
|
+
| Layer | Technologies |
|
|
152
|
+
|---|---|
|
|
153
|
+
| **Runtime** | Node.js 24, ES Modules |
|
|
154
|
+
| **Frontend** | Backbone.js, jQuery, Underscore, Handlebars, LESS |
|
|
155
|
+
| **Frontend Build** | Rollup, Babel 7 |
|
|
156
|
+
| **Backend** | Express.js 5.1, custom module system |
|
|
157
|
+
| **Database** | MongoDB 7.0 (native driver) |
|
|
158
|
+
| **Auth** | bcryptjs, JWT, express-session, connect-mongo, RBAC |
|
|
159
|
+
| **Validation** | AJV (JSON Schema) |
|
|
160
|
+
| **Security** | Helmet, rate-limiter-flexible |
|
|
161
|
+
| **Media** | FFmpeg, FFprobe |
|
|
162
|
+
| **Email** | Nodemailer |
|
|
163
|
+
| **Real-time** | WebSocket (ws) |
|
|
164
|
+
| **i18n** | Custom lang module + language packs |
|
|
165
|
+
| **Logging** | Chalk (CLI), MongoDB (persistent) |
|
|
166
|
+
| **Packaging** | JSZip, adapt-cli |
|
|
167
|
+
|
|
168
|
+
## Key Architectural Patterns
|
|
169
|
+
|
|
170
|
+
- **Plugin-based modularity** — Every feature is a separate npm package extending `AbstractModule` from `core`
|
|
171
|
+
- **Singleton App** — `App.instance` bootstraps and manages all modules via `DependencyLoader`
|
|
172
|
+
- **Hook system** — Lifecycle hooks for module initialization, ready states, and extensibility
|
|
173
|
+
- **RBAC** — Role-based access control with scoped permissions per API route
|
|
174
|
+
- **Event-driven UI** — `Origin` singleton (Backbone.Events) acts as a global event bus in the frontend
|
|
175
|
+
- **Schema-validated APIs** — All REST endpoints validated against JSON schemas using AJV
|
package/docsify/docsify.js
CHANGED
|
@@ -23,7 +23,7 @@ function generateSectionTitle (sectionName) {
|
|
|
23
23
|
export default async function docsify (app, configs, outputdir, defaultPages) {
|
|
24
24
|
const dir = path.resolve(outputdir, 'manual')
|
|
25
25
|
const sectionsConf = app.config.get('adapt-authoring-docs.manualSections')
|
|
26
|
-
const defaultSection = Object.entries(sectionsConf).
|
|
26
|
+
const defaultSection = Object.entries(sectionsConf).find(([, data]) => data.default)?.[0]
|
|
27
27
|
/**
|
|
28
28
|
* init docsify folder
|
|
29
29
|
*/
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": {
|
|
3
|
+
"include": []
|
|
4
|
+
},
|
|
5
|
+
"docdash": {
|
|
6
|
+
"collapse": true,
|
|
7
|
+
"typedefs": true,
|
|
8
|
+
"search": true,
|
|
9
|
+
"static": true,
|
|
10
|
+
"menu": {
|
|
11
|
+
"<img class=\"logo\" src=\"assets/logo-outline-colour.png\" />Adapt authoring tool back-end API documentation<br><span class=\"version\">v2.5.0</span>": {
|
|
12
|
+
"class": "menu-title"
|
|
13
|
+
},
|
|
14
|
+
"Documentation home": {
|
|
15
|
+
"href": "https://adapt-security.github.io/adapt-authoring-documentation/",
|
|
16
|
+
"target": "_self",
|
|
17
|
+
"class": "menu-item",
|
|
18
|
+
"id": "home_link"
|
|
19
|
+
},
|
|
20
|
+
"Project Website": {
|
|
21
|
+
"href": "https://www.adaptlearning.org/",
|
|
22
|
+
"target": "_blank",
|
|
23
|
+
"class": "menu-item",
|
|
24
|
+
"id": "website_link"
|
|
25
|
+
},
|
|
26
|
+
"Technical Discussion Forum": {
|
|
27
|
+
"href": "https://community.adaptlearning.org/mod/forum/view.php?id=4",
|
|
28
|
+
"target": "_blank",
|
|
29
|
+
"class": "menu-item",
|
|
30
|
+
"id": "forum_link"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"sectionOrder": [
|
|
34
|
+
"Namespaces",
|
|
35
|
+
"Classes",
|
|
36
|
+
"Modules",
|
|
37
|
+
"Externals",
|
|
38
|
+
"Events",
|
|
39
|
+
"Mixins",
|
|
40
|
+
"Tutorials",
|
|
41
|
+
"Interfaces"
|
|
42
|
+
],
|
|
43
|
+
"meta": {
|
|
44
|
+
"title": "Adapt authoring tool UI documentation",
|
|
45
|
+
"description": "Adapt authoring tool UI documentation",
|
|
46
|
+
"keyword": "v2.5.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": [
|
|
49
|
+
"styles/adapt.css",
|
|
50
|
+
"scripts/adapt.js"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"opts": {
|
|
54
|
+
"destination": "/var/folders/28/8f7zyfj927z96jtjw_v0j9x80000gn/T/jsdoc-test-lPjKMQ/backend",
|
|
55
|
+
"template": "node_modules/docdash"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/package.json
CHANGED
package/tests/docsify.spec.js
CHANGED
|
@@ -205,18 +205,7 @@ describe('docsify', () => {
|
|
|
205
205
|
})
|
|
206
206
|
|
|
207
207
|
describe('bugs', () => {
|
|
208
|
-
it('
|
|
209
|
-
// BUG: In docsify.js line 26, Object.entries(sectionsConf).reduce((m, [id, data]) => ...)
|
|
210
|
-
// has no initial value. When there is only one section entry, reduce() returns
|
|
211
|
-
// the entry itself (an [id, data] array) without calling the callback.
|
|
212
|
-
// This causes generateSectionTitle to fail with:
|
|
213
|
-
// TypeError: sectionName.slice(...).replaceAll is not a function
|
|
214
|
-
// because sectionName is an array, not a string.
|
|
215
|
-
//
|
|
216
|
-
// To fix: add an initial value to reduce, e.g.:
|
|
217
|
-
// Object.entries(sectionsConf).reduce((m, [id, data]) => data.default ? id : m, undefined)
|
|
218
|
-
// or use Array.find instead:
|
|
219
|
-
// Object.entries(sectionsConf).find(([, data]) => data.default)?.[0]
|
|
208
|
+
it('defaultSection reduce with single entry returns string section name', async () => {
|
|
220
209
|
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'docsify-test-'))
|
|
221
210
|
const outputDir = tmpDir
|
|
222
211
|
const docsSrcDir = await fs.mkdtemp(path.join(os.tmpdir(), 'docsify-src-'))
|
|
@@ -238,10 +227,8 @@ describe('docsify', () => {
|
|
|
238
227
|
}]
|
|
239
228
|
|
|
240
229
|
const { default: docsify } = await import('../docsify/docsify.js')
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
() => docsify(mockApp, configs, outputDir, {}),
|
|
244
|
-
TypeError
|
|
230
|
+
await assert.doesNotReject(
|
|
231
|
+
() => docsify(mockApp, configs, outputDir, {})
|
|
245
232
|
)
|
|
246
233
|
|
|
247
234
|
await fs.rm(docsSrcDir, { recursive: true, force: true })
|