appydave-tools 0.21.2 → 0.22.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/bin/dam +137 -0
  4. data/docs/README.md +187 -90
  5. data/docs/architecture/dam/dam-cli-enhancements.md +642 -0
  6. data/docs/architecture/dam/dam-cli-implementation-guide.md +1041 -0
  7. data/docs/architecture/dam/dam-data-model.md +466 -0
  8. data/docs/architecture/dam/dam-visualization-requirements.md +641 -0
  9. data/docs/architecture/dam/implementation-roadmap.md +328 -0
  10. data/docs/architecture/dam/jan-collaboration-guide.md +309 -0
  11. data/lib/appydave/tools/dam/s3_operations.rb +57 -5
  12. data/lib/appydave/tools/dam/s3_scanner.rb +139 -0
  13. data/lib/appydave/tools/version.rb +1 -1
  14. data/lib/appydave/tools.rb +1 -0
  15. data/package.json +1 -1
  16. metadata +37 -32
  17. data/docs/development/CODEX-recommendations.md +0 -258
  18. data/docs/development/README.md +0 -100
  19. /data/docs/{development/pattern-comparison.md → architecture/cli/cli-pattern-comparison.md} +0 -0
  20. /data/docs/{development/cli-architecture-patterns.md → architecture/cli/cli-patterns.md} +0 -0
  21. /data/docs/{project-brand-systems-analysis.md → architecture/configuration/configuration-systems.md} +0 -0
  22. /data/docs/{dam → architecture/dam}/dam-vision.md +0 -0
  23. /data/docs/{dam/prd-client-sharing.md → architecture/dam/design-decisions/002-client-sharing.md} +0 -0
  24. /data/docs/{dam/prd-git-integration.md → architecture/dam/design-decisions/003-git-integration.md} +0 -0
  25. /data/docs/{prd-unified-brands-configuration.md → architecture/design-decisions/001-unified-brands-config.md} +0 -0
  26. /data/docs/{dam/session-summary-2025-11-09.md → architecture/design-decisions/session-2025-11-09.md} +0 -0
  27. /data/docs/{configuration/README.md → guides/configuration-setup.md} +0 -0
  28. /data/docs/{dam → guides/platforms}/windows/README.md +0 -0
  29. /data/docs/{dam → guides/platforms}/windows/dam-testing-plan-windows-powershell.md +0 -0
  30. /data/docs/{dam → guides/platforms}/windows/installation.md +0 -0
  31. /data/docs/{tools → guides/tools}/bank-reconciliation.md +0 -0
  32. /data/docs/{tools → guides/tools}/cli-actions.md +0 -0
  33. /data/docs/{tools → guides/tools}/configuration.md +0 -0
  34. /data/docs/{dam → guides/tools/dam}/dam-testing-plan.md +0 -0
  35. /data/docs/{dam/usage.md → guides/tools/dam/dam-usage.md} +0 -0
  36. /data/docs/{tools → guides/tools}/gpt-context.md +0 -0
  37. /data/docs/{tools → guides/tools}/index.md +0 -0
  38. /data/docs/{tools → guides/tools}/move-images.md +0 -0
  39. /data/docs/{tools → guides/tools}/name-manager.md +0 -0
  40. /data/docs/{tools → guides/tools}/prompt-tools.md +0 -0
  41. /data/docs/{tools → guides/tools}/subtitle-processor.md +0 -0
  42. /data/docs/{tools → guides/tools}/youtube-automation.md +0 -0
  43. /data/docs/{tools → guides/tools}/youtube-manager.md +0 -0
  44. /data/docs/{configuration → templates}/.env.example +0 -0
  45. /data/docs/{configuration → templates}/channels.example.json +0 -0
  46. /data/docs/{configuration → templates}/settings.example.json +0 -0
