@clidey/dory 0.1.0
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/.dockerignore +4 -0
- package/.github/ISSUE_TEMPLATE/anything-else.md +10 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/claude.yml +37 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +91 -0
- package/LICENSE +201 -0
- package/README.md +185 -0
- package/SECURITY.md +11 -0
- package/assets/dory_logo.png +0 -0
- package/bin/dory.js +131 -0
- package/docs/README.md +2 -0
- package/docs/configuration/app-settings/feature-flags.mdx +157 -0
- package/docs/configuration/app-settings/user-settings.mdx +201 -0
- package/docs/configuration/installation-setup/env-vars.mdx +198 -0
- package/docs/configuration/installation-setup/installation.mdx +127 -0
- package/docs/dory.json +162 -0
- package/docs/integrations/analytics-monitoring/error-tracking.mdx +199 -0
- package/docs/integrations/analytics-monitoring/notifications.mdx +189 -0
- package/docs/integrations/analytics-monitoring/user-analytics.mdx +182 -0
- package/docs/integrations/shopify-integration/shopify-setup.mdx +226 -0
- package/docs/integrations/shopify-integration/shopify-webhooks.mdx +207 -0
- package/docs/overview/developer-overview/dev-architecture.mdx +292 -0
- package/docs/overview/product-intro/app-overview.mdx +167 -0
- package/docs/overview/product-intro/architecture.mdx +203 -0
- package/docs/overview/product-intro/core-concepts.mdx +267 -0
- package/docs/platform-admin/billing-subscriptions/billing.mdx +176 -0
- package/docs/platform-admin/system-maintenance/db-migrations.mdx +184 -0
- package/docs/platform-admin/system-maintenance/health-monitoring.mdx +222 -0
- package/docs/platform-admin/system-maintenance/queue-management.mdx +234 -0
- package/docs/platform-admin/user-team-management/teams.mdx +170 -0
- package/docs/platform-admin/user-team-management/users.mdx +185 -0
- package/docs/support/legal/dependency-analysis.mdx +132 -0
- package/docs/support/legal/privacy-terms.mdx +73 -0
- package/docs/support/troubleshooting/common-issues.mdx +159 -0
- package/docs/usage/api-usage/api-inventory.mdx +213 -0
- package/docs/usage/api-usage/api-products.mdx +249 -0
- package/docs/usage/api-usage/api-purchase-orders.mdx +289 -0
- package/docs/usage/api-usage/api-reports.mdx +227 -0
- package/docs/usage/api-usage/api-suppliers.mdx +171 -0
- package/docs/usage/api-usage/api-user-management.mdx +171 -0
- package/docs/usage/ui-workflows/bundles.mdx +157 -0
- package/docs/usage/ui-workflows/demand-planning.mdx +210 -0
- package/docs/usage/ui-workflows/favorites.mdx +167 -0
- package/docs/usage/ui-workflows/inventory-management.mdx +179 -0
- package/docs/usage/ui-workflows/onboarding.mdx +215 -0
- package/docs/usage/ui-workflows/purchase-orders.mdx +200 -0
- package/docs/usage/ui-workflows/reports.mdx +257 -0
- package/index.html +54 -0
- package/k8s/Dockerfile +15 -0
- package/k8s/config/nginx-default.conf +22 -0
- package/k8s/dev.Dockerfile +16 -0
- package/package.json +71 -0
- package/src/app.css +3 -0
- package/src/app.tsx +13 -0
- package/src/components/dark-mode-toggle.tsx +25 -0
- package/src/components/dropdown.tsx +49 -0
- package/src/components/hooks.tsx +28 -0
- package/src/components/loading.tsx +23 -0
- package/src/components/mdx-provider.tsx +13 -0
- package/src/components/navigation.tsx +53 -0
- package/src/components/notification.tsx +97 -0
- package/src/components/routes.tsx +89 -0
- package/src/components/search-index.ts +43 -0
- package/src/components/search.tsx +508 -0
- package/src/components/store.ts +144 -0
- package/src/index.css +24 -0
- package/src/main.tsx +18 -0
- package/src/mdx/accordion.tsx +48 -0
- package/src/mdx/api-playground.tsx +674 -0
- package/src/mdx/api.tsx +354 -0
- package/src/mdx/callout.tsx +80 -0
- package/src/mdx/card.tsx +48 -0
- package/src/mdx/code.tsx +289 -0
- package/src/mdx/expandable.tsx +40 -0
- package/src/mdx/fence.tsx +73 -0
- package/src/mdx/icon.tsx +73 -0
- package/src/mdx/latex.tsx +26 -0
- package/src/mdx/list.tsx +7 -0
- package/src/mdx/mdx.tsx +43 -0
- package/src/mdx/mermaid.tsx +102 -0
- package/src/mdx/open-api.tsx +325 -0
- package/src/mdx/source.tsx +47 -0
- package/src/mdx/step.tsx +49 -0
- package/src/mdx/table.tsx +15 -0
- package/src/mdx/tag.tsx +66 -0
- package/src/mdx/text.tsx +98 -0
- package/src/plugins/sanitize.ts +15 -0
- package/src/theme.scss +124 -0
- package/src/ui/header.tsx +88 -0
- package/src/ui/layout.tsx +167 -0
- package/src/ui/mobile-navigation.tsx +91 -0
- package/src/ui/prev-next-link.tsx +74 -0
- package/src/ui/table-of-content.tsx +166 -0
- package/src/utils/fonts.ts +20 -0
- package/src/utils/functions.ts +12 -0
- package/src/utils/hooks.ts +46 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +32 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +25 -0
- package/vite.config.ts +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="./assets/dory_logo.png" alt="Dory Logo" width="200" />
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
# Dory
|
|
6
|
+
|
|
7
|
+
> 🐟 A lightweight static site generator for technical documentation.
|
|
8
|
+
|
|
9
|
+
Dory is a lightweight static site generator built for developers who want fast, clean, and customizable documentation — without the overhead of server-side rendering, complex CI/CD setups, or cloud-specific constraints.
|
|
10
|
+
|
|
11
|
+
Built with [Preact](https://preactjs.com/), [Vite](https://vitejs.dev/), [Tailwind CSS](https://tailwindcss.com/), [Mermaid](https://mermaid.js.org/), and [TypeScript](https://www.typescriptlang.org/).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🚀 Why Dory?
|
|
16
|
+
|
|
17
|
+
We created Dory while building a documentation platform and getting frustrated by bloated frameworks, slow build times, and cryptic deployment errors.
|
|
18
|
+
|
|
19
|
+
Dory is:
|
|
20
|
+
|
|
21
|
+
- 🧠 **Simple** — Drop in `.mdx` files and configure one `dory.json`.
|
|
22
|
+
- ⚡ **Fast** — Instant hot reload in dev, quick static builds for prod.
|
|
23
|
+
- 🌐 **Portable** — No SSR, no lock-in, deploy anywhere.
|
|
24
|
+
- 🧩 **Flexible** — Hackable theme, readable codebase, minimal magic.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ✨ Features
|
|
29
|
+
|
|
30
|
+
- 📄 Write docs in `.mdx` (Markdown + JSX)
|
|
31
|
+
- 🧭 Configure site structure with a single `dory.json`
|
|
32
|
+
- 🧪 Built-in components for layout, navigation, and code highlighting
|
|
33
|
+
- 🔁 Instant hot-reload during development
|
|
34
|
+
- 📊 Mermaid support for diagrams and flows
|
|
35
|
+
- 🎨 Customizable via Tailwind and minimal theme overrides
|
|
36
|
+
- 🌍 Deploy to Netlify, Vercel, S3, GitHub Pages — your call
|
|
37
|
+
- 🌐 HTTP client for testing API endpoints (automatic inference from openapi.json)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📦 CLI Installation
|
|
42
|
+
|
|
43
|
+
Install Dory globally to use the CLI tool:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g dory
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### CLI Usage
|
|
50
|
+
|
|
51
|
+
Once installed, you can use the `dory` command:
|
|
52
|
+
|
|
53
|
+
#### `dory build`
|
|
54
|
+
Builds your documentation site:
|
|
55
|
+
- Checks for `dory.json` in current directory
|
|
56
|
+
- Clears and prepares the `docs` folder
|
|
57
|
+
- Copies configuration to `docs` folder
|
|
58
|
+
- Runs the build process
|
|
59
|
+
- Creates `dist` folder with build output
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
dory build
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### `dory preview`
|
|
66
|
+
Previews the built documentation site:
|
|
67
|
+
- Requires `dist` folder (run `dory build` first)
|
|
68
|
+
- Starts a local preview server
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
dory preview
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `dory help`
|
|
75
|
+
Shows CLI usage information:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
dory help
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 🧑💻 Development Setup
|
|
84
|
+
|
|
85
|
+
Follow these steps to set up and preview the documentation locally, as well as build a static site for deployment.
|
|
86
|
+
|
|
87
|
+
### 1️⃣ Clone the Repository
|
|
88
|
+
|
|
89
|
+
Clone the repository to your local machine:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/clidey/dory.git
|
|
93
|
+
cd dory
|
|
94
|
+
````
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### 2️⃣ Install Dependencies
|
|
99
|
+
|
|
100
|
+
Install all required dependencies using `pnpm`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pnpm install
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Make sure you have `pnpm` installed. If not, you can install it via:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install -g pnpm
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### 3️⃣ Copy Documentation Content
|
|
115
|
+
|
|
116
|
+
Copy your existing documentation into the `./docs` directory:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
rm -rf ./docs
|
|
120
|
+
cp ../wherever-the-docs-are/. ./docs
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> Replace `../wherever-the-docs-are/` with the actual path to your documentation source files.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 4️⃣ Start Development Server
|
|
128
|
+
|
|
129
|
+
Start the development server to preview the documentation locally:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pnpm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This will launch a local server (typically at `http://localhost:3000`) where you can preview and edit your documentation in real-time.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 5️⃣ Build Static Site for Production
|
|
140
|
+
|
|
141
|
+
To generate a static version of the site for production deployment:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pnpm run build
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This will create a `dist` directory containing the fully built static site, ready to be served.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🐳 Docker Deployment (Optional)
|
|
152
|
+
|
|
153
|
+
You can also build and run the static site inside a Docker container using Nginx:
|
|
154
|
+
|
|
155
|
+
### Build Docker Image
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
docker build -f k8s/Dockerfile --tag docs:1.0.0 .
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Run Docker Container
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
docker run -it -p 8080:80 docs:1.0.0
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> The site will be available at `http://localhost:8080` inside your browser.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 📂 Notes
|
|
172
|
+
|
|
173
|
+
* `pnpm run build` creates the static site inside the `dist` folder, which can be served using any static file server.
|
|
174
|
+
* The Docker image uses Nginx to serve the contents of the `dist` folder.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
## 🔮 Roadmap
|
|
178
|
+
|
|
179
|
+
We’re actively improving Dory. Here’s what’s on deck:
|
|
180
|
+
|
|
181
|
+
* [ ] 📚 **Full Documentation** — comprehensive guides, API docs, and examples
|
|
182
|
+
* [ ] 🎨 **Themes** — full theming support with a flexible theme API
|
|
183
|
+
* [ ] 🌐 **Multi-language Support** — internationalization (i18n) & localization (l10n)
|
|
184
|
+
* [ ] 🚀 **GraphQL Client** — integrated GraphQL playground and client support
|
|
185
|
+
* [ ] 🔄 **WebSocket Client** — built-in WebSocket utilities for real-time API demos
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Currently the latest version of Dory is supported. We advise you to upgrade whenever possible to receive the latest security updates.
|
|
6
|
+
|
|
7
|
+
## Reporting a Vulnerability
|
|
8
|
+
|
|
9
|
+
Please use the repo's Report A Vulnerability option to report.
|
|
10
|
+
|
|
11
|
+
The team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix, and may ask for additional information or guidance.
|
|
Binary file
|
package/bin/dory.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { existsSync, rmSync, mkdirSync, cpSync, readFileSync } from 'fs';
|
|
5
|
+
import { resolve, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
import http from 'http';
|
|
8
|
+
import sirv from 'sirv';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const commands = {
|
|
14
|
+
build: () => {
|
|
15
|
+
console.log('🏗️ Starting Dory build...');
|
|
16
|
+
|
|
17
|
+
// Check if dory.json exists in current directory
|
|
18
|
+
const currentDir = process.cwd();
|
|
19
|
+
const doryConfigPath = resolve(currentDir, 'dory.json');
|
|
20
|
+
|
|
21
|
+
if (!existsSync(doryConfigPath)) {
|
|
22
|
+
console.error('❌ dory.json not found in current directory');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Read and validate dory.json
|
|
27
|
+
try {
|
|
28
|
+
const config = JSON.parse(readFileSync(doryConfigPath, 'utf8'));
|
|
29
|
+
console.log(`📋 Using config: ${config.name || 'Unnamed project'}`);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('❌ Invalid dory.json file:', error.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Clear and prepare docs folder
|
|
36
|
+
const docsDir = resolve(currentDir, 'docs');
|
|
37
|
+
if (existsSync(docsDir)) {
|
|
38
|
+
console.log('🧹 Clearing docs folder...');
|
|
39
|
+
rmSync(docsDir, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
mkdirSync(docsDir, { recursive: true });
|
|
42
|
+
|
|
43
|
+
// Copy dory.json to docs folder
|
|
44
|
+
cpSync(doryConfigPath, resolve(docsDir, 'dory.json'));
|
|
45
|
+
console.log('📄 Copied dory.json to docs folder');
|
|
46
|
+
|
|
47
|
+
// Run the build command
|
|
48
|
+
console.log('⚡ Running build command...');
|
|
49
|
+
try {
|
|
50
|
+
execSync('npm run build', { stdio: 'inherit', cwd: __dirname });
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('❌ Build failed:', error.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if dist folder was created
|
|
57
|
+
const distDir = resolve(__dirname, '..', 'dist');
|
|
58
|
+
if (existsSync(distDir)) {
|
|
59
|
+
console.log('✅ Build completed successfully!');
|
|
60
|
+
console.log(`📦 Build output available in: ${distDir}`);
|
|
61
|
+
console.log('📋 Moving build output to current directory...');
|
|
62
|
+
cpSync(distDir, resolve(currentDir, 'dist'), { recursive: true });
|
|
63
|
+
console.log(`📦 Build output moved to: ${resolve(currentDir, 'dist')}`);
|
|
64
|
+
} else {
|
|
65
|
+
console.log('⚠️ Build completed but no dist folder found');
|
|
66
|
+
}
|
|
67
|
+
rmSync(distDir, { recursive: true, force: true });
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
preview: () => {
|
|
71
|
+
console.log('👀 Starting Dory preview...');
|
|
72
|
+
const currentDir = process.cwd();
|
|
73
|
+
const distDir = resolve(currentDir, 'dist');
|
|
74
|
+
const port = process.env.PORT || 3000;
|
|
75
|
+
|
|
76
|
+
const serve = sirv(distDir, {
|
|
77
|
+
dev: false,
|
|
78
|
+
single: true,
|
|
79
|
+
etag: true,
|
|
80
|
+
gzip: true,
|
|
81
|
+
brotli: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const server = http.createServer((req, res) => {
|
|
85
|
+
serve(req, res);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
server.listen(port, () => {
|
|
89
|
+
console.log(`🚀 Serving Dory at http://localhost:${port}`);
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
help: () => {
|
|
94
|
+
console.log(`
|
|
95
|
+
🐟 Dory CLI - Documentation Build Tool
|
|
96
|
+
|
|
97
|
+
Usage:
|
|
98
|
+
dory <command>
|
|
99
|
+
|
|
100
|
+
Commands:
|
|
101
|
+
build Build the documentation site
|
|
102
|
+
- Requires dory.json in current directory
|
|
103
|
+
- Clears and copies to docs folder
|
|
104
|
+
- Runs build command
|
|
105
|
+
- Creates dist folder with build output
|
|
106
|
+
|
|
107
|
+
preview Preview the built documentation site
|
|
108
|
+
- Requires dist folder (run build first)
|
|
109
|
+
- Starts preview server
|
|
110
|
+
|
|
111
|
+
help Show this help message
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
dory build # Build the documentation
|
|
115
|
+
dory preview # Preview the built site
|
|
116
|
+
`);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Parse command line arguments
|
|
121
|
+
const command = process.argv[2];
|
|
122
|
+
|
|
123
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
124
|
+
commands.help();
|
|
125
|
+
} else if (commands[command]) {
|
|
126
|
+
commands[command]();
|
|
127
|
+
} else {
|
|
128
|
+
console.error(`❌ Unknown command: ${command}`);
|
|
129
|
+
console.log('Run "dory help" for usage information');
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Feature Flags'
|
|
3
|
+
description: 'Manage and understand feature flags affecting the application behavior.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Feature Flags
|
|
7
|
+
|
|
8
|
+
## Purpose and Scope
|
|
9
|
+
|
|
10
|
+
The Feature Flags module provides a centralized mechanism to enable or disable specific features within the Genie application dynamically. This approach allows controlled rollout, testing, and gradual adoption of new functionalities without deploying new code versions.
|
|
11
|
+
|
|
12
|
+
This module primarily parses and validates feature flag configurations from environment variables and exposes them for use throughout the web and API services.
|
|
13
|
+
|
|
14
|
+
## Technical Overview
|
|
15
|
+
|
|
16
|
+
Feature Flags are defined and validated using the `zod` schema validation library to ensure that flag values comply with expected types. Flags can generally be boolean or strings convertible to booleans (`"true"`), permitting flexibility in how environment variables are specified.
|
|
17
|
+
|
|
18
|
+
The parsing logic safely attempts to read environment variables, falling back to an empty object on failure and capturing exceptions with Sentry for monitoring.
|
|
19
|
+
|
|
20
|
+
### Key Locations
|
|
21
|
+
|
|
22
|
+
- **Web client feature flags:** Defined and parsed in `apps/web/src/utils/feature-flags.ts`.
|
|
23
|
+
- **API service feature flags:** Defined under API config schemas in `apps/api/src/config/schemas/index.ts`.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Core Concepts and Responsibilities
|
|
27
|
+
|
|
28
|
+
- **Feature Flags Schema:** A set of typed mappings that describe each flag's expected type and optional presence.
|
|
29
|
+
- Flags can be a boolean or a string (`"true"` interpreted as `true`) or undefined.
|
|
30
|
+
- Certain flags have additional typed definitions such as arrays, e.g., `DEMAND_PLANNER_SHOP_ALLOW_LIST` which is an optional array of strings.
|
|
31
|
+
|
|
32
|
+
- **Error Handling:** Parsing errors are logged to Sentry via `Sentry.captureException(error)` to facilitate early detection of misconfiguration.
|
|
33
|
+
|
|
34
|
+
- **Environmental Scope:** Flags are read from environment variables prefixed with `NEXT_PUBLIC_FEATURE_FLAGS` for frontend exposure or `FEATURE_FLAGS` for the backend.
|
|
35
|
+
|
|
36
|
+
- **Security and Scope:** Flags must be explicitly defined in environment configuration, preventing undefined or unexpected flags from being used.
|
|
37
|
+
|
|
38
|
+
## Code Structure
|
|
39
|
+
|
|
40
|
+
### `apps/web/src/utils/feature-flags.ts`
|
|
41
|
+
|
|
42
|
+
This file implements the feature flag parsing logic for the web frontend.
|
|
43
|
+
|
|
44
|
+
- `flagSchema`: Accepts either a boolean or a string representing booleans and transforms the string to a boolean.
|
|
45
|
+
- `featureFlagsSchema`: Defines known feature flags such as `UI_PAGE`, `DEMAND_PLANNER`, `MOV`, `PAYMENT_TERMS`, and others. Some flags are booleans, others arrays of strings.
|
|
46
|
+
- `parseFeatureFlags()`:
|
|
47
|
+
- Attempts to JSON parse the environment variable `NEXT_PUBLIC_FEATURE_FLAGS`.
|
|
48
|
+
- Validates it against the schema.
|
|
49
|
+
- On error, logs to Sentry and returns an empty object.
|
|
50
|
+
- `FEATURE_FLAGS`: Exported constant representing the parsed flags for app-wide consumption.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { z } from "zod";
|
|
54
|
+
import * as Sentry from "@sentry/nextjs";
|
|
55
|
+
|
|
56
|
+
const flagSchema = z.union([
|
|
57
|
+
z.boolean(),
|
|
58
|
+
z.string().transform((val) => val === "true")
|
|
59
|
+
]).optional();
|
|
60
|
+
|
|
61
|
+
const featureFlagsSchema = z.object({
|
|
62
|
+
UI_PAGE: flagSchema,
|
|
63
|
+
DEMAND_PLANNER: flagSchema,
|
|
64
|
+
DEMAND_PLANNER_SHOP_ALLOW_LIST: z.array(z.string()).optional(),
|
|
65
|
+
MOV: flagSchema,
|
|
66
|
+
PAYMENT_TERMS: flagSchema,
|
|
67
|
+
MANUAL_STATUS: flagSchema,
|
|
68
|
+
REPORTS_ALERTS: flagSchema,
|
|
69
|
+
PAYMENTS_PAGE: flagSchema,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
type FeatureFlags = z.infer<typeof featureFlagsSchema>;
|
|
73
|
+
|
|
74
|
+
const parseFeatureFlags = (): FeatureFlags => {
|
|
75
|
+
try {
|
|
76
|
+
return featureFlagsSchema.parse(
|
|
77
|
+
JSON.parse(process.env.NEXT_PUBLIC_FEATURE_FLAGS || "{}")
|
|
78
|
+
);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
Sentry.captureException(error);
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const FEATURE_FLAGS = parseFeatureFlags();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `apps/api/src/config/schemas/index.ts`
|
|
89
|
+
|
|
90
|
+
This file extends feature flag support within the API backend.
|
|
91
|
+
|
|
92
|
+
- The API uses a similar schema (`featureFlagSchema`) that accepts booleans or strings convertible to booleans.
|
|
93
|
+
- `featureFlagsSchema` is defined but currently empty (`z.object({} satisfies Record<string, typeof featureFlagSchema>)`).
|
|
94
|
+
- The `FEATURE_FLAGS` environment variable is parsed and coerced to a string, then JSON parsed and validated.
|
|
95
|
+
|
|
96
|
+
The config schema merges the feature flags, along with many other env vars, into a consolidated validation schema.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const featureFlagSchema = z.union([
|
|
100
|
+
z.boolean(),
|
|
101
|
+
z.string().transform((value) => value === "true")
|
|
102
|
+
]).optional();
|
|
103
|
+
|
|
104
|
+
const featureFlagsSchema = z.object(
|
|
105
|
+
{} satisfies Record<string, typeof featureFlagSchema>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
export type FeatureFlags = z.infer<typeof featureFlagsSchema>;
|
|
109
|
+
|
|
110
|
+
export const configSchema = z.object({
|
|
111
|
+
// ... other config fields ...
|
|
112
|
+
FEATURE_FLAGS: z.coerce.string().optional().transform((jsonString = "{}") =>
|
|
113
|
+
featureFlagsSchema.parse(JSON.parse(jsonString))
|
|
114
|
+
),
|
|
115
|
+
// ... other config fields ...
|
|
116
|
+
}).merge(databaseConfigSchema).strip();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Environment & Configuration
|
|
120
|
+
|
|
121
|
+
### Environment Variables
|
|
122
|
+
|
|
123
|
+
- `NEXT_PUBLIC_FEATURE_FLAGS` (frontend): JSON string representing flags.
|
|
124
|
+
- `FEATURE_FLAGS` (API backend): JSON string representing flags.
|
|
125
|
+
|
|
126
|
+
Example environment value for frontend (simplified):
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"UI_PAGE": true,
|
|
131
|
+
"DEMAND_PLANNER": "true",
|
|
132
|
+
"DEMAND_PLANNER_SHOP_ALLOW_LIST": ["shop1", "shop2"],
|
|
133
|
+
"MOV": false
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The environment variable must be valid JSON and correctly typed for each feature flag.
|
|
138
|
+
|
|
139
|
+
## Integration & System Boundaries
|
|
140
|
+
|
|
141
|
+
- **Web UI:** Uses parsed `FEATURE_FLAGS` to enable/disable UI features.
|
|
142
|
+
- **API:** Reads feature flags from environment on startup to alter backend behavior.
|
|
143
|
+
- **Error Logging:** Parsing issues send errors to Sentry for diagnosis.
|
|
144
|
+
|
|
145
|
+
## Observability & Error Handling
|
|
146
|
+
|
|
147
|
+
- Parsing errors of feature flags are monitored via Sentry.
|
|
148
|
+
- Apps fall back gracefully to default empty flags on error, ensuring stability.
|
|
149
|
+
|
|
150
|
+
## Summary
|
|
151
|
+
|
|
152
|
+
This feature flags module provides a robust, type-safe approach to managing application features dynamically through environment configuration. It ensures flags are validated on startup and exposes them as constants for consistent use across frontend and backend components.
|
|
153
|
+
|
|
154
|
+
## References
|
|
155
|
+
|
|
156
|
+
- [Feature Flags in Web Frontend](apps/web/src/utils/feature-flags.ts)
|
|
157
|
+
- [Feature Flags in API Config](apps/api/src/config/schemas/index.ts)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'User and Team Settings'
|
|
3
|
+
description: 'Configuration of user preferences, team settings, saved views, and insights settings.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## User and Team Settings - Internal Developer Documentation
|
|
7
|
+
|
|
8
|
+
### 1. Purpose and Scope
|
|
9
|
+
|
|
10
|
+
This module handles **user and team settings management** within the Genie application, enabling users to configure team-wide preferences, manage memberships, and control notifications. It provides REST API endpoints to update and retrieve team general settings, insights settings, shop settings, and manage invitations and team members.
|
|
11
|
+
|
|
12
|
+
The module's responsibilities include:
|
|
13
|
+
- CRUD operations on team settings (general, insights, shop).
|
|
14
|
+
- Managing team member invitations and acceptance.
|
|
15
|
+
- Deactivating users from a team.
|
|
16
|
+
- Querying team membership and invitation status.
|
|
17
|
+
- Managing user notification preferences.
|
|
18
|
+
|
|
19
|
+
It acts as a boundary between frontend clients and backend services managing persistent storage and business logic related to teams and user contexts.
|
|
20
|
+
|
|
21
|
+
### 2. Technical Overview
|
|
22
|
+
|
|
23
|
+
The main components involved are:
|
|
24
|
+
|
|
25
|
+
- **TeamsController** (`apps/api/src/user-management/controllers/teams.controller.ts`): API entrypoint defining HTTP routes for team settings and team user management.
|
|
26
|
+
- **SettingsService** (`apps/api/src/user-management/services/settings.service.ts`): Business logic for retrieving and updating team settings.
|
|
27
|
+
- **TeamsService** (`apps/api/src/user-management/services/teams.service.ts`): Business logic for user and invitation management within teams.
|
|
28
|
+
- **UserContextController** (`apps/api/src/user-management/controllers/user-context.controller.ts`): Manages retrieval of user context and notification preferences.
|
|
29
|
+
|
|
30
|
+
The module leverages **NestJS** for structuring controllers and services and **TypeORM** for database interactions with `TeamEntity`, `UserEntity`, and `MemberInvitationEntity`.
|
|
31
|
+
|
|
32
|
+
Dependencies include:
|
|
33
|
+
- Shared DTOs and schemas from `@genie/shared` for payload validation.
|
|
34
|
+
- Zod validation pipes for input validation.
|
|
35
|
+
- JWT service for token handling during invitation acceptance.
|
|
36
|
+
|
|
37
|
+
#### Architectural Pattern:
|
|
38
|
+
- The system follows an **MVC-style architecture** where Controllers handle HTTP requests, delegate to Services for business logic, and Services interact with entities via repositories.
|
|
39
|
+
|
|
40
|
+
### 3. Core Concepts and Responsibilities
|
|
41
|
+
|
|
42
|
+
- **Team Settings** are divided into:
|
|
43
|
+
- **General Settings**: Business name, contact info, VAT, and address.
|
|
44
|
+
- **Insights Settings**: Sales period days, stock levels, and grading strategy parameters.
|
|
45
|
+
- **Shop Settings**: Currency and timezone.
|
|
46
|
+
|
|
47
|
+
- **Users and Invitations**:
|
|
48
|
+
- Invitations are managed as entities with statuses (Pending, Accepted, Expired).
|
|
49
|
+
- An invitation can be sent, accepted with validation and token generation, or expired.
|
|
50
|
+
- Only Admin users can deactivate users.
|
|
51
|
+
|
|
52
|
+
- **Notification Settings**:
|
|
53
|
+
- Stored as JSON config inside team entity under `notifications`.
|
|
54
|
+
- Users can retrieve and update their notification preferences.
|
|
55
|
+
|
|
56
|
+
- **Error Handling**:
|
|
57
|
+
- If requests come from users with no team association, `GenieException` with "User not in a team" message is thrown.
|
|
58
|
+
- Role-based authorization on critical operations like user deactivation.
|
|
59
|
+
|
|
60
|
+
- **Security**:
|
|
61
|
+
- Invitation acceptance requires a valid code (invitation ID) and checks for expiration.
|
|
62
|
+
- JWT tokens are issued upon invitation acceptance.
|
|
63
|
+
|
|
64
|
+
### 4. Code Structure
|
|
65
|
+
|
|
66
|
+
| File | Description |
|
|
67
|
+
|-------|-------------|
|
|
68
|
+
| `teams.controller.ts` | API endpoints for team settings and user management (send invitations, deactivate users, retrieve members) |
|
|
69
|
+
| `settings.service.ts` | Implements logic to get and update team settings in the DB, including insights and shop settings |
|
|
70
|
+
| `teams.service.ts` | Handles user retrieval, invitations, notification states, team user management, and tokenized invitation acceptance |
|
|
71
|
+
| `user-context.controller.ts` | API endpoints to get user context and manage user notification preferences |
|
|
72
|
+
| `team.entity.ts` | Defines Team entity schema, including settings fields and onboarding states |
|
|
73
|
+
| `user.entity.ts` | Defines User entity schema and relations to team |
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
#### Example snippet from TeamsController showing settings update endpoint:
|
|
77
|
+
```ts
|
|
78
|
+
@Put("settings")
|
|
79
|
+
@HttpCode(204)
|
|
80
|
+
async updateTeamSettings(@Request() { user }: RequestWithUser, @Body(new ZodValidationPipe(teamSettingsDtoSchema)) settings: TeamSettingsDto) {
|
|
81
|
+
if (!user.teamId) throw new GenieException("User not in a team");
|
|
82
|
+
await this.settingsService.updateTeamSettings(user.teamId, settings);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 5. API and Interfaces
|
|
87
|
+
|
|
88
|
+
#### TeamsController Endpoints Summary
|
|
89
|
+
|
|
90
|
+
| Endpoint | Method | Description | Req. Auth | Input (DTO) | Output |
|
|
91
|
+
|-------------------------------|--------|-----------------------------------------------------|-----------|-------------------------------------|--------------------------|
|
|
92
|
+
| `/teams/settings` | PUT | Update complete team settings | Yes | `TeamSettingsDto` | 204 No Content |
|
|
93
|
+
| `/teams/settings/general` | PUT | Update team general settings | Yes | `TeamGeneralSettingsDto` | 204 No Content |
|
|
94
|
+
| `/teams/settings/general` | GET | Get team general settings | Yes | - | `TeamGeneralSettingsDto` |
|
|
95
|
+
| `/teams/settings/insights` | PUT | Update team insights settings | Yes | `InsightsSettingsDto` | 204 No Content |
|
|
96
|
+
| `/teams/settings/insights` | GET | Get team insights settings | Yes | - | `InsightsSettingsDto` |
|
|
97
|
+
| `/teams/settings/shop` | GET | Get team shop settings (currency, timezone) | Yes | - | `GetShopSettingsResponseDto` |
|
|
98
|
+
| `/teams/members` | GET | Get all team members and invitations | Yes | - | `GetTeamUsersInfoResponseDto` |
|
|
99
|
+
| `/teams/send-invitations` | POST | Send invitations to new members | Yes | `SendInvitationsRequestDto` | `SendInvitationsResponseDto` |
|
|
100
|
+
| `/teams/user/:id/deactivate` | PATCH | Deactivate a user (admin-only) | Yes | - | 204 No Content |
|
|
101
|
+
| `/teams/invitations/:email` | DELETE | Remove an invitation by email | Yes | - | 204 No Content |
|
|
102
|
+
| `/teams/accept-invitation` | POST | Accept invitation and obtain auth token | No | `AcceptInvitationRequestDto` | `{ token: string }` |
|
|
103
|
+
|
|
104
|
+
#### UserContextController Endpoints
|
|
105
|
+
|
|
106
|
+
| Endpoint | Method | Description | Auth | Input | Output |
|
|
107
|
+
|-------------------------|--------|--------------------------------|--------|-------------------------|-------------------------------|
|
|
108
|
+
| `/user-context` | GET | Get current user context | Yes | - | `GetUserContextResponseDto` |
|
|
109
|
+
| `/user-context/notifications` | GET | Get user/team notification prefs | Yes | - | `UserNotificationsSchema` |
|
|
110
|
+
| `/user-context/notifications` | PUT | Update notification preferences | Yes | `UserNotificationsSchema` | 204 No Content |
|
|
111
|
+
|
|
112
|
+
#### API Validation
|
|
113
|
+
- All request bodies are validated using `ZodValidationPipe` based on shared DTO schemas.
|
|
114
|
+
- User authorization checks confirm user belongs to a team before proceeding.
|
|
115
|
+
|
|
116
|
+
#### Failure Modes
|
|
117
|
+
- Throws `GenieException` with clear messages for unauthorized or invalid operations, e.g. "User not in a team", "Only team admins can remove users".
|
|
118
|
+
- Invitation acceptance fails with `ForbiddenException` for invalid or expired codes.
|
|
119
|
+
|
|
120
|
+
### 6. Environment & Configuration
|
|
121
|
+
|
|
122
|
+
- Uses environment variables for:
|
|
123
|
+
- Intercom secret (`INTERCOM_IDENTITY_VERIFICATION_SECRET`) for generating user hashes.
|
|
124
|
+
- Team integration tokens for Mantle subscription management.
|
|
125
|
+
|
|
126
|
+
- Slack app token and channel IDs are used indirectly via injected `SlackService` for notifications when related to teams.
|
|
127
|
+
|
|
128
|
+
- Team settings updates impact DB table `team` via TypeORM repository.
|
|
129
|
+
|
|
130
|
+
- JWT secret utilized by `JwtService` for signing tokens on invitation acceptance.
|
|
131
|
+
|
|
132
|
+
### 7. Testing, Monitoring, and Deployment
|
|
133
|
+
|
|
134
|
+
- Standard NestJS testing practices apply. Unit and integration tests should cover:
|
|
135
|
+
- Controller endpoint authorization and validation.
|
|
136
|
+
- Service method's DB interactions and error handling.
|
|
137
|
+
|
|
138
|
+
- Observability:
|
|
139
|
+
- Errors throw `GenieException` which integrates with centralized error handling.
|
|
140
|
+
- Logging and tracing occur in related services (not detailed here).
|
|
141
|
+
|
|
142
|
+
- Deployment follows standard service lifecycle as per NestJS backend.
|
|
143
|
+
|
|
144
|
+
### 8. Troubleshooting & Known Issues
|
|
145
|
+
|
|
146
|
+
- Common failure if the user is not assigned to a team is consistently checked in controllers.
|
|
147
|
+
- Admin-only restrictions on deactivation ensure minimal privilege violations.
|
|
148
|
+
- Expired or invalid invitation codes are handled explicitly with meaningful exceptions.
|
|
149
|
+
|
|
150
|
+
### 9. Style and Tone Guidelines
|
|
151
|
+
|
|
152
|
+
- Terminology consistent with codebase entities: "team", "user", "invitation", "settings".
|
|
153
|
+
- Methods first check authorization and preconditions, then perform updates.
|
|
154
|
+
- API uses HTTP 204 status for successful PUT/PATCH requests with no response body.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Mermaid Diagram: Teams and User Settings Module Architecture
|
|
159
|
+
|
|
160
|
+
```mermaid
|
|
161
|
+
flowchart TD
|
|
162
|
+
subgraph API Layer
|
|
163
|
+
TeamsController["TeamsController<br/>(HTTP API)" ]:::api
|
|
164
|
+
UserContextController["UserContextController<br/>(User Context API)"]:::api
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
subgraph Services Layer
|
|
168
|
+
SettingsService["SettingsService<br/>Team Settings Logic"]:::service
|
|
169
|
+
TeamsService["TeamsService<br/>User & Invitations Logic"]:::service
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
subgraph Persistence Layer
|
|
173
|
+
TeamEntity["TeamEntity<br/>(Postgres DB)"]:::db
|
|
174
|
+
UserEntity["UserEntity<br/>(Postgres DB)"]:::db
|
|
175
|
+
MemberInvitationEntity["MemberInvitationEntity<br/>(Postgres DB)"]:::db
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
%% Relationships
|
|
179
|
+
TeamsController -->|calls| SettingsService
|
|
180
|
+
TeamsController -->|calls| TeamsService
|
|
181
|
+
UserContextController -->|calls| TeamsService
|
|
182
|
+
|
|
183
|
+
SettingsService -->|reads/writes| TeamEntity
|
|
184
|
+
TeamsService -->|reads/writes| UserEntity
|
|
185
|
+
TeamsService -->|reads/writes| TeamEntity
|
|
186
|
+
TeamsService -->|reads/writes| MemberInvitationEntity
|
|
187
|
+
|
|
188
|
+
%% Classes styles
|
|
189
|
+
classDef api fill:#f9f,stroke:#333,stroke-width:1px,color:#000
|
|
190
|
+
classDef service fill:#bbf,stroke:#333,stroke-width:1px,color:#000
|
|
191
|
+
classDef db fill:#bfb,stroke:#060,stroke-width:1px,color:#060
|
|
192
|
+
|
|
193
|
+
%% Click events
|
|
194
|
+
click TeamsController "apps/api/src/user-management/controllers/teams.controller.ts"
|
|
195
|
+
click UserContextController "apps/api/src/user-management/controllers/user-context.controller.ts"
|
|
196
|
+
click SettingsService "apps/api/src/user-management/services/settings.service.ts"
|
|
197
|
+
click TeamsService "apps/api/src/user-management/services/teams.service.ts"
|
|
198
|
+
click TeamEntity "apps/api/src/user-management/entities/team.entity.ts"
|
|
199
|
+
click UserEntity "apps/api/src/user-management/entities/user.entity.ts"
|
|
200
|
+
click MemberInvitationEntity "apps/api/src/user-management/entities/member-invitation.entity.ts"
|
|
201
|
+
```
|