hazo_files 1.0.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/.cursor/rules/db_schema.mdc +0 -0
- package/.cursor/rules/design.mdc +0 -0
- package/.cursor/rules/general.mdc +0 -0
- package/CHANGE_LOG.md +341 -0
- package/CLAUDE.md +926 -0
- package/README.md +929 -0
- package/SETUP_CHECKLIST.md +931 -0
- package/TECHDOC.md +325 -0
- package/dist/index.d.mts +1031 -0
- package/dist/index.d.ts +1031 -0
- package/dist/index.js +2457 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2333 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ui/index.js +4054 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/index.mjs +3982 -0
- package/dist/ui/index.mjs.map +1 -0
- package/docs/ADDING_MODULES.md +964 -0
- package/hazo_files_config.ini +31 -0
- package/package.json +83 -0
package/TECHDOC.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# hazo_files - Technical Documentation
|
|
2
|
+
|
|
3
|
+
Comprehensive technical reference describing system architecture, components, data flows, and integration patterns.
|
|
4
|
+
|
|
5
|
+
## System Architecture
|
|
6
|
+
|
|
7
|
+
The hazo_files package is built on a layered architecture with pluggable storage modules.
|
|
8
|
+
|
|
9
|
+
### Architecture Diagram
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Client Layer (React)
|
|
13
|
+
└── FileBrowser Component
|
|
14
|
+
└── HTTP API Calls
|
|
15
|
+
|
|
16
|
+
Server Layer (Node.js)
|
|
17
|
+
└── API Routes (Next.js/Express)
|
|
18
|
+
└── FileManager Service
|
|
19
|
+
├── LocalStorageModule → fs
|
|
20
|
+
└── GoogleDriveModule → Google Drive API
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Core Components
|
|
24
|
+
|
|
25
|
+
### FileManager
|
|
26
|
+
Main service providing unified API across storage providers.
|
|
27
|
+
- Location: `src/services/file-manager.ts`
|
|
28
|
+
- Methods: createDirectory, uploadFile, downloadFile, listDirectory, etc.
|
|
29
|
+
- Delegates operations to active storage module
|
|
30
|
+
|
|
31
|
+
### Storage Modules
|
|
32
|
+
Implement `StorageModule` interface with all file operations.
|
|
33
|
+
- LocalStorageModule: Direct filesystem access
|
|
34
|
+
- GoogleDriveModule: Google Drive API v3 with OAuth
|
|
35
|
+
|
|
36
|
+
### Naming System
|
|
37
|
+
Pattern-based file/folder name generation system.
|
|
38
|
+
- Location: `src/common/naming-utils.ts`, `src/types/naming.ts`
|
|
39
|
+
- Components: Schema definition, pattern parsing, variable substitution
|
|
40
|
+
- Functions: hazo_files_generate_file_name, hazo_files_generate_folder_name
|
|
41
|
+
- System variables: Date formats, file metadata, counter
|
|
42
|
+
|
|
43
|
+
### UI Components
|
|
44
|
+
React components for file management and configuration:
|
|
45
|
+
- **File Browser**: FileBrowser, FolderTree, FileList, FilePreview, PathBreadcrumb
|
|
46
|
+
- **Naming Configurator**: NamingRuleConfigurator, VariableList, PatternBuilder, PatternPreview
|
|
47
|
+
- **Dialogs**: Create/rename/delete/upload dialogs
|
|
48
|
+
- **Hooks**: useFileBrowser, useFileOperations, useNamingRule
|
|
49
|
+
|
|
50
|
+
## Storage Modules
|
|
51
|
+
|
|
52
|
+
### LocalStorageModule
|
|
53
|
+
**Path Mapping**: Virtual paths (`/docs/file.pdf`) map to filesystem (`{basePath}/docs/file.pdf`)
|
|
54
|
+
**Features**: Extension filtering, size limits, progress tracking
|
|
55
|
+
**Performance**: <10ms for most operations
|
|
56
|
+
|
|
57
|
+
### GoogleDriveModule
|
|
58
|
+
**Path Resolution**: Recursive API queries to resolve paths to Drive file IDs
|
|
59
|
+
**Authentication**: OAuth 2.0 with token refresh
|
|
60
|
+
**Performance**: 200-1000ms per operation (network latency)
|
|
61
|
+
|
|
62
|
+
## API Endpoints
|
|
63
|
+
|
|
64
|
+
### GET /api/files
|
|
65
|
+
- Query params: action (list|tree|exists|get), path, provider
|
|
66
|
+
- Returns: OperationResult<T>
|
|
67
|
+
|
|
68
|
+
### POST /api/files
|
|
69
|
+
- Body: action, path, provider, operation-specific params
|
|
70
|
+
- Returns: OperationResult<T>
|
|
71
|
+
|
|
72
|
+
### POST /api/files/upload
|
|
73
|
+
- Content-Type: multipart/form-data
|
|
74
|
+
- Fields: file, path, provider
|
|
75
|
+
- Returns: OperationResult<FileItem>
|
|
76
|
+
|
|
77
|
+
### GET /api/files/download
|
|
78
|
+
- Query: path, provider
|
|
79
|
+
- Returns: Binary file stream
|
|
80
|
+
|
|
81
|
+
## Database Schema
|
|
82
|
+
|
|
83
|
+
### Token Storage (PostgreSQL)
|
|
84
|
+
|
|
85
|
+
```sql
|
|
86
|
+
CREATE TABLE google_drive_tokens (
|
|
87
|
+
id SERIAL PRIMARY KEY,
|
|
88
|
+
user_id VARCHAR(255) UNIQUE NOT NULL,
|
|
89
|
+
access_token TEXT NOT NULL,
|
|
90
|
+
refresh_token TEXT NOT NULL,
|
|
91
|
+
expiry_date BIGINT,
|
|
92
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
93
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
CREATE INDEX idx_tokens_user_id ON google_drive_tokens(user_id);
|
|
97
|
+
|
|
98
|
+
GRANT ALL PRIVILEGES ON DATABASE your_database TO your_user;
|
|
99
|
+
GRANT ALL PRIVILEGES ON TABLE google_drive_tokens TO your_user;
|
|
100
|
+
GRANT USAGE, SELECT ON SEQUENCE google_drive_tokens_id_seq TO your_user;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Token Storage (SQLite)
|
|
104
|
+
|
|
105
|
+
```sql
|
|
106
|
+
CREATE TABLE google_drive_tokens (
|
|
107
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
108
|
+
user_id TEXT UNIQUE NOT NULL,
|
|
109
|
+
access_token TEXT NOT NULL,
|
|
110
|
+
refresh_token TEXT NOT NULL,
|
|
111
|
+
expiry_date INTEGER,
|
|
112
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
113
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
CREATE INDEX idx_tokens_user_id ON google_drive_tokens(user_id);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Security
|
|
120
|
+
|
|
121
|
+
### Authentication
|
|
122
|
+
- Local: Server-side access control required
|
|
123
|
+
- Google Drive: OAuth 2.0 with token refresh
|
|
124
|
+
|
|
125
|
+
### Input Validation
|
|
126
|
+
- Path validation prevents directory traversal
|
|
127
|
+
- Filename sanitization removes dangerous characters
|
|
128
|
+
- Extension whitelist via allowedExtensions
|
|
129
|
+
- Size limits via maxFileSize
|
|
130
|
+
|
|
131
|
+
### Best Practices
|
|
132
|
+
- Store tokens in database, never expose to client
|
|
133
|
+
- Use CSRF protection on POST endpoints
|
|
134
|
+
- Implement rate limiting
|
|
135
|
+
- Validate all user inputs
|
|
136
|
+
|
|
137
|
+
## Performance
|
|
138
|
+
|
|
139
|
+
### Benchmarks
|
|
140
|
+
|
|
141
|
+
**Local Storage**:
|
|
142
|
+
- Upload 1MB: 5-10ms
|
|
143
|
+
- Download 1MB: 3-8ms
|
|
144
|
+
- List 100 files: 2-5ms
|
|
145
|
+
|
|
146
|
+
**Google Drive**:
|
|
147
|
+
- Upload 1MB: 500-1000ms
|
|
148
|
+
- Download 1MB: 300-700ms
|
|
149
|
+
- List 100 files: 400-800ms
|
|
150
|
+
|
|
151
|
+
### Optimization Strategies
|
|
152
|
+
1. Path caching for Google Drive
|
|
153
|
+
2. Batch API requests
|
|
154
|
+
3. Virtual scrolling for large lists
|
|
155
|
+
4. React Query for client-side caching
|
|
156
|
+
|
|
157
|
+
## Error Handling
|
|
158
|
+
|
|
159
|
+
### Error Types
|
|
160
|
+
- FileNotFoundError, DirectoryNotFoundError
|
|
161
|
+
- FileExistsError, DirectoryExistsError
|
|
162
|
+
- InvalidPathError, FileTooLargeError
|
|
163
|
+
- InvalidExtensionError, AuthenticationError
|
|
164
|
+
|
|
165
|
+
### Error Flow
|
|
166
|
+
```
|
|
167
|
+
Module → Catch error → Return OperationResult with error
|
|
168
|
+
API → Return OperationResult as JSON
|
|
169
|
+
Client → Check result.success, handle error
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Naming System Architecture
|
|
173
|
+
|
|
174
|
+
### Pattern Structure
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
NamingRuleSchema
|
|
178
|
+
├── version: number
|
|
179
|
+
├── filePattern: PatternSegment[]
|
|
180
|
+
│ ├── { id, type: 'variable', value: 'client_id' }
|
|
181
|
+
│ ├── { id, type: 'literal', value: '_' }
|
|
182
|
+
│ └── { id, type: 'variable', value: 'YYYY-MM-DD' }
|
|
183
|
+
├── folderPattern: PatternSegment[]
|
|
184
|
+
└── metadata: { name?, description?, createdAt?, updatedAt? }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Name Generation Flow
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
User provides:
|
|
191
|
+
- NamingRuleSchema (pattern definition)
|
|
192
|
+
- Variable values (user-defined variables)
|
|
193
|
+
- Options (date, counter, etc.)
|
|
194
|
+
|
|
195
|
+
↓
|
|
196
|
+
|
|
197
|
+
Pattern segments iteration:
|
|
198
|
+
For each segment:
|
|
199
|
+
- If literal → Use value directly
|
|
200
|
+
- If variable → Lookup value:
|
|
201
|
+
- Check date variables (YYYY, MM, DD, etc.)
|
|
202
|
+
- Check file metadata (original_name, extension)
|
|
203
|
+
- Check counter variable
|
|
204
|
+
- Check user variables
|
|
205
|
+
- If missing → Return error
|
|
206
|
+
|
|
207
|
+
↓
|
|
208
|
+
|
|
209
|
+
Post-processing:
|
|
210
|
+
- Join all segments
|
|
211
|
+
- Sanitize filename (remove unsafe chars)
|
|
212
|
+
- Preserve extension (if file pattern)
|
|
213
|
+
|
|
214
|
+
↓
|
|
215
|
+
|
|
216
|
+
Return GeneratedNameResult:
|
|
217
|
+
{ success: true, name: "ACME_2024-12-09_001.pdf" }
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Variable Resolution Order
|
|
221
|
+
|
|
222
|
+
1. **Date variables**: Checked first using formatDateToken()
|
|
223
|
+
2. **File metadata**: From original filename (if provided)
|
|
224
|
+
3. **Counter**: Formatted with zero padding
|
|
225
|
+
4. **User variables**: From provided variables object
|
|
226
|
+
5. **Error**: If none match, return error result
|
|
227
|
+
|
|
228
|
+
### Configurator State Management
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
useNamingRule Hook
|
|
232
|
+
├── State:
|
|
233
|
+
│ ├── filePattern: PatternSegment[]
|
|
234
|
+
│ ├── folderPattern: PatternSegment[]
|
|
235
|
+
│ ├── history: NamingRuleHistoryEntry[]
|
|
236
|
+
│ └── historyIndex: number
|
|
237
|
+
│
|
|
238
|
+
├── Actions:
|
|
239
|
+
│ ├── Pattern manipulation (add, remove, update, reorder, clear)
|
|
240
|
+
│ ├── Undo/Redo (Ctrl+Z, Ctrl+Y)
|
|
241
|
+
│ └── Schema import/export
|
|
242
|
+
│
|
|
243
|
+
└── Effects:
|
|
244
|
+
├── onChange callback on pattern change
|
|
245
|
+
├── Keyboard event listeners
|
|
246
|
+
└── History recording
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Drag-and-Drop System
|
|
250
|
+
|
|
251
|
+
**Architecture**: Single top-level DndContext pattern
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
NamingRuleConfigurator (DndContext)
|
|
255
|
+
├── Sensors:
|
|
256
|
+
│ └── PointerSensor (8px activation distance)
|
|
257
|
+
│
|
|
258
|
+
├── Collision Detection: closestCenter
|
|
259
|
+
│
|
|
260
|
+
├── Event Handlers:
|
|
261
|
+
│ ├── onDragStart → setActiveVariable (for DragOverlay)
|
|
262
|
+
│ └── onDragEnd → handleDragEnd:
|
|
263
|
+
│ ├── Case 1: New variable drop (draggable-* ID)
|
|
264
|
+
│ │ ├── Detect drop target (file-pattern-drop / folder-pattern-drop)
|
|
265
|
+
│ │ └── Call addToFilePattern / addToFolderPattern
|
|
266
|
+
│ └── Case 2: Segment reordering (segment ID)
|
|
267
|
+
│ ├── Find indices in filePattern / folderPattern
|
|
268
|
+
│ └── Call reorderFilePattern / reorderFolderPattern
|
|
269
|
+
│
|
|
270
|
+
├── DragOverlay:
|
|
271
|
+
│ └── Shows activeVariable during drag
|
|
272
|
+
│
|
|
273
|
+
├── Children:
|
|
274
|
+
├── VariableList
|
|
275
|
+
│ └── DraggableVariable (useDraggable)
|
|
276
|
+
│ └── Data: { type: 'variable', variable: NamingVariable }
|
|
277
|
+
│
|
|
278
|
+
└── PatternBuilder (NO DndContext - CRITICAL)
|
|
279
|
+
├── SortableContext (for segment reordering)
|
|
280
|
+
├── useDroppable (for drop zone detection)
|
|
281
|
+
└── PatternSegmentItem (useSortable)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Critical Design Decision**: PatternBuilder does NOT have its own DndContext. It relies entirely on the parent NamingRuleConfigurator's DndContext. This is essential because:
|
|
285
|
+
|
|
286
|
+
1. Nested DndContext blocks drag events from parent
|
|
287
|
+
2. @dnd-kit prevents event bubbling between contexts
|
|
288
|
+
3. All drag logic must be in a single handleDragEnd handler
|
|
289
|
+
|
|
290
|
+
**Common Mistake**: Adding DndContext to child components causes drag-and-drop to break. Always use SortableContext and useDroppable/useSortable hooks in children, reserve DndContext for top-level component only.
|
|
291
|
+
|
|
292
|
+
### System Variable Evaluation
|
|
293
|
+
|
|
294
|
+
**Date Variables** (evaluated at generation time):
|
|
295
|
+
- Uses provided `date` option or `new Date()`
|
|
296
|
+
- Formatted via `formatDateToken()` with switch statement
|
|
297
|
+
- Supports 12+ date formats
|
|
298
|
+
|
|
299
|
+
**File Variables** (from original filename):
|
|
300
|
+
- `original_name`: Extracted via getNameWithoutExtension()
|
|
301
|
+
- `extension`: Extracted via getExtension() (includes dot)
|
|
302
|
+
- `ext`: Extension without dot
|
|
303
|
+
|
|
304
|
+
**Counter Variable**:
|
|
305
|
+
- Provided via `counterValue` option (default: 1)
|
|
306
|
+
- Formatted with `counterDigits` padding (default: 3)
|
|
307
|
+
- Example: 1 → "001", 42 → "042"
|
|
308
|
+
|
|
309
|
+
### Performance Characteristics
|
|
310
|
+
|
|
311
|
+
**Name Generation**:
|
|
312
|
+
- Time complexity: O(n) where n = number of segments
|
|
313
|
+
- Memory: O(n) for segment array and result string
|
|
314
|
+
- No I/O operations, pure computation
|
|
315
|
+
- Typical execution: <1ms for patterns with <50 segments
|
|
316
|
+
|
|
317
|
+
**Configurator UI**:
|
|
318
|
+
- Pattern updates: Re-renders affected components only
|
|
319
|
+
- History operations: O(1) for undo/redo
|
|
320
|
+
- Drag operations: Handled by @dnd-kit (optimized)
|
|
321
|
+
- Preview generation: Runs on every pattern change (debounce recommended for production)
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
**Version**: 1.0.0
|