@@ -0,0 +1,466 @@
1
+ # DAM Data Model
2
+
3
+ **Digital Asset Management - Entity Schema and Data Sources**
4
+
5
+ This document defines the complete data model for the DAM (Digital Asset Management) system, including all entities, their relationships, data sources, and how state is inferred from the filesystem and configuration.
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ The DAM system manages video projects across multiple brands, team members, and storage locations. The data model is **inferred from filesystem structure and configuration** rather than stored in a database, making it git-friendly and deployment-agnostic.
12
+
13
+ **Key Principle:** All state is calculated at runtime from:
14
+ - Filesystem structure (project folders, file presence)
15
+ - Configuration files (`brands.json`, `settings.json`, `channels.json`)
16
+ - Generated manifests (`projects.json` per brand)
17
+
18
+ ---
19
+
20
+ ## Entity Hierarchy
21
+
22
+ ```
23
+ System (root)
24
+ ├── Brands (6 brands: appydave, aitldr, voz, kiros, beauty-and-joy, supportsignal)
25
+ │ ├── Projects (varies by brand)
26
+ │ │ ├── Storage Locations (local, S3, SSD)
27
+ │ │ │ └── Files (recordings, assets, s3-staging, etc.)
28
+ │ │ └── Metadata (type, structure, disk usage)
29
+ │ └── Team Members (brand-specific access)
30
+ └── Users (cross-brand: david, jan, joy, vasilios, ronnie)
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Core Entities
36
+
37
+ ### 1. Brand
38
+
39
+ **Definition:** A content brand or client with its own video projects, team, and storage configuration.
40
+
41
+ **Data Source:** `~/.config/appydave/brands.json`
42
+
43
+ **Schema:**
44
+ ```json
45
+ {
46
+ "name": "AppyDave",
47
+ "shortcut": "ad",
48
+ "type": "owned|client",
49
+ "youtube_channels": ["appydave"],
50
+ "team": ["david", "jan"],
51
+ "git_remote": "git@github.com:appydave-video-projects/v-appydave.git",
52
+ "locations": {
53
+ "video_projects": "/Users/davidcruwys/dev/video-projects/v-appydave",
54
+ "ssd_backup": "/Volumes/T7/youtube-PUBLISHED/appydave"
55
+ },
56
+ "aws": {
57
+ "profile": "david-appydave",
58
+ "region": "ap-southeast-1",
59
+ "s3_bucket": "appydave-video-projects",
60
+ "s3_prefix": "staging/v-appydave/"
61
+ },
62
+ "settings": {
63
+ "s3_cleanup_days": 90
64
+ }
65
+ }
66
+ ```
67
+
68
+ **Properties:**
69
+ | Property | Type | Description | Example |
70
+ |----------|------|-------------|---------|
71
+ | `name` | string | Display name | `"AppyDave"` |
72
+ | `shortcut` | string | Short identifier | `"ad"` |
73
+ | `type` | enum | `"owned"` or `"client"` | `"owned"` |
74
+ | `youtube_channels` | array | YouTube channel codes | `["appydave"]` |
75
+ | `team` | array | User keys with access | `["david", "jan"]` |
76
+ | `git_remote` | string | Git repository URL | `"git@github.com:..."` |
77
+ | `locations.video_projects` | string | Local project root path | `"/Users/.../v-appydave"` |
78
+ | `locations.ssd_backup` | string | SSD backup base path | `"/Volumes/T7/..."` |
79
+ | `aws.profile` | string | AWS CLI profile name | `"david-appydave"` |
80
+ | `aws.s3_bucket` | string | S3 bucket name | `"appydave-video-projects"` |
81
+ | `aws.s3_prefix` | string | S3 key prefix | `"staging/v-appydave/"` |
82
+ | `settings.s3_cleanup_days` | number | S3 retention policy | `90` |
83
+
84
+ **Current Brands:**
85
+ - `appydave` (owned, David + Jan)
86
+ - `aitldr` (owned, David + Jan)
87
+ - `voz` (client, Vasilios)
88
+ - `beauty-and-joy` (owned, Joy + David)
89
+ - `kiros` (client, Ronnie)
90
+ - `supportsignal` (client, Ronnie)
91
+
92
+ ---
93
+
94
+ ### 2. User
95
+
96
+ **Definition:** A person with access to one or more brands.
97
+
98
+ **Data Source:** `~/.config/appydave/brands.json` (users section)
99
+
100
+ **Schema:**
101
+ ```json
102
+ {
103
+ "name": "David Cruwys",
104
+ "email": "david@appydave.com",
105
+ "role": "owner|team_member|client",
106
+ "default_aws_profile": "david-appydave"
107
+ }
108
+ ```
109
+
110
+ **Properties:**
111
+ | Property | Type | Description | Values |
112
+ |----------|------|-------------|--------|
113
+ | `name` | string | Full name | `"David Cruwys"` |
114
+ | `email` | string | Email address | `"david@appydave.com"` |
115
+ | `role` | enum | User type | `"owner"`, `"team_member"`, `"client"` |
116
+ | `default_aws_profile` | string | Default AWS profile | `"david-appydave"` |
117
+
118
+ **Current Users:**
119
+ - `david` - Owner (all brands)
120
+ - `jan` - Team member (appydave, aitldr)
121
+ - `joy` - Team member (beauty-and-joy)
122
+ - `vasilios` - Client (voz)
123
+ - `ronnie` - Client (kiros, supportsignal)
124
+
125
+ ---
126
+
127
+ ### 3. Project
128
+
129
+ **Definition:** A video project belonging to a brand, with content spread across local, S3, and SSD storage.
130
+
131
+ **Data Source:**
132
+ - Primary: `{brand}/projects.json` (generated manifest)
133
+ - Filesystem: Project folders in `{brand}/`, `{brand}/archived/`, SSD ranges
134
+
135
+ **Schema:**
136
+ ```json
137
+ {
138
+ "id": "b64-bmad-claude-sdk",
139
+ "type": "flivideo|storyline|general",
140
+ "storage": {
141
+ "local": {
142
+ "exists": true,
143
+ "structure": "flat|archived|null",
144
+ "has_heavy_files": false,
145
+ "has_light_files": true
146
+ },
147
+ "s3": {
148
+ "exists": true
149
+ },
150
+ "ssd": {
151
+ "exists": false,
152
+ "path": null
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ **Properties:**
159
+ | Property | Type | Description | Inferred From |
160
+ |----------|------|-------------|---------------|
161
+ | `id` | string | Project folder name | Filesystem |
162
+ | `type` | enum | Project workflow type | Folder structure + naming |
163
+ | `storage.local.exists` | boolean | Exists in local filesystem | `Dir.exist?` |
164
+ | `storage.local.structure` | enum | Storage structure type | Path location |
165
+ | `storage.local.has_heavy_files` | boolean | Contains video files | `*.{mp4,mov,avi,mkv,webm}` |
166
+ | `storage.local.has_light_files` | boolean | Contains text/assets | `*.{srt,jpg,png,md,json}` |
167
+ | `storage.s3.exists` | boolean | Has `s3-staging` folder | `Dir.exist?(s3-staging)` |
168
+ | `storage.ssd.exists` | boolean | Found on SSD | SSD filesystem scan |
169
+ | `storage.ssd.path` | string | SSD relative path | Project ID (or range path) |
170
+
171
+ **Project Types:**
172
+ | Type | Detection Logic | Example |
173
+ |------|-----------------|---------|
174
+ | `flivideo` | Pattern: `[a-z]\d{2}-name` | `b64-bmad-claude-sdk` |
175
+ | `storyline` | Has `data/storyline.json` | `boy-baker` |
176
+ | `general` | Everything else | `-01-25` |
177
+
178
+ **Local Structure Types:**
179
+ | Structure | Location | Purpose |
180
+ |-----------|----------|---------|
181
+ | `flat` | `{brand}/{project-id}/` | Active projects |
182
+ | `archived` | `{brand}/archived/{range}/{project-id}/` | Restored/archived projects |
183
+ | `null` | Not on local | SSD-only or missing |
184
+
185
+ ---
186
+
187
+ ### 4. Storage Location
188
+
189
+ **Definition:** A physical or cloud location where project files reside.
190
+
191
+ **Three Storage Types:**
192
+
193
+ #### A. Local Storage
194
+ - **Path:** `{brand}/` or `{brand}/archived/{range}/`
195
+ - **Purpose:** Active development, recording, editing
196
+ - **Characteristics:**
197
+ - Git repository (light files only)
198
+ - Heavy files gitignored
199
+ - Structured folders (recordings/, assets/, s3-staging/, etc.)
200
+
201
+ #### B. S3 Staging Storage
202
+ - **Path (virtual):** `s3://{bucket}/{prefix}/{project-id}/`
203
+ - **Detection:** Presence of `{project-local}/s3-staging/` folder
204
+ - **Purpose:** Short-term collaboration (90 days)
205
+ - **Characteristics:**
206
+ - Transient (auto-cleanup after 90 days)
207
+ - Enables David ↔ Jan file exchange
208
+ - Shareable links for clients
209
+
210
+ #### C. SSD Backup Storage
211
+ - **Path:** `/Volumes/T7/{brand}/{range}/{project-id}/`
212
+ - **Purpose:** Long-term archive
213
+ - **Characteristics:**
214
+ - Cold storage (external drive)
215
+ - Organized in range folders (`b00-b49`, `b50-b99`)
216
+ - Not always mounted/available
217
+
218
+ **SSD Availability Detection:**
219
+ ```ruby
220
+ ssd_available = Dir.exist?(brand_info.locations.ssd_backup)
221
+ ```
222
+
223
+ ---
224
+
225
+ ### 5. File Categories
226
+
227
+ **Definition:** Files within a project, categorized by type and gitignore status.
228
+
229
+ **Heavy Files** (gitignored):
230
+ - `*.mp4`, `*.mov`, `*.avi`, `*.mkv`, `*.webm`
231
+ - Detection: `Dir.glob(File.join(dir, '*.{mp4,mov,...}'))`
232
+
233
+ **Light Files** (git-tracked):
234
+ - `*.srt`, `*.vtt` (subtitles)
235
+ - `*.jpg`, `*.png` (thumbnails, assets)
236
+ - `*.md`, `*.txt` (documentation)
237
+ - `*.json`, `*.yml` (metadata)
238
+ - Detection: `Dir.glob(File.join(dir, '**/*.{srt,vtt,...}'))`
239
+
240
+ ---
241
+
242
+ ## Data Sources Hierarchy
243
+
244
+ ### Configuration Files (Read Once, Cached)
245
+
246
+ ```
247
+ ~/.config/appydave/
248
+ ├── brands.json # Brand definitions, team, AWS config
249
+ ├── settings.json # Global paths (video-projects-root, etc.)
250
+ ├── channels.json # YouTube channel metadata (optional)
251
+ └── youtube-automation.json # Automation workflows (out of scope)
252
+ ```
253
+
254
+ ### Generated Manifests (Regenerated on Demand)
255
+
256
+ #### Brand-Level Manifests
257
+
258
+ ```
259
+ {video-projects-root}/
260
+ ├── v-appydave/
261
+ │ └── projects.json # Brand manifest (auto-generated)
262
+ ├── v-aitldr/
263
+ │ └── projects.json
264
+ └── v-voz/
265
+ └── projects.json
266
+ ```
267
+
268
+ **Command:** `dam manifest <brand>` or `dam manifest all`
269
+
270
+ **What It Contains:**
271
+ - All projects for the brand
272
+ - Storage locations (local/S3/SSD)
273
+ - Disk usage totals
274
+ - Project types
275
+
276
+ **Regeneration Triggers:**
277
+ - Explicit: `dam manifest <brand>` command
278
+ - Explicit: `dam refresh <brand>` (manifest + S3 scan)
279
+ - Implicit: None (must be manually triggered)
280
+
281
+ #### Project-Level Manifests (Optional/Transient)
282
+
283
+ ```
284
+ {video-projects-root}/v-appydave/
285
+ ├── b64-bmad-claude-sdk/
286
+ │ ├── .project-manifest.json # Project manifest (optional, transient)
287
+ │ ├── recordings/
288
+ │ ├── assets/
289
+ │ └── s3-staging/
290
+ ├── b65-guy-monroe-marketing-plan/
291
+ │ ├── .project-manifest.json # Project manifest (optional, transient)
292
+ │ └── ...
293
+ └── b70-ito.ai-doubled-productivity/
294
+ ├── .project-manifest.json # Project manifest (optional, transient)
295
+ └── ...
296
+ ```
297
+
298
+ **Command:** `dam project-manifest <brand> <project>`
299
+
300
+ **What It Contains:**
301
+ - Detailed file tree (directory structure)
302
+ - File counts per directory
303
+ - Subdirectory breakdown (e.g., `recordings/recordings-bmad-v6/`)
304
+ - Heavy/light file summaries
305
+
306
+ **Characteristics:**
307
+ - **Transient** - Not required, regenerate on demand
308
+ - **Git-ignored** - Too volatile to commit (add to `.gitignore`)
309
+ - **Optional** - Dashboard works without it (falls back to brand manifest booleans)
310
+ - **On-demand** - Only generate when needed for detailed project view
311
+
312
+ **Regeneration Triggers:**
313
+ - Explicit: `dam project-manifest <brand> <project>` command
314
+ - Explicit: Dashboard button (future - local dev only)
315
+ - Implicit: None
316
+
317
+ ---
318
+
319
+ ## State Inference Rules
320
+
321
+ ### Project Existence
322
+
323
+ | Condition | Result |
324
+ |-----------|--------|
325
+ | `Dir.exist?("{brand}/{id}")` | `storage.local.exists = true, structure = "flat"` |
326
+ | `Dir.exist?("{brand}/archived/{range}/{id}")` | `storage.local.exists = true, structure = "archived"` |
327
+ | Neither exists | `storage.local.exists = false, structure = null` |
328
+
329
+ ### S3 Staging Status
330
+
331
+ | Condition | Result |
332
+ |-----------|--------|
333
+ | `Dir.exist?("{project}/s3-staging")` | `storage.s3.exists = true` |
334
+ | Otherwise | `storage.s3.exists = false` |
335
+
336
+ **Note:** This detects the **local marker folder**, not actual S3 contents. The `s3-staging/` folder is used to stage files before S3 upload.
337
+
338
+ ### SSD Backup Status
339
+
340
+ **Search Order:**
341
+ 1. Flat: `{ssd_base}/{project-id}/`
342
+ 2. Calculated range: `{ssd_base}/{range}/{project-id}/`
343
+ 3. Exhaustive search: All range folders in `{ssd_base}/*/`
344
+
345
+ **Result:** `storage.ssd.exists = true` if found anywhere
346
+
347
+ ### Sync State (Inferred)
348
+
349
+ | Local | S3 | SSD | Interpretation |
350
+ |-------|----|----|----------------|
351
+ | ✅ | ✅ | ❌ | **Active collaboration** - David & Jan working |
352
+ | ✅ | ❌ | ❌ | **Local only** - Not shared yet |
353
+ | ❌ | ✅ | ❌ | **Remote only** - Need to download |
354
+ | ✅ | ❌ | ✅ | **Archived** - Published, local for reference |
355
+ | ❌ | ❌ | ✅ | **Cold storage** - Historical archive |
356
+ | ✅ | ✅ | ✅ | **Fully backed up** - All locations |
357
+
358
+ ---
359
+
360
+ ## Disk Usage Calculation
361
+
362
+ **Calculated Fields in Manifest:**
363
+ ```json
364
+ {
365
+ "disk_usage": {
366
+ "local": {
367
+ "total_bytes": 12399975489,
368
+ "total_mb": 11825.54,
369
+ "total_gb": 11.55
370
+ },
371
+ "ssd": {
372
+ "total_bytes": 429749225514,
373
+ "total_mb": 409840.8,
374
+ "total_gb": 400.24
375
+ }
376
+ }
377
+ }
378
+ ```
379
+
380
+ **Calculation Method:**
381
+ - Walk entire directory tree
382
+ - Sum `File.size(file)` for all files
383
+ - Convert bytes → MB, GB
384
+ - Performed at manifest generation time (not real-time)
385
+
386
+ ---
387
+
388
+ ## Relationships
389
+
390
+ ### Brand → Projects (1:N)
391
+ - One brand has many projects
392
+ - Projects identified by folder name
393
+ - Manifest lists all projects for brand
394
+
395
+ ### Brand → Users (M:N)
396
+ - Brands have `team` array
397
+ - Users can belong to multiple brands
398
+ - Example: David is on all brands, Jan is on appydave + aitldr
399
+
400
+ ### Project → Storage Locations (1:3)
401
+ - Each project can exist in:
402
+ - Local (0 or 1)
403
+ - S3 (0 or 1)
404
+ - SSD (0 or 1)
405
+ - Valid combinations: Any subset of {local, s3, ssd}
406
+
407
+ ### User → AWS Profile (N:1)
408
+ - Each user has `default_aws_profile`
409
+ - Multiple users can share same AWS profile (e.g., Jan uses david-appydave)
410
+ - AWS profiles defined in `~/.aws/credentials` (outside DAM scope)
411
+
412
+ ---
413
+
414
+ ## Data Flow
415
+
416
+ ### Manifest Generation
417
+ ```
418
+ 1. Load brands.json (configuration)
419
+ 2. Scan local filesystem ({brand}/, {brand}/archived/*/)
420
+ 3. Scan SSD filesystem (if available)
421
+ 4. Detect S3 staging (local folder presence)
422
+ 5. Calculate disk usage (recursive file size sum)
423
+ 6. Generate projects.json (per brand)
424
+ ```
425
+
426
+ ### S3 Sync Detection
427
+ ```
428
+ 1. Check for local s3-staging folder
429
+ 2. List S3 bucket contents (AWS API call)
430
+ 3. Compare MD5 hashes or timestamps
431
+ 4. Determine sync status (in-sync, needs-upload, needs-download)
432
+ ```
433
+
434
+ **Note:** MD5 comparison is used by S3 sync tools but not currently exposed in the manifest.
435
+
436
+ ---
437
+
438
+ ## Missing / Out of Scope
439
+
440
+ **What's NOT in the current data model:**
441
+
442
+ 1. **S3 actual contents** - Manifest only tracks local `s3-staging/` folder existence
443
+ 2. **File-level metadata** - No per-file tracking (size, MD5, timestamps)
444
+ 3. **FliVideo chapter structure** - Not exposed at manifest level
445
+ 4. **Storyline scripts** - Not parsed into manifest
446
+ 5. **Transcripts** - Not indexed (though important for workflows)
447
+ 6. **YouTube publish status** - No link between project and published video
448
+ 7. **Project state machine** - No "recording", "editing", "published" status
449
+ 8. **Team permissions** - No granular access control (inferred from brand team list)
450
+
451
+ ---
452
+
453
+ ## Future Enhancements
454
+
455
+ **Potential additions to data model:**
456
+
457
+ 1. **S3 actual sync status** - Query AWS API for real S3 contents, not just local folder
458
+ 2. **File manifest** - Per-project file listing with sizes, MD5s, timestamps
459
+ 3. **Transcript index** - Parse and index all `.srt` files
460
+ 4. **Chapter structure** - FliVideo recording organization
461
+ 5. **Project metadata** - Title, description, recording date
462
+ 6. **State tracking** - Workflow status (planned → recording → editing → published)
463
+
464
+ ---
465
+
466
+ **Last updated**: 2025-11-18