02-rbor 0.2.0 β†’ 0.2.1

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.
Files changed (2) hide show
  1. package/README.md +676 -606
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,606 +1,676 @@
1
- # 02-rBOR CLI
2
-
3
- [![npm version](https://img.shields.io/npm/v/02-rbor.svg)](https://www.npmjs.com/package/02-rbor)
4
- [![CI](https://github.com/02-davinci-01/02-rbor/workflows/CI/badge.svg)](https://github.com/02-davinci-01/02-rbor/actions)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
-
7
- > **Scaffold Clean Architecture-inspired React features with dependency graph analysis**
8
-
9
- A CLI tool for building frontend applications following the **02-rBOR** architecture pattern. Generate domain-driven feature modules with proper layering, enforce architectural rules, and analyze dependency graphs β€” with SVG visualization out of the box.
10
-
11
- ## πŸ€” What is rBOR?
12
-
13
- rBOR is an opinionated folder architecture for React apps. Instead of organizing by file type (`components/`, `hooks/`, `services/` at the root), rBOR organizes by **domain** β€” each feature gets its own self-contained folder with every layer it needs.
14
-
15
- The idea: a `user` feature shouldn't scatter its files across 6 different top-level folders. Everything related to `user` lives under `domains/user/`, with a single barrel export (`index.tsx`) as the public API.
16
-
17
- Each domain follows a strict **downward dependency rule** inspired by the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle):
18
-
19
- ```
20
- Page β†’ Component β†’ Hook (data/action) β†’ Hook (controller) β†’ Method β†’ Service β†’ Infrastructure
21
- (route) (UI) (React Query) (wiring) (logic) (HTTP) (shared base)
22
- ```
23
-
24
- **control flows upward** β€” each layer orchestrates the layer below it.
25
- **dependencies flow downward** β€” lower layers are completely independent of what consumes them.
26
-
27
- This means:
28
-
29
- - `Infrastructure` (BaseService, ServiceFactory) knows nothing about any domain.
30
- - `Service` extends BaseService β€” depends only on infrastructure.
31
- - `Method` receives a service object as its first argument β€” depends only on services.
32
- - `Hook (controller)` creates the service via ServiceFactory, passes it to methods β€” depends on methods & infrastructure.
33
- - `Hook (data/action)` consumes the controller hook for fetching or mutations β€” depends on the controller.
34
- - `Component` renders data from hooks β€” depends only on hooks.
35
- - `Page` composes components β€” depends only on components.
36
-
37
- Lower layers never import from higher layers. This keeps your business logic testable, your services reusable, and your UI replaceable.
38
-
39
- ## πŸ“¦ Installation
40
-
41
- ```bash
42
- npm install -g 02-rbor
43
- ```
44
-
45
- ```bash
46
- rbor init
47
- rbor domain auth
48
- ```
49
-
50
- > **Tip:** If you prefer not to install globally, use `npx` β€” it works without any install:
51
- >
52
- > ```bash
53
- > npx 02-rbor domain auth
54
- > ```
55
- >
56
- > All commands work with `npx 02-rbor <command>`, for example:
57
- >
58
- > ```bash
59
- > npx 02-rbor domain <domain-name>
60
- > npx 02-rbor validate
61
- > npx 02-rbor deps domains/auth -f svg
62
- > ```
63
-
64
- ## πŸš€ Quick Start
65
-
66
- ### 1. Initialize your project
67
-
68
- ```bash
69
- rbor init
70
- ```
71
-
72
- This creates a `.rborrc.json` configuration file with your project defaults.
73
-
74
- ### 2. Generate your first domain
75
-
76
- ```bash
77
- # Interactive mode β€” prompts for name and HTTP client
78
- rbor domain
79
-
80
- # Or pass the name directly
81
- rbor domain user --http axios
82
- ```
83
-
84
- This generates a complete domain structure:
85
-
86
- ```
87
- domains/user/
88
- β”œβ”€β”€ index.tsx # Barrel export (public API)
89
- β”œβ”€β”€ __test__/ # Test directory
90
- β”œβ”€β”€ components/
91
- β”‚ └── User.tsx # Main component
92
- β”œβ”€β”€ hooks/
93
- β”‚ β”œβ”€β”€ useUser.ts # Controller hook (creates service, wires methods)
94
- β”‚ β”œβ”€β”€ useUserData.ts # Data hook (React Query)
95
- β”‚ └── useUserAction.ts # Action hook (mutations)
96
- β”œβ”€β”€ methods/
97
- β”‚ └── user-logic.ts # Pure async functions (React-independent)
98
- β”œβ”€β”€ schema/
99
- β”‚ └── user-schema.ts # Validation schema (zod)
100
- β”œβ”€β”€ services/
101
- β”‚ └── user-service.ts # Domain service (HTTP layer)
102
- β”œβ”€β”€ types/
103
- β”‚ └── user-types.ts # TypeScript types
104
- └── utils/
105
- β”œβ”€β”€ constant/
106
- β”‚ β”œβ”€β”€ user-constants.ts
107
- β”‚ └── user-endpoints.ts
108
- └── helper/
109
- └── user-helpers.ts
110
- ```
111
-
112
- #### What each folder does
113
-
114
- | Folder | Purpose | Rules |
115
- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
116
- | **`components/`** | React UI. Renders data, handles user interaction. | Can import from `hooks/`. Nothing else in the domain. |
117
- | **`hooks/`** | Wiring layer. Connects React to your domain logic. | `useUser` creates the service object and passes it to methods. `useUserData` and `useUserAction` provide React Query scaffolds for fetching and mutations. |
118
- | **`methods/`** | Pure business logic. Every function receives the service as its first argument β€” no React, no hooks, no global state. | Can import from `services/` and `utils/`. Must stay framework-free so it's easy to test and reuse. |
119
- | **`services/`** | HTTP layer. Extends `BaseService` to get an axios (or fetch/ky) instance. Exposes typed `get`, `post`, `put`, `delete` methods with URL param substitution. | Can import from `infrastructure/` and `utils/`. |
120
- | **`schema/`** | Validation schemas (zod by default). Define the shape of your domain data for form validation, API response parsing, etc. | Pure data definitions β€” no side effects. |
121
- | **`types/`** | TypeScript interfaces and types for this domain. | Pure type definitions. |
122
- | **`utils/constant/`** | Endpoint paths and domain-specific constants (timeouts, config values, feature flags). | Pure values β€” no logic. |
123
- | **`utils/helper/`** | Domain-specific utility functions (formatters, transformers, parsers). | Pure functions β€” no React, no service calls. |
124
- | **`__test__/`** | Tests for this domain. | Mirrors the folder structure above. |
125
- | **`index.tsx`** | Barrel export β€” the **only** file other parts of your app should import from. | Re-exports the component and anything else that's part of the public API. |
126
-
127
- #### How data flows
128
-
129
- ```
130
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
131
- β”‚ Component │────▢│ Hook (data/ │────▢│ Hook │────▢│ Method │────▢│ Service │────▢│ Infrastructure β”‚
132
- β”‚ (User.tsx) β”‚ β”‚ action) β”‚ β”‚ (controller) β”‚ β”‚(user-logic)β”‚ β”‚(UserService)β”‚ β”‚ (BaseService) β”‚
133
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ useUserData β”‚ β”‚ useUser β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
134
- UI β”‚ useUserAction β”‚ β”‚ creates service β”‚ pure logic HTTP calls axios instance
135
- renders β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ & wires methods β”‚ receives extends interceptors
136
- data React Query β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ service as BaseService base URL
137
- fetching & β”‚ 1st param β–² timeout
138
- mutations β”‚ β”‚
139
- └────── ServiceFactory.create() β”€β”€β”€β”€β”€β”€β”€β”˜
140
- ```
141
-
142
- **Dependency Inversion in practice:**
143
-
144
- - Lower layers are **stable abstractions** β€” they define contracts (BaseService, ServiceFactory registry) that don't change when features change.
145
- - Higher layers are **volatile details** β€” UI, state management, and wiring change frequently.
146
- - Each layer only depends on the layer directly below it, never sideways or upward.
147
- - ServiceFactory never imports domain services β€” each service self-registers via `ServiceFactory.register()` at the bottom of its file. The controller hook triggers registration by importing the service file.
148
- - `hook-data` and `hook-action` are **independent siblings** β€” both depend on the controller hook, but never on each other.
149
-
150
- ### 3. Add endpoints and constants
151
-
152
- ```bash
153
- cd domains/user
154
- rbor endpoint users/:id/profile # β†’ USERS_ID_PROFILE
155
- rbor constant timeout=3000 # β†’ TIMEOUT = 3000
156
- ```
157
-
158
- ### 4. Analyze dependencies
159
-
160
- ```bash
161
- # Who imports this file?
162
- rbor deps domains/user/components/User.tsx -d reverse -f svg -o deps.svg
163
-
164
- # What does this file import?
165
- rbor deps src/app/App.tsx -d forward -f tree
166
- ```
167
-
168
- ### 5. Validate architecture
169
-
170
- ```bash
171
- rbor validate
172
- ```
173
-
174
- ---
175
-
176
- ## πŸ“š Commands
177
-
178
- | Command | Description |
179
- | --------------------------- | ------------------------------------------------ |
180
- | `rbor init` | Initialize `.rborrc.json` configuration |
181
- | `rbor domain [name]` | Generate a domain (interactive if no name given) |
182
- | `rbor endpoint <path>` | Add an endpoint to the current domain |
183
- | `rbor constant <key=value>` | Add a constant to the current domain |
184
- | `rbor list` | List all domains with metadata |
185
- | `rbor validate` | Validate architecture rules |
186
- | `rbor deps <path>` | Analyze dependency graph |
187
- | `rbor davinci` | Credits |
188
-
189
- ---
190
-
191
- ### `rbor init`
192
-
193
- Initialize rBOR configuration in your project.
194
-
195
- ```bash
196
- rbor init [options]
197
-
198
- Options:
199
- --http <client> HTTP client (axios, fetch, ky)
200
- --domains-path <path> Path to domains folder
201
- --infrastructure-path <path> Path to infrastructure folder
202
- --force Overwrite existing config
203
- ```
204
-
205
- Creates `.rborrc.json`:
206
-
207
- ```json
208
- {
209
- "http": "axios",
210
- "domainsPath": "domains",
211
- "infrastructurePath": "infrastructure",
212
- "schema": { "library": "zod" }
213
- }
214
- ```
215
-
216
- ---
217
-
218
- ### `rbor domain [name]`
219
-
220
- Generate a new domain with the full 02-rBOR structure.
221
-
222
- ```bash
223
- # Interactive mode (prompts for name, HTTP client, confirmation)
224
- rbor domain
225
-
226
- # Direct mode
227
- rbor domain auth
228
- rbor domain products --http ky
229
- ```
230
-
231
- **What it generates:**
232
-
233
- - βœ… Component with TypeScript + JSX
234
- - βœ… Three-hook pattern (controller, data, action)
235
- - βœ… Pure domain logic (methods receive service, stay React-free)
236
- - βœ… Service layer with HTTP client integration
237
- - βœ… Validation schemas (zod)
238
- - βœ… Type definitions
239
- - βœ… Constants and endpoint files
240
- - βœ… Barrel export (index.tsx)
241
-
242
- **Hook pattern:**
243
-
244
- Three hooks are generated per domain:
245
-
246
- - **`use<Domain>`** β€” Controller hook. Creates a service object and wires up all methods:
247
- - **`use<Domain>Data`** β€” Data hook. Fetches server state using React Query (commented scaffold).
248
- - **`use<Domain>Action`** β€” Action hook. Mutation actions via React Query (commented scaffold).
249
-
250
- The controller hook wires up services and methods:
251
-
252
- ```ts
253
- export const useUser = () => {
254
- const service = ServiceFactory.create('USER') as UserService;
255
-
256
- return {
257
- getList: () => getUserList(service),
258
- getById: (id: string) => getUserById(service, id),
259
- create: (data: unknown) => createUser(service, data),
260
- update: (id: string, data: unknown) => updateUser(service, id, data),
261
- remove: (id: string) => deleteUser(service, id),
262
- };
263
- };
264
- ```
265
-
266
- > **Note:** If you need access to the Redux store or other global state, access it in the hook and pass values down to your methods. Methods should remain pure async functions.
267
-
268
- ---
269
-
270
- ### `rbor endpoint <path>`
271
-
272
- Add an API endpoint constant to an existing domain. Run from inside `domains/<domain>/`.
273
-
274
- ```bash
275
- rbor endpoint users/:id/profile
276
- ```
277
-
278
- Generates ALL_CAPS keys and appends to `utils/constant/<domain>-endpoints.ts`:
279
-
280
- ```ts
281
- export const AUTH_ENDPOINTS = {
282
- LOGIN: '/login',
283
- USERS_ID_PROFILE: '/users/:id/profile',
284
- } as const;
285
- ```
286
-
287
- ---
288
-
289
- ### `rbor constant <key=value>`
290
-
291
- Add a constant to the current domain's constants file. Run from inside `domains/<domain>/`.
292
-
293
- ```bash
294
- rbor constant timeout=3000 # β†’ export const TIMEOUT = 3000;
295
- rbor constant maxRetries=5 # β†’ export const MAX_RETRIES = 5;
296
- rbor constant api-url=https://x # β†’ export const API_URL = 'https://x';
297
- rbor constant debug=true # β†’ export const DEBUG = true;
298
- ```
299
-
300
- Auto-detects value types β€” numbers and booleans stay unquoted, strings get wrapped in quotes.
301
-
302
- ---
303
-
304
- ### `rbor list`
305
-
306
- List all domains with metadata.
307
-
308
- ```bash
309
- rbor list # or: rbor ls
310
- ```
311
-
312
- ---
313
-
314
- ### `rbor validate`
315
-
316
- Enforce 02-rBOR architectural rules.
317
-
318
- ```bash
319
- rbor validate # or: rbor lint
320
- rbor validate --strict # treat warnings as errors
321
- ```
322
-
323
- **What it checks:**
324
-
325
- - ❌ **No cross-domain imports** β€” Domains must not import from each other
326
- - ❌ **Downward-only dependencies** β€” Page β†’ Component β†’ Hook (data/action) β†’ Hook (controller) β†’ Method β†’ Service β†’ Infrastructure
327
- - ❌ **Sibling isolation** β€” `hook-data` and `hook-action` must be independent (no importing each other)
328
- - ❌ **No React in methods layer** β€” Pure logic must be framework-free
329
- - ⚠️ **Barrel exports** β€” Every domain should have an index.tsx
330
- - ⚠️ **Circular dependencies** β€” Warns about import cycles
331
-
332
- ---
333
-
334
- ### `rbor deps <path>`
335
-
336
- Analyze dependency graphs for any file or directory. Traces imports forward (what does this file use?) or reverse (who imports this file?) and renders the result in five different formats β€” from quick terminal summaries to full SVG diagrams you can open in a browser.
337
-
338
- ```bash
339
- rbor deps <path> [options]
340
- ```
341
-
342
- #### Flags
343
-
344
- | Flag | Short | Description | Default |
345
- | --------------------- | ----- | ------------------------------------------------------ | ------------------------------- |
346
- | `--direction <dir>` | `-d` | `forward` (imports) or `reverse` (importers) | `forward` |
347
- | `--format <fmt>` | `-f` | Output format: `summary`, `tree`, `json`, `dot`, `svg` | `summary` |
348
- | `--output <file>` | `-o` | Write output to a file instead of stdout | _(stdout)_ |
349
- | `--depth <n>` | | Maximum traversal depth | `10` |
350
- | `--include-external` | | Include external npm packages in the graph | `false` |
351
- | `--include-tests` | | Include test files (`*.test.*`, `*.spec.*`) | `false` |
352
- | `--include-types` | | Include type-only imports (`import type { ... }`) | `true` |
353
- | `--aliases <mapping>` | | Path aliases, e.g. `"@/=src/,@utils/=src/utils/"` | _(auto-detected from tsconfig)_ |
354
-
355
- > **Alias auto-detection:** If your project has a `tsconfig.json` with `compilerOptions.paths`, aliases are read automatically. Use `--aliases` to add extras or override.
356
-
357
- #### Direction
358
-
359
- ```
360
- --direction forward (default) --direction reverse
361
-
362
- "What does this file import?" "Who imports this file?"
363
-
364
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
365
- β”‚ App.tsx │── imports ──▢ router.ts β”‚ App.tsx │◀── imported by ── Layout.tsx
366
- β”‚ (entry) │── imports ──▢ store.ts β”‚ (entry) │◀── imported by ── Main.tsx
367
- β”‚ │── imports ──▢ utils.ts β”‚ │◀── imported by ── test.tsx
368
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
369
- ```
370
-
371
- Use `forward` to understand what a file depends on. Use `reverse` to see a file's consumers β€” useful for gauging blast radius before a refactor.
372
-
373
- #### Output Formats
374
-
375
- **`summary`** (default) β€” Grouped table view in the terminal. Shows imports and importers categorized by file type, plus stats.
376
-
377
- ```
378
- ═══════════════════════════════════════════════════════════════
379
- FILE SUMMARY: useUser.ts
380
- Path: domains/user/hooks/useUser.ts
381
- ═══════════════════════════════════════════════════════════════
382
-
383
- πŸ“₯ IMPORTS (what this file depends on)
384
- πŸ”¨ method user-logic.ts
385
- πŸ—οΈ infrastructure ServiceFactory.ts
386
- πŸ“ type user-types.ts
387
-
388
- πŸ“€ IMPORTED BY (what depends on this file)
389
- πŸ“Š hook-data useUserData.ts
390
- ⚑ hook-action useUserAction.ts
391
-
392
- πŸ“Š STATS
393
- Nodes: 5 β”‚ Edges: 4 β”‚ Circular: 0
394
- ═══════════════════════════════════════════════════════════════
395
- ```
396
-
397
- **`tree`** β€” ASCII tree in the terminal. Respects `--depth` to control how deep the traversal goes.
398
-
399
- ```
400
- πŸ“¦ domains/user/hooks/useUser.ts
401
- β”œβ”€β”€ πŸ”¨ domains/user/methods/user-logic.ts
402
- β”‚ └── βš™οΈ domains/user/services/user-service.ts
403
- β”‚ └── πŸ—οΈ infrastructure/BaseService.ts
404
- β”œβ”€β”€ πŸ—οΈ infrastructure/ServiceFactory.ts
405
- └── πŸ“ domains/user/types/user-types.ts
406
- ```
407
-
408
- **`json`** β€” Full structured output. Contains `nodes`, `edges`, `metadata`, and `stats`. Pipe to `jq` or consume in scripts.
409
-
410
- ```bash
411
- rbor deps domains/user -f json | jq '.stats'
412
- rbor deps domains/user -f json -o deps.json
413
- ```
414
-
415
- ```json
416
- {
417
- "nodes": [
418
- { "id": "domains/user/hooks/useUser.ts", "type": "internal", "category": "hook-controller" }
419
- ],
420
- "edges": [
421
- {
422
- "source": "domains/user/hooks/useUser.ts",
423
- "target": "domains/user/methods/user-logic.ts",
424
- "importType": "static"
425
- }
426
- ],
427
- "metadata": { "direction": "forward", "circularDependencies": [] },
428
- "stats": { "nodeCount": 5, "edgeCount": 4 }
429
- }
430
- ```
431
-
432
- **`dot`** β€” [Graphviz DOT](https://graphviz.org/) format. Use if you have Graphviz installed locally or want to paste into an online viewer.
433
-
434
- ```bash
435
- rbor deps domains/user -f dot -o deps.dot
436
- dot -Tpng deps.dot -o deps.png # render with Graphviz
437
- ```
438
-
439
- **`svg`** β€” Renders the DOT graph to an SVG image using `@viz-js/viz` (bundled, no external install needed). This is the richest format β€” color-coded nodes, labeled edges, and circular dependency highlighting.
440
-
441
- ```bash
442
- rbor deps domains/user -f svg -o deps.svg
443
- # Open deps.svg in your browser or VS Code
444
- ```
445
-
446
- SVG/DOT node colors:
447
-
448
- ```
449
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
450
- β”‚ 🟣 Entry point (purple) β”‚
451
- β”‚ πŸ”΅ Internal file (blue) β”‚
452
- β”‚ 🟒 External package (green)β”‚
453
- β”‚ 🟑 Dynamic import (amber) β”‚
454
- β”‚ βšͺ Built-in module (grey) β”‚
455
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
456
- ```
457
-
458
- #### Circular Dependency Detection
459
-
460
- All formats detect and report circular imports. In SVG/DOT output they're visually highlighted:
461
-
462
- ```
463
- Normal edge: Circular edge:
464
-
465
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
466
- β”‚ A.ts │───────────▢ B.ts β”‚ A.ts β”‚β”€β”€β”€βš  circular──▢ B.ts
467
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ (red edge)
468
- (blue) (red border)
469
-
470
- πŸ”΄ Red borders β€” nodes involved in a cycle
471
- πŸ”΄ Red edges β€” the circular import itself, labeled "⚠ circular"
472
- πŸ“‹ Legend box β€” appears in the bottom-left with the cycle count
473
- ```
474
-
475
- The `summary` and `tree` formats print `(circular)` inline when a cycle is encountered.
476
-
477
- #### Recipes
478
-
479
- ```bash
480
- # Quick overview of a domain's internal structure
481
- rbor deps domains/auth -f tree --depth 3
482
-
483
- # Full SVG graph saved to file
484
- rbor deps domains/auth -f svg -o auth-deps.svg
485
-
486
- # Reverse lookup: who depends on this service?
487
- rbor deps domains/auth/services/auth-service.ts -d reverse -f tree
488
-
489
- # Include npm packages in the graph
490
- rbor deps src/App.tsx -f svg --include-external -o full-deps.svg
491
-
492
- # Shallow analysis (immediate imports only)
493
- rbor deps domains/auth/hooks/useAuth.ts -f summary --depth 1
494
-
495
- # JSON for scripting / CI pipelines
496
- rbor deps domains/auth -f json -o deps.json
497
-
498
- # Custom aliases (on top of tsconfig auto-detection)
499
- rbor deps src/App.tsx --aliases "@shared/=src/shared/,@lib/=lib/"
500
- ```
501
-
502
- ---
503
-
504
- ## βš™οΈ Configuration
505
-
506
- ### `.rborrc.json`
507
-
508
- ```json
509
- {
510
- "http": "axios",
511
- "domainsPath": "domains",
512
- "infrastructurePath": "infrastructure",
513
- "schema": { "library": "zod" }
514
- }
515
- ```
516
-
517
- | Option | Description | Values |
518
- | -------------------- | ------------------------- | ---------------------- |
519
- | `http` | Default HTTP client | `axios`, `fetch`, `ky` |
520
- | `domainsPath` | Where to generate domains | Any path |
521
- | `infrastructurePath` | Shared infrastructure dir | Any path |
522
- | `schema.library` | Validation library | `zod`, `yup`, `none` |
523
-
524
- CLI flags always override config values.
525
-
526
- ---
527
-
528
- ## πŸ—οΈ Architecture Philosophy
529
-
530
- **02-rBOR** is built on the **Dependency Inversion Principle** β€” higher layers control the flow, lower layers remain independent abstractions.
531
-
532
- ### The Layer Model
533
-
534
- ```
535
- Layer 0 β”‚ type, schema, constant, config, util ← importable by anyone (pure data)
536
- Layer 1 β”‚ infrastructure (BaseService, Factory) ← independent, no domain knowledge
537
- Layer 2 β”‚ service (extends BaseService) ← depends only on infrastructure
538
- Layer 3 β”‚ method (pure async functions) ← depends on service, no React
539
- Layer 4 β”‚ hook-controller (useUser) ← wires service + methods
540
- Layer 5 β”‚ hook-data / hook-action ← consumes controller, independent siblings
541
- Layer 6 β”‚ component (User.tsx) ← renders from hooks
542
- Layer 7 β”‚ page (route) ← composes components
543
- ```
544
-
545
- Each layer can import from the **same layer or below**, never above. `hook-data` and `hook-action` are at the same level but must stay independent β€” both consume the controller, neither consumes the other.
546
-
547
- ### Why this works
548
-
549
- 1. **Feature Containerization** β€” Each domain is self-contained with a single barrel export. The rest of the app imports `from 'domains/user'`, never `from 'domains/user/services/user-service'`.
550
- 2. **Downward Dependencies** β€” Complexity flows down: Page β†’ Component β†’ Hook β†’ Method β†’ Service β†’ Infrastructure. Upper layers orchestrate lower layers, never the reverse.
551
- 3. **Layer Separation** β€” React stays in the component and hook layers. Methods are pure async functions that receive a service object and return data. You can unit test them without rendering anything.
552
- 4. **No Cross-Domain Imports** β€” `domains/auth` must never import from `domains/user`. Shared logic goes in `infrastructure/`.
553
- 5. **Service as a Parameter** β€” Methods don't create their own HTTP clients. They receive the service object from the hook, making them easy to mock and test.
554
- 6. **Sibling Isolation** β€” `useUserData` (fetching) and `useUserAction` (mutations) are independent. They both depend on `useUser` (the controller), but never on each other. This prevents tangled state flows between reads and writes.
555
-
556
- ### Infrastructure (shared across all domains)
557
-
558
- ```
559
- infrastructure/
560
- β”œβ”€β”€ BaseService.ts # Abstract class β€” creates axios instance, interceptors, base CRUD methods
561
- β”œβ”€β”€ ServiceFactory.ts # Registry-based factory β€” services self-register, factory never imports domain code
562
- └── generateURL.ts # URL builder β€” replaces :params and appends ?query strings
563
- ```
564
-
565
- - **BaseService** β€” Every domain service extends this. It creates an axios instance with configured `baseURL`, `timeout`, and request/response interceptors. Exposes `protected` `get`, `post`, `put`, `delete` methods that all domain services inherit.
566
- - **ServiceFactory** β€” A registry-based factory. Each domain service calls `ServiceFactory.register('KEY', () => new DomainService())` at the bottom of its own file. The factory never imports domain code β€” it just stores creators and instantiates on demand via `ServiceFactory.create('KEY')`. This keeps infrastructure fully independent (Dependency Inversion).
567
- - **generateURL** β€” Utility for URL parameter substitution (`/users/:id` β†’ `/users/42`) and query string building.
568
-
569
- ---
570
-
571
- ## πŸ§ͺ Testing
572
-
573
- ```bash
574
- npm test # Run all tests
575
- npm run test:watch # Watch mode
576
- npm run test:coverage # Coverage report
577
- ```
578
-
579
- ---
580
-
581
- ## πŸ’‘ Examples
582
-
583
- ```bash
584
- # Full domain setup
585
- rbor domain auth --http axios
586
- cd domains/auth
587
- rbor endpoint auth/login
588
- rbor endpoint auth/logout
589
- rbor endpoint auth/refresh
590
- rbor constant session-timeout=1800000
591
-
592
- # Analyze and validate
593
- rbor validate --strict
594
- rbor deps domains/auth -d forward -f svg -o auth-deps.svg
595
- rbor list
596
- ```
597
-
598
- ---
599
-
600
- ## πŸ“„ License
601
-
602
- MIT Β© [02-davinci-01](https://github.com/02-davinci-01)
603
-
604
- ---
605
-
606
- **rendered to reality by [02-davinci-01](https://02-davinci-01.vercel.app)**
1
+ # 02-rBOR CLI
2
+
3
+ [![npm version](https://img.shields.io/npm/v/02-rbor.svg)](https://www.npmjs.com/package/02-rbor)
4
+ [![CI](https://github.com/02-davinci-01/02-rbor/workflows/CI/badge.svg)](https://github.com/02-davinci-01/02-rbor/actions)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ > **Scaffold Clean Architecture-inspired React features with dependency graph analysis**
8
+
9
+ A CLI tool for building frontend applications following the **02-rBOR** architecture pattern. Generate domain-driven feature modules with proper layering, enforce architectural rules, and analyze dependency graphs β€” with SVG visualization out of the box.
10
+
11
+ ## πŸ€” What is rBOR?
12
+
13
+ rBOR is an opinionated folder architecture for React apps. Instead of organizing by file type (`components/`, `hooks/`, `services/` at the root), rBOR organizes by **domain** β€” each feature gets its own self-contained folder with every layer it needs.
14
+
15
+ The idea: a `user` feature shouldn't scatter its files across 6 different top-level folders. Everything related to `user` lives under `domains/user/`, with a single barrel export (`index.tsx`) as the public API.
16
+
17
+ Each domain follows a strict **downward dependency rule** inspired by the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle):
18
+
19
+ ```
20
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
21
+ β”‚ Page (route) β”‚ composes components
22
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
23
+ β–Ό
24
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
25
+ β”‚ Component (UI) β”‚ renders data from hooks
26
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
27
+ β–Ό
28
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
29
+ β”‚ Hook β€” data / action β”‚ React Query fetching & mutations
30
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
31
+ β–Ό
32
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
33
+ β”‚ Hook β€” controller β”‚ creates service, wires methods
34
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
35
+ β–Ό
36
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
37
+ β”‚ Method (pure logic) β”‚ receives service as 1st param
38
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
39
+ β–Ό
40
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
41
+ β”‚ Service (HTTP layer) β”‚ extends BaseService
42
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
43
+ β–Ό
44
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
45
+ β”‚ Infrastructure (shared) β”‚ BaseService, ServiceFactory
46
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
47
+ ```
48
+
49
+ **Control flows upward** β€” each layer orchestrates the layer below it.
50
+ **Dependencies flow downward** β€” lower layers are completely independent of what consumes them.
51
+
52
+ This means:
53
+
54
+ - `Infrastructure` (BaseService, ServiceFactory) knows nothing about any domain.
55
+ - `Service` extends BaseService β€” depends only on infrastructure.
56
+ - `Method` receives a service object as its first argument β€” depends only on services.
57
+ - `Hook (controller)` creates the service via ServiceFactory, passes it to methods β€” depends on methods & infrastructure.
58
+ - `Hook (data/action)` consumes the controller hook for fetching or mutations β€” depends on the controller.
59
+ - `Component` renders data from hooks β€” depends only on hooks.
60
+ - `Page` composes components β€” depends only on components.
61
+
62
+ Lower layers never import from higher layers. This keeps your business logic testable, your services reusable, and your UI replaceable.
63
+
64
+ ## πŸ“¦ Installation
65
+
66
+ ```bash
67
+ npm install -g 02-rbor
68
+ ```
69
+
70
+ ```bash
71
+ rbor init
72
+ rbor domain <domain-name>
73
+ ```
74
+
75
+ > **Tip:** If you prefer not to install globally, use `npx` β€” it works without any install:
76
+ >
77
+ > ```bash
78
+ > npx 02-rbor init
79
+ > npx 02-rbor domain <domain-name>
80
+ > ```
81
+ >
82
+ > All commands work with `npx 02-rbor <command>`, for example:
83
+ >
84
+ > ```bash
85
+ > npx 02-rbor domain user
86
+ > npx 02-rbor validate
87
+ > npx 02-rbor deps domains/user -f svg
88
+ > ```
89
+
90
+ ## πŸš€ Quick Start
91
+
92
+ ### 1. Initialize your project
93
+
94
+ ```bash
95
+ rbor init
96
+ ```
97
+
98
+ This creates a `.rborrc.json` configuration file with your project defaults.
99
+
100
+ ### 2. Generate your first domain
101
+
102
+ ```bash
103
+ # Interactive mode β€” prompts for name and HTTP client
104
+ rbor domain
105
+
106
+ # Or pass the name directly
107
+ rbor domain user --http axios
108
+ ```
109
+
110
+ This generates a complete domain structure:
111
+
112
+ ```
113
+ domains/user/
114
+ β”œβ”€β”€ index.tsx # Barrel export (public API)
115
+ β”œβ”€β”€ __test__/ # Test directory
116
+ β”œβ”€β”€ components/
117
+ β”‚ └── User.tsx # Main component
118
+ β”œβ”€β”€ hooks/
119
+ β”‚ β”œβ”€β”€ useUser.ts # Controller hook (creates service, wires methods)
120
+ β”‚ β”œβ”€β”€ useUserData.ts # Data hook (React Query)
121
+ β”‚ └── useUserAction.ts # Action hook (mutations)
122
+ β”œβ”€β”€ methods/
123
+ β”‚ └── user-logic.ts # Pure async functions (React-independent)
124
+ β”œβ”€β”€ schema/
125
+ β”‚ └── user-schema.ts # Validation schema (zod)
126
+ β”œβ”€β”€ services/
127
+ β”‚ └── user-service.ts # Domain service (HTTP layer)
128
+ β”œβ”€β”€ types/
129
+ β”‚ └── user-types.ts # TypeScript types
130
+ └── utils/
131
+ β”œβ”€β”€ constant/
132
+ β”‚ β”œβ”€β”€ user-constants.ts
133
+ β”‚ └── user-endpoints.ts
134
+ └── helper/
135
+ └── user-helpers.ts
136
+ ```
137
+
138
+ #### What each folder does
139
+
140
+ | Folder | Purpose | Rules |
141
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
142
+ | **`components/`** | React UI. Renders data, handles user interaction. | Can import from `hooks/`. Nothing else in the domain. |
143
+ | **`hooks/`** | Wiring layer. Connects React to your domain logic. | `useUser` creates the service object and passes it to methods. `useUserData` and `useUserAction` provide React Query scaffolds for fetching and mutations. |
144
+ | **`methods/`** | Pure business logic. Every function receives the service as its first argument β€” no React, no hooks, no global state. | Can import from `services/` and `utils/`. Must stay framework-free so it's easy to test and reuse. |
145
+ | **`services/`** | HTTP layer. Extends `BaseService` to get an axios (or fetch/ky) instance. Exposes typed `get`, `post`, `put`, `delete` methods with URL param substitution. | Can import from `infrastructure/` and `utils/`. |
146
+ | **`schema/`** | Validation schemas (zod by default). Define the shape of your domain data for form validation, API response parsing, etc. | Pure data definitions β€” no side effects. |
147
+ | **`types/`** | TypeScript interfaces and types for this domain. | Pure type definitions. |
148
+ | **`utils/constant/`** | Endpoint paths and domain-specific constants (timeouts, config values, feature flags). | Pure values β€” no logic. |
149
+ | **`utils/helper/`** | Domain-specific utility functions (formatters, transformers, parsers). | Pure functions β€” no React, no service calls. |
150
+ | **`__test__/`** | Tests for this domain. | Mirrors the folder structure above. |
151
+ | **`index.tsx`** | Barrel export β€” the **only** file other parts of your app should import from. | Re-exports the component and anything else that's part of the public API. |
152
+
153
+ #### How data flows
154
+
155
+ ```
156
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
157
+ β”‚ Component (User.tsx) β”‚ UI β€” renders data
158
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
159
+ β”‚ uses hooks
160
+ β–Ό
161
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
162
+ β”‚ useUserData / useUserAction β”‚ React Query β€” fetching & mutations
163
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
164
+ β”‚ consumes controller
165
+ β–Ό
166
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
167
+ β”‚ useUser (controller hook) β”‚ creates service, wires methods
168
+ β”‚ β”‚ ServiceFactory.create('USER')
169
+ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
170
+ β”‚ β”‚
171
+ β–Ό β–Ό
172
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
173
+ β”‚ user-logic β”‚ β”‚ ServiceFactory β”‚
174
+ β”‚ (methods) β”‚ β”‚ (infrastructure) β”‚
175
+ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
176
+ β”‚ calls service
177
+ β–Ό
178
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
179
+ β”‚ UserService β”‚ extends BaseService
180
+ β”‚ self-registers with Factory β”‚
181
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
182
+ β”‚
183
+ β–Ό
184
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
185
+ β”‚ BaseService β”‚ axios instance, interceptors,
186
+ β”‚ (infrastructure) β”‚ base URL, timeout
187
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
188
+ ```
189
+
190
+ **Dependency Inversion in practice:**
191
+
192
+ - Lower layers are **stable abstractions** β€” they define contracts (BaseService, ServiceFactory registry) that don't change when features change.
193
+ - Higher layers are **volatile details** β€” UI, state management, and wiring change frequently.
194
+ - Each layer only depends on the layer directly below it, never sideways or upward.
195
+ - ServiceFactory never imports domain services β€” each service self-registers via `ServiceFactory.register()` at the bottom of its file. The controller hook triggers registration by importing the service file.
196
+ - `hook-data` and `hook-action` are **independent siblings** β€” both depend on the controller hook, but never on each other.
197
+
198
+ ### 3. Add endpoints and constants
199
+
200
+ ```bash
201
+ cd domains/user
202
+ rbor endpoint users/:id/profile # β†’ USERS_ID_PROFILE
203
+ rbor constant timeout=3000 # β†’ TIMEOUT = 3000
204
+ ```
205
+
206
+ ### 4. Analyze dependencies
207
+
208
+ ```bash
209
+ # Who imports this file?
210
+ rbor deps domains/user/components/User.tsx -d reverse -f svg -o deps.svg
211
+
212
+ # What does this file import?
213
+ rbor deps src/app/App.tsx -d forward -f tree
214
+ ```
215
+
216
+ ### 5. Validate architecture
217
+
218
+ ```bash
219
+ rbor validate
220
+ ```
221
+
222
+ ---
223
+
224
+ ## πŸ“š Commands
225
+
226
+ | Command | Description |
227
+ | --------------------------- | ------------------------------------------------ |
228
+ | `rbor init` | Initialize `.rborrc.json` configuration |
229
+ | `rbor domain [name]` | Generate a domain (interactive if no name given) |
230
+ | `rbor endpoint <path>` | Add an endpoint to the current domain |
231
+ | `rbor constant <key=value>` | Add a constant to the current domain |
232
+ | `rbor list` | List all domains with metadata |
233
+ | `rbor validate` | Validate architecture rules |
234
+ | `rbor deps <path>` | Analyze dependency graph |
235
+ | `rbor davinci` | Credits |
236
+
237
+ ---
238
+
239
+ ### `rbor init`
240
+
241
+ Initialize rBOR configuration in your project.
242
+
243
+ ```bash
244
+ rbor init [options]
245
+
246
+ Options:
247
+ --http <client> HTTP client (axios, fetch, ky)
248
+ --domains-path <path> Path to domains folder
249
+ --infrastructure-path <path> Path to infrastructure folder
250
+ --force Overwrite existing config
251
+ ```
252
+
253
+ Creates `.rborrc.json`:
254
+
255
+ ```json
256
+ {
257
+ "http": "axios",
258
+ "domainsPath": "domains",
259
+ "infrastructurePath": "infrastructure",
260
+ "schema": { "library": "zod" }
261
+ }
262
+ ```
263
+
264
+ ---
265
+
266
+ ### `rbor domain [name]`
267
+
268
+ Generate a new domain with the full 02-rBOR structure.
269
+
270
+ ```bash
271
+ # Interactive mode (prompts for name, HTTP client, confirmation)
272
+ rbor domain
273
+
274
+ # Direct mode
275
+ rbor domain auth
276
+ rbor domain products --http ky
277
+ ```
278
+
279
+ **What it generates:**
280
+
281
+ - βœ… Component with TypeScript + JSX
282
+ - βœ… Three-hook pattern (controller, data, action)
283
+ - βœ… Pure domain logic (methods receive service, stay React-free)
284
+ - βœ… Service layer with HTTP client integration
285
+ - βœ… Validation schemas (zod)
286
+ - βœ… Type definitions
287
+ - βœ… Constants and endpoint files
288
+ - βœ… Barrel export (index.tsx)
289
+
290
+ **Hook pattern:**
291
+
292
+ Three hooks are generated per domain:
293
+
294
+ - **`use<Domain>`** β€” Controller hook. Creates a service object and wires up all methods:
295
+ - **`use<Domain>Data`** β€” Data hook. Fetches server state using React Query (commented scaffold).
296
+ - **`use<Domain>Action`** β€” Action hook. Mutation actions via React Query (commented scaffold).
297
+
298
+ The controller hook wires up services and methods:
299
+
300
+ ```ts
301
+ export const useUser = () => {
302
+ const service = ServiceFactory.create('USER') as UserService;
303
+
304
+ return {
305
+ getList: () => getUserList(service),
306
+ getById: (id: string) => getUserById(service, id),
307
+ create: (data: unknown) => createUser(service, data),
308
+ update: (id: string, data: unknown) => updateUser(service, id, data),
309
+ remove: (id: string) => deleteUser(service, id),
310
+ };
311
+ };
312
+ ```
313
+
314
+ > **Note:** If you need access to the Redux store or other global state, access it in the hook and pass values down to your methods. Methods should remain pure async functions.
315
+
316
+ ---
317
+
318
+ ### `rbor endpoint <path>`
319
+
320
+ Add an API endpoint constant to an existing domain. Run from inside `domains/<domain>/`.
321
+
322
+ ```bash
323
+ rbor endpoint users/:id/profile
324
+ ```
325
+
326
+ Generates ALL_CAPS keys and appends to `utils/constant/<domain>-endpoints.ts`:
327
+
328
+ ```ts
329
+ export const AUTH_ENDPOINTS = {
330
+ LOGIN: '/login',
331
+ USERS_ID_PROFILE: '/users/:id/profile',
332
+ } as const;
333
+ ```
334
+
335
+ ---
336
+
337
+ ### `rbor constant <key=value>`
338
+
339
+ Add a constant to the current domain's constants file. Run from inside `domains/<domain>/`.
340
+
341
+ ```bash
342
+ rbor constant timeout=3000 # β†’ export const TIMEOUT = 3000;
343
+ rbor constant maxRetries=5 # β†’ export const MAX_RETRIES = 5;
344
+ rbor constant api-url=https://x # β†’ export const API_URL = 'https://x';
345
+ rbor constant debug=true # β†’ export const DEBUG = true;
346
+ ```
347
+
348
+ Auto-detects value types β€” numbers and booleans stay unquoted, strings get wrapped in quotes.
349
+
350
+ ---
351
+
352
+ ### `rbor list`
353
+
354
+ List all domains with metadata.
355
+
356
+ ```bash
357
+ rbor list # or: rbor ls
358
+ ```
359
+
360
+ ---
361
+
362
+ ### `rbor validate`
363
+
364
+ Enforce 02-rBOR architectural rules.
365
+
366
+ ```bash
367
+ rbor validate # or: rbor lint
368
+ rbor validate --strict # treat warnings as errors
369
+ ```
370
+
371
+ **What it checks:**
372
+
373
+ - ❌ **No cross-domain imports** β€” Domains must not import from each other
374
+ - ❌ **Downward-only dependencies** β€” Page β†’ Component β†’ Hook (data/action) β†’ Hook (controller) β†’ Method β†’ Service β†’ Infrastructure
375
+ - ❌ **Sibling isolation** β€” `hook-data` and `hook-action` must be independent (no importing each other)
376
+ - ❌ **No React in methods layer** β€” Pure logic must be framework-free
377
+ - ⚠️ **Barrel exports** β€” Every domain should have an index.tsx
378
+ - ⚠️ **Circular dependencies** β€” Warns about import cycles
379
+
380
+ ---
381
+
382
+ ### `rbor deps <path>`
383
+
384
+ Analyze dependency graphs for any file or directory. Traces imports forward (what does this file use?) or reverse (who imports this file?) and renders the result in five different formats β€” from quick terminal summaries to full SVG diagrams you can open in a browser.
385
+
386
+ ```bash
387
+ rbor deps <path> [options]
388
+ ```
389
+
390
+ #### Flags
391
+
392
+ | Flag | Short | Description | Default |
393
+ | --------------------- | ----- | ------------------------------------------------------ | ------------------------------- |
394
+ | `--direction <dir>` | `-d` | `forward` (imports) or `reverse` (importers) | `forward` |
395
+ | `--format <fmt>` | `-f` | Output format: `summary`, `tree`, `json`, `dot`, `svg` | `summary` |
396
+ | `--output <file>` | `-o` | Write output to a file instead of stdout | _(stdout)_ |
397
+ | `--depth <n>` | | Maximum traversal depth | `10` |
398
+ | `--include-external` | | Include external npm packages in the graph | `false` |
399
+ | `--include-tests` | | Include test files (`*.test.*`, `*.spec.*`) | `false` |
400
+ | `--include-types` | | Include type-only imports (`import type { ... }`) | `true` |
401
+ | `--aliases <mapping>` | | Path aliases, e.g. `"@/=src/,@utils/=src/utils/"` | _(auto-detected from tsconfig)_ |
402
+
403
+ > **Alias auto-detection:** If your project has a `tsconfig.json` with `compilerOptions.paths`, aliases are read automatically. Use `--aliases` to add extras or override.
404
+
405
+ #### Direction
406
+
407
+ **`--direction forward`** (default) β€” "What does this file import?"
408
+
409
+ ```
410
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
411
+ β”‚ App.tsx β”‚
412
+ β”‚ (entry) β”‚
413
+ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
414
+ β”‚
415
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
416
+ β–Ό β–Ό β–Ό
417
+ router.ts store.ts utils.ts
418
+ ```
419
+
420
+ **`--direction reverse`** β€” "Who imports this file?"
421
+
422
+ ```
423
+ Layout.tsx Main.tsx test.tsx
424
+ β”‚ β”‚ β”‚
425
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
426
+ β–Ό
427
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
428
+ β”‚ App.tsx β”‚
429
+ β”‚ (target) β”‚
430
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
431
+ ```
432
+
433
+ Use `forward` to understand what a file depends on. Use `reverse` to see a file's consumers β€” useful for gauging blast radius before a refactor.
434
+
435
+ #### Output Formats
436
+
437
+ **`summary`** (default) β€” Grouped table view in the terminal. Shows imports and importers categorized by file type, plus stats.
438
+
439
+ ```
440
+ ═══════════════════════════════════════════════════════════════
441
+ FILE SUMMARY: useUser.ts
442
+ Path: domains/user/hooks/useUser.ts
443
+ ═══════════════════════════════════════════════════════════════
444
+
445
+ πŸ“₯ IMPORTS (what this file depends on)
446
+ πŸ”¨ method user-logic.ts
447
+ πŸ—οΈ infrastructure ServiceFactory.ts
448
+ πŸ“ type user-types.ts
449
+
450
+ πŸ“€ IMPORTED BY (what depends on this file)
451
+ πŸ“Š hook-data useUserData.ts
452
+ ⚑ hook-action useUserAction.ts
453
+
454
+ πŸ“Š STATS
455
+ Nodes: 5 β”‚ Edges: 4 β”‚ Circular: 0
456
+ ═══════════════════════════════════════════════════════════════
457
+ ```
458
+
459
+ **`tree`** β€” ASCII tree in the terminal. Respects `--depth` to control how deep the traversal goes.
460
+
461
+ ```
462
+ πŸ“¦ domains/user/hooks/useUser.ts
463
+ β”œβ”€β”€ πŸ”¨ domains/user/methods/user-logic.ts
464
+ β”‚ └── βš™οΈ domains/user/services/user-service.ts
465
+ β”‚ └── πŸ—οΈ infrastructure/BaseService.ts
466
+ β”œβ”€β”€ πŸ—οΈ infrastructure/ServiceFactory.ts
467
+ └── πŸ“ domains/user/types/user-types.ts
468
+ ```
469
+
470
+ **`json`** β€” Full structured output. Contains `nodes`, `edges`, `metadata`, and `stats`. Pipe to `jq` or consume in scripts.
471
+
472
+ ```bash
473
+ rbor deps domains/user -f json | jq '.stats'
474
+ rbor deps domains/user -f json -o deps.json
475
+ ```
476
+
477
+ ```json
478
+ {
479
+ "nodes": [
480
+ { "id": "domains/user/hooks/useUser.ts", "type": "internal", "category": "hook-controller" }
481
+ ],
482
+ "edges": [
483
+ {
484
+ "source": "domains/user/hooks/useUser.ts",
485
+ "target": "domains/user/methods/user-logic.ts",
486
+ "importType": "static"
487
+ }
488
+ ],
489
+ "metadata": { "direction": "forward", "circularDependencies": [] },
490
+ "stats": { "nodeCount": 5, "edgeCount": 4 }
491
+ }
492
+ ```
493
+
494
+ **`dot`** β€” [Graphviz DOT](https://graphviz.org/) format. Use if you have Graphviz installed locally or want to paste into an online viewer.
495
+
496
+ ```bash
497
+ rbor deps domains/user -f dot -o deps.dot
498
+ dot -Tpng deps.dot -o deps.png # render with Graphviz
499
+ ```
500
+
501
+ **`svg`** β€” Renders the DOT graph to an SVG image using `@viz-js/viz` (bundled, no external install needed). This is the richest format β€” color-coded nodes, labeled edges, and circular dependency highlighting.
502
+
503
+ ```bash
504
+ rbor deps domains/user -f svg -o deps.svg
505
+ # Open deps.svg in your browser or VS Code
506
+ ```
507
+
508
+ SVG/DOT node colors:
509
+
510
+ ```
511
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
512
+ β”‚ 🟣 Entry point (purple) β”‚
513
+ β”‚ πŸ”΅ Internal file (blue) β”‚
514
+ β”‚ 🟒 External package (green)β”‚
515
+ β”‚ 🟑 Dynamic import (amber) β”‚
516
+ β”‚ βšͺ Built-in module (grey) β”‚
517
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
518
+ ```
519
+
520
+ #### Circular Dependency Detection
521
+
522
+ All formats detect and report circular imports. In SVG/DOT output they're visually highlighted:
523
+
524
+ ```
525
+ Normal edge: Circular edge:
526
+
527
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
528
+ β”‚ A.ts β”‚ β”‚ A.ts β”‚ (red border)
529
+ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
530
+ β”‚ β”‚
531
+ β–Ό β–Ό ⚠ circular (red edge)
532
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
533
+ β”‚ B.ts β”‚ β”‚ B.ts β”‚ (red border)
534
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜
535
+
536
+ πŸ”΄ Red borders β€” nodes involved in a cycle
537
+ πŸ”΄ Red edges β€” the circular import itself, labeled "⚠ circular"
538
+ πŸ“‹ Legend box β€” appears in the bottom-left with the cycle count
539
+ ```
540
+
541
+ The `summary` and `tree` formats print `(circular)` inline when a cycle is encountered.
542
+
543
+ #### Recipes
544
+
545
+ ```bash
546
+ # Quick overview of a domain's internal structure
547
+ rbor deps domains/auth -f tree --depth 3
548
+
549
+ # Full SVG graph saved to file
550
+ rbor deps domains/auth -f svg -o auth-deps.svg
551
+
552
+ # Reverse lookup: who depends on this service?
553
+ rbor deps domains/auth/services/auth-service.ts -d reverse -f tree
554
+
555
+ # Include npm packages in the graph
556
+ rbor deps src/App.tsx -f svg --include-external -o full-deps.svg
557
+
558
+ # Shallow analysis (immediate imports only)
559
+ rbor deps domains/auth/hooks/useAuth.ts -f summary --depth 1
560
+
561
+ # JSON for scripting / CI pipelines
562
+ rbor deps domains/auth -f json -o deps.json
563
+
564
+ # Custom aliases (on top of tsconfig auto-detection)
565
+ rbor deps src/App.tsx --aliases "@shared/=src/shared/,@lib/=lib/"
566
+ ```
567
+
568
+ ---
569
+
570
+ ## βš™οΈ Configuration
571
+
572
+ ### `.rborrc.json`
573
+
574
+ ```json
575
+ {
576
+ "http": "axios",
577
+ "domainsPath": "domains",
578
+ "infrastructurePath": "infrastructure",
579
+ "schema": { "library": "zod" }
580
+ }
581
+ ```
582
+
583
+ | Option | Description | Values |
584
+ | -------------------- | ------------------------- | ---------------------- |
585
+ | `http` | Default HTTP client | `axios`, `fetch`, `ky` |
586
+ | `domainsPath` | Where to generate domains | Any path |
587
+ | `infrastructurePath` | Shared infrastructure dir | Any path |
588
+ | `schema.library` | Validation library | `zod`, `yup`, `none` |
589
+
590
+ CLI flags always override config values.
591
+
592
+ ---
593
+
594
+ ## πŸ—οΈ Architecture Philosophy
595
+
596
+ **02-rBOR** is built on the **Dependency Inversion Principle** β€” higher layers control the flow, lower layers remain independent abstractions.
597
+
598
+ ### The Layer Model
599
+
600
+ ```
601
+ Layer 0 β”‚ type, schema, constant, config, util ← importable by anyone (pure data)
602
+ Layer 1 β”‚ infrastructure (BaseService, Factory) ← independent, no domain knowledge
603
+ Layer 2 β”‚ service (extends BaseService) ← depends only on infrastructure
604
+ Layer 3 β”‚ method (pure async functions) ← depends on service, no React
605
+ Layer 4 β”‚ hook-controller (useUser) ← wires service + methods
606
+ Layer 5 β”‚ hook-data / hook-action ← consumes controller, independent siblings
607
+ Layer 6 β”‚ component (User.tsx) ← renders from hooks
608
+ Layer 7 β”‚ page (route) ← composes components
609
+ ```
610
+
611
+ Each layer can import from the **same layer or below**, never above. `hook-data` and `hook-action` are at the same level but must stay independent β€” both consume the controller, neither consumes the other.
612
+
613
+ ### Why this works
614
+
615
+ 1. **Feature Containerization** β€” Each domain is self-contained with a single barrel export. The rest of the app imports `from 'domains/user'`, never `from 'domains/user/services/user-service'`.
616
+ 2. **Downward Dependencies** β€” Complexity flows down: Page β†’ Component β†’ Hook β†’ Method β†’ Service β†’ Infrastructure. Upper layers orchestrate lower layers, never the reverse.
617
+ 3. **Layer Separation** β€” React stays in the component and hook layers. Methods are pure async functions that receive a service object and return data. You can unit test them without rendering anything.
618
+ 4. **No Cross-Domain Imports** β€” `domains/auth` must never import from `domains/user`. Shared logic goes in `infrastructure/`.
619
+ 5. **Service as a Parameter** β€” Methods don't create their own HTTP clients. They receive the service object from the hook, making them easy to mock and test.
620
+ 6. **Sibling Isolation** β€” `useUserData` (fetching) and `useUserAction` (mutations) are independent. They both depend on `useUser` (the controller), but never on each other. This prevents tangled state flows between reads and writes.
621
+
622
+ ### Infrastructure (shared across all domains)
623
+
624
+ ```
625
+ infrastructure/
626
+ β”œβ”€β”€ BaseService.ts # Abstract class β€” creates axios instance, interceptors, base CRUD methods
627
+ β”œβ”€β”€ ServiceFactory.ts # Registry-based factory β€” services self-register, factory never imports domain code
628
+ └── generateURL.ts # URL builder β€” replaces :params and appends ?query strings
629
+ ```
630
+
631
+ - **BaseService** β€” Every domain service extends this. It creates an axios instance with configured `baseURL`, `timeout`, and request/response interceptors. Exposes `protected` `get`, `post`, `put`, `delete` methods that all domain services inherit.
632
+ - **ServiceFactory** β€” A registry-based factory. Each domain service calls `ServiceFactory.register('KEY', () => new DomainService())` at the bottom of its own file. The factory never imports domain code β€” it just stores creators and instantiates on demand via `ServiceFactory.create('KEY')`. This keeps infrastructure fully independent (Dependency Inversion).
633
+ - **generateURL** β€” Utility for URL parameter substitution (`/users/:id` β†’ `/users/42`) and query string building.
634
+
635
+ ---
636
+
637
+ ## πŸ§ͺ Testing
638
+
639
+ ```bash
640
+ npm test # Run all tests
641
+ npm run test:watch # Watch mode
642
+ npm run test:coverage # Coverage report
643
+ ```
644
+
645
+ ---
646
+
647
+ ## πŸ’‘ Examples
648
+
649
+ ```bash
650
+ # Full domain setup
651
+ rbor domain auth --http axios
652
+ cd domains/auth
653
+ rbor endpoint auth/login
654
+ rbor endpoint auth/logout
655
+ rbor endpoint auth/refresh
656
+ rbor constant session-timeout=1800000
657
+
658
+ # Generate more domains
659
+ rbor domain user
660
+ rbor domain products --http ky
661
+
662
+ # Analyze and validate
663
+ rbor validate --strict
664
+ rbor deps domains/auth -d forward -f svg -o auth-deps.svg
665
+ rbor list
666
+ ```
667
+
668
+ ---
669
+
670
+ ## πŸ“„ License
671
+
672
+ MIT Β© [02-davinci-01](https://github.com/02-davinci-01)
673
+
674
+ ---
675
+
676
+ **rendered to reality by [02-davinci-01](https://02-davinci-01.vercel.app)**