appydave-tools 0.16.0 → 0.17.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/AGENTS.md +22 -0
- data/CHANGELOG.md +12 -0
- data/CLAUDE.md +206 -51
- data/README.md +144 -11
- data/bin/archive_project.rb +249 -0
- data/bin/configuration.rb +21 -1
- data/bin/generate_manifest.rb +357 -0
- data/bin/sync_from_ssd.rb +236 -0
- data/bin/vat +623 -0
- data/docs/README.md +169 -0
- data/docs/configuration/.env.example +19 -0
- data/docs/configuration/README.md +394 -0
- data/docs/configuration/channels.example.json +26 -0
- data/docs/configuration/settings.example.json +6 -0
- data/docs/development/CODEX-recommendations.md +123 -0
- data/docs/development/README.md +100 -0
- data/docs/development/cli-architecture-patterns.md +1604 -0
- data/docs/development/pattern-comparison.md +284 -0
- data/docs/prd-unified-brands-configuration.md +792 -0
- data/docs/project-brand-systems-analysis.md +934 -0
- data/docs/vat/dam-vision.md +123 -0
- data/docs/vat/session-summary-2025-11-09.md +297 -0
- data/docs/vat/usage.md +508 -0
- data/docs/vat/vat-testing-plan.md +801 -0
- data/lib/appydave/tools/configuration/models/brands_config.rb +238 -0
- data/lib/appydave/tools/configuration/models/config_base.rb +7 -0
- data/lib/appydave/tools/configuration/models/settings_config.rb +4 -0
- data/lib/appydave/tools/vat/config.rb +153 -0
- data/lib/appydave/tools/vat/config_loader.rb +91 -0
- data/lib/appydave/tools/vat/manifest_generator.rb +239 -0
- data/lib/appydave/tools/vat/project_listing.rb +198 -0
- data/lib/appydave/tools/vat/project_resolver.rb +132 -0
- data/lib/appydave/tools/vat/s3_operations.rb +560 -0
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools.rb +9 -1
- data/package.json +1 -1
- metadata +57 -3
- data/docs/dam/overview.md +0 -28
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
# PRD: Unified Brands Configuration System
|
|
2
|
+
|
|
3
|
+
**Status**: Draft for Review
|
|
4
|
+
**Author**: Claude (with David Cruwys)
|
|
5
|
+
**Date**: 2025-11-09
|
|
6
|
+
**Version**: 1.0
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Executive Summary
|
|
11
|
+
|
|
12
|
+
Create a unified `brands.json` configuration system that consolidates video project brand management, integrating with existing `channels.json` (YouTube) and `settings.json` (global) configs. This eliminates the fragmented `.video-tools.env` files and provides a centralized, team-friendly configuration approach for multi-brand video project collaboration.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Problem Statement
|
|
17
|
+
|
|
18
|
+
### Current Issues
|
|
19
|
+
|
|
20
|
+
1. **Fragmented Configuration**: Three disconnected systems
|
|
21
|
+
- `settings.json` (global paths)
|
|
22
|
+
- `channels.json` (YouTube metadata) - only 2/7 brands configured
|
|
23
|
+
- `.video-tools.env` (per-brand secrets) - only 1/7 brands has this file
|
|
24
|
+
|
|
25
|
+
2. **Missing Multi-User Support**:
|
|
26
|
+
- Only David's credentials configured
|
|
27
|
+
- No structure for Jan, Vasilios, Ronnie to use their own AWS credentials
|
|
28
|
+
- No clear team access model
|
|
29
|
+
|
|
30
|
+
3. **Code Bugs**:
|
|
31
|
+
- `ConfigLoader.load()` doesn't exist (should be `load_from_repo()`)
|
|
32
|
+
- AWS CLI dependency instead of AWS SDK gem
|
|
33
|
+
- Hardcoded brand shortcuts in `Config.expand_brand()`
|
|
34
|
+
|
|
35
|
+
4. **Incomplete Coverage**:
|
|
36
|
+
- 7 brand directories exist
|
|
37
|
+
- 2 configured in `channels.json`
|
|
38
|
+
- 1 has `.video-tools.env`
|
|
39
|
+
- Brands: appydave, voz, aitldr, kiros, beauty-and-joy, supportsignal
|
|
40
|
+
|
|
41
|
+
5. **Relationship Ambiguity**:
|
|
42
|
+
- Brands vs. YouTube channels not clearly defined
|
|
43
|
+
- Some brands are owned (appydave, aitldr, beauty-and-joy)
|
|
44
|
+
- Some brands are client work (voz, kiros, supportsignal)
|
|
45
|
+
- Not all brands publish to YouTube
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Goals
|
|
50
|
+
|
|
51
|
+
### Primary Goals
|
|
52
|
+
|
|
53
|
+
1. **Unified Configuration**: Single source of truth for brand metadata via `brands.json`
|
|
54
|
+
2. **Multi-User Support**: Enable David, Jan, Vasilios, Ronnie to use their own AWS credentials
|
|
55
|
+
3. **Security**: Separate secrets (AWS credentials) from metadata (brand config)
|
|
56
|
+
4. **Consistency**: All 7 brands properly configured and accessible
|
|
57
|
+
5. **Tool Integration**: `ad_config` (alias to `bin/configuration.rb`) manages all configs
|
|
58
|
+
|
|
59
|
+
### Secondary Goals
|
|
60
|
+
|
|
61
|
+
1. Migrate from AWS CLI shell commands to AWS SDK gem
|
|
62
|
+
2. Fix `ConfigLoader` bugs
|
|
63
|
+
3. Remove `.video-tools.env` dependency
|
|
64
|
+
4. Link brands ↔ YouTube channels where applicable
|
|
65
|
+
|
|
66
|
+
### Non-Goals
|
|
67
|
+
|
|
68
|
+
1. **No business logic on brand types**: `owned` vs `client` is metadata only
|
|
69
|
+
2. **No client isolation**: Single S3 bucket with prefixes (current architecture)
|
|
70
|
+
3. **No required YouTube channels**: Brands can exist without YouTube channels
|
|
71
|
+
4. **No complex permissions**: Use AWS IAM for access control
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## User Stories
|
|
76
|
+
|
|
77
|
+
### As David (Owner)
|
|
78
|
+
- I want to configure all 7 brands in one place
|
|
79
|
+
- I want to use my AWS credentials for brands I manage (appydave, aitldr, joy)
|
|
80
|
+
- I want team members to use their own credentials for brands they manage
|
|
81
|
+
- I want `ad_config` to show me all brands and their configuration status
|
|
82
|
+
|
|
83
|
+
### As Jan (Team Member)
|
|
84
|
+
- I want to access most brands (except maybe appydave core) with my AWS credentials
|
|
85
|
+
- I want to see which brands I have access to
|
|
86
|
+
- I want VAT commands to automatically use my AWS profile
|
|
87
|
+
|
|
88
|
+
### As Vasilios (Client - VOZ)
|
|
89
|
+
- I want to access only v-voz brand with my AWS credentials
|
|
90
|
+
- I want VAT to work for my brand without seeing other brands
|
|
91
|
+
|
|
92
|
+
### As Ronnie (Client - Kiros/SupportSignal)
|
|
93
|
+
- I want to access v-kiros and v-supportsignal with my AWS credentials
|
|
94
|
+
- I want isolated access to only my client brands
|
|
95
|
+
|
|
96
|
+
### As Developer (Using VAT)
|
|
97
|
+
- I want `vat list` to show all brands I have access to
|
|
98
|
+
- I want `vat s3-up appydave b65` to use the correct AWS profile automatically
|
|
99
|
+
- I want clear error messages if my AWS credentials are missing/invalid
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Architecture
|
|
104
|
+
|
|
105
|
+
### Configuration File Structure
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
~/.config/appydave/
|
|
109
|
+
├── settings.json # Global tool settings
|
|
110
|
+
├── channels.json # YouTube channel configs (existing)
|
|
111
|
+
├── brands.json # NEW: Video project brands
|
|
112
|
+
└── youtube_automation.json
|
|
113
|
+
|
|
114
|
+
~/.aws/
|
|
115
|
+
└── credentials # AWS profiles (standard AWS CLI format)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### brands.json Schema
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"brands": {
|
|
123
|
+
"appydave": {
|
|
124
|
+
"name": "AppyDave",
|
|
125
|
+
"shortcut": "ad",
|
|
126
|
+
"type": "owned",
|
|
127
|
+
"youtube_channels": ["appydave"],
|
|
128
|
+
"team": ["david", "jan"],
|
|
129
|
+
"locations": {
|
|
130
|
+
"video_projects": "/Users/davidcruwys/dev/video-projects/v-appydave",
|
|
131
|
+
"ssd_backup": "/Volumes/T7/youtube-PUBLISHED/appydave"
|
|
132
|
+
},
|
|
133
|
+
"aws": {
|
|
134
|
+
"profile": "david-appydave",
|
|
135
|
+
"region": "ap-southeast-1",
|
|
136
|
+
"s3_bucket": "appydave-video-projects",
|
|
137
|
+
"s3_prefix": "staging/v-appydave/"
|
|
138
|
+
},
|
|
139
|
+
"settings": {
|
|
140
|
+
"s3_cleanup_days": 90
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"voz": {
|
|
144
|
+
"name": "VOZ Creative",
|
|
145
|
+
"shortcut": "voz",
|
|
146
|
+
"type": "client",
|
|
147
|
+
"youtube_channels": [],
|
|
148
|
+
"team": ["vasilios"],
|
|
149
|
+
"locations": {
|
|
150
|
+
"video_projects": "/Users/davidcruwys/dev/video-projects/v-voz",
|
|
151
|
+
"ssd_backup": "/Volumes/T7/voz"
|
|
152
|
+
},
|
|
153
|
+
"aws": {
|
|
154
|
+
"profile": "vasilios-voz",
|
|
155
|
+
"region": "ap-southeast-1",
|
|
156
|
+
"s3_bucket": "appydave-video-projects",
|
|
157
|
+
"s3_prefix": "staging/v-voz/"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"aitldr": {
|
|
161
|
+
"name": "AITLDR",
|
|
162
|
+
"shortcut": "ai",
|
|
163
|
+
"type": "owned",
|
|
164
|
+
"youtube_channels": ["aitldr"],
|
|
165
|
+
"team": ["david", "jan"],
|
|
166
|
+
"aws": {
|
|
167
|
+
"profile": "david-appydave",
|
|
168
|
+
"region": "ap-southeast-1",
|
|
169
|
+
"s3_bucket": "appydave-video-projects",
|
|
170
|
+
"s3_prefix": "staging/v-aitldr/"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"beauty-and-joy": {
|
|
174
|
+
"name": "Beauty & Joy",
|
|
175
|
+
"shortcut": "joy",
|
|
176
|
+
"type": "owned",
|
|
177
|
+
"youtube_channels": [],
|
|
178
|
+
"team": ["joy", "david"],
|
|
179
|
+
"aws": {
|
|
180
|
+
"profile": "david-appydave",
|
|
181
|
+
"region": "ap-southeast-1",
|
|
182
|
+
"s3_bucket": "appydave-video-projects",
|
|
183
|
+
"s3_prefix": "staging/v-beauty-and-joy/"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"kiros": {
|
|
187
|
+
"name": "Kiros",
|
|
188
|
+
"shortcut": "kiros",
|
|
189
|
+
"type": "client",
|
|
190
|
+
"youtube_channels": [],
|
|
191
|
+
"team": ["ronnie"],
|
|
192
|
+
"aws": {
|
|
193
|
+
"profile": "ronnie-kiros",
|
|
194
|
+
"region": "ap-southeast-1",
|
|
195
|
+
"s3_bucket": "appydave-video-projects",
|
|
196
|
+
"s3_prefix": "staging/v-kiros/"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"supportsignal": {
|
|
200
|
+
"name": "SupportSignal",
|
|
201
|
+
"shortcut": "ss",
|
|
202
|
+
"type": "client",
|
|
203
|
+
"youtube_channels": [],
|
|
204
|
+
"team": ["ronnie"],
|
|
205
|
+
"aws": {
|
|
206
|
+
"profile": "ronnie-kiros",
|
|
207
|
+
"region": "ap-southeast-1",
|
|
208
|
+
"s3_bucket": "appydave-video-projects",
|
|
209
|
+
"s3_prefix": "staging/v-supportsignal/"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"users": {
|
|
214
|
+
"david": {
|
|
215
|
+
"name": "David Cruwys",
|
|
216
|
+
"email": "david@appydave.com",
|
|
217
|
+
"role": "owner",
|
|
218
|
+
"default_aws_profile": "david-appydave"
|
|
219
|
+
},
|
|
220
|
+
"jan": {
|
|
221
|
+
"name": "Jan",
|
|
222
|
+
"role": "team_member",
|
|
223
|
+
"default_aws_profile": "jan-appydave"
|
|
224
|
+
},
|
|
225
|
+
"vasilios": {
|
|
226
|
+
"name": "Vasilios Kapenekas",
|
|
227
|
+
"role": "client",
|
|
228
|
+
"default_aws_profile": "vasilios-voz"
|
|
229
|
+
},
|
|
230
|
+
"ronnie": {
|
|
231
|
+
"name": "Ronnie",
|
|
232
|
+
"role": "client",
|
|
233
|
+
"default_aws_profile": "ronnie-kiros"
|
|
234
|
+
},
|
|
235
|
+
"joy": {
|
|
236
|
+
"name": "Joy",
|
|
237
|
+
"role": "owner",
|
|
238
|
+
"default_aws_profile": "joy-beauty"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### AWS Credentials (separate file)
|
|
245
|
+
|
|
246
|
+
**Location**: `~/.aws/credentials` (standard AWS CLI format)
|
|
247
|
+
|
|
248
|
+
```ini
|
|
249
|
+
[david-appydave]
|
|
250
|
+
aws_access_key_id = YOUR_ACCESS_KEY_HERE
|
|
251
|
+
aws_secret_access_key = YOUR_SECRET_KEY_HERE
|
|
252
|
+
|
|
253
|
+
[jan-appydave]
|
|
254
|
+
aws_access_key_id = YOUR_ACCESS_KEY_HERE
|
|
255
|
+
aws_secret_access_key = YOUR_SECRET_KEY_HERE
|
|
256
|
+
|
|
257
|
+
[vasilios-voz]
|
|
258
|
+
aws_access_key_id = YOUR_ACCESS_KEY_HERE
|
|
259
|
+
aws_secret_access_key = YOUR_SECRET_KEY_HERE
|
|
260
|
+
|
|
261
|
+
[ronnie-kiros]
|
|
262
|
+
aws_access_key_id = YOUR_ACCESS_KEY_HERE
|
|
263
|
+
aws_secret_access_key = YOUR_SECRET_KEY_HERE
|
|
264
|
+
|
|
265
|
+
[joy-beauty]
|
|
266
|
+
aws_access_key_id = YOUR_ACCESS_KEY_HERE
|
|
267
|
+
aws_secret_access_key = YOUR_SECRET_KEY_HERE
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Security Benefits**:
|
|
271
|
+
- ✅ Never in git (standard AWS practice)
|
|
272
|
+
- ✅ Standard AWS tooling (`aws configure --profile`)
|
|
273
|
+
- ✅ Per-user credentials
|
|
274
|
+
- ✅ Separate from metadata
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Data Model
|
|
279
|
+
|
|
280
|
+
### BrandInfo Class
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
class BrandInfo
|
|
284
|
+
attr_accessor :key, :name, :shortcut, :type, :youtube_channels,
|
|
285
|
+
:team, :locations, :aws, :settings
|
|
286
|
+
|
|
287
|
+
def initialize(key, data)
|
|
288
|
+
@key = key
|
|
289
|
+
@name = data['name']
|
|
290
|
+
@shortcut = data['shortcut']
|
|
291
|
+
@type = data['type'] # 'owned' or 'client' (metadata only)
|
|
292
|
+
@youtube_channels = data['youtube_channels'] || []
|
|
293
|
+
@team = data['team'] || []
|
|
294
|
+
@locations = BrandLocation.new(data['locations'] || {})
|
|
295
|
+
@aws = BrandAws.new(data['aws'] || {})
|
|
296
|
+
@settings = BrandSettings.new(data['settings'] || {})
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
class BrandLocation
|
|
301
|
+
attr_accessor :video_projects, :ssd_backup
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
class BrandAws
|
|
305
|
+
attr_accessor :profile, :region, :s3_bucket, :s3_prefix
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
class BrandSettings
|
|
309
|
+
attr_accessor :s3_cleanup_days
|
|
310
|
+
end
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Features & Requirements
|
|
316
|
+
|
|
317
|
+
### Feature 1: BrandsConfig Model
|
|
318
|
+
|
|
319
|
+
**Description**: New configuration model parallel to `ChannelsConfig`
|
|
320
|
+
|
|
321
|
+
**Requirements**:
|
|
322
|
+
- [ ] Create `lib/appydave/tools/configuration/models/brands_config.rb`
|
|
323
|
+
- [ ] Implement `BrandsConfig < ConfigBase`
|
|
324
|
+
- [ ] Methods:
|
|
325
|
+
- `get_brand(brand_key)` → returns `BrandInfo`
|
|
326
|
+
- `set_brand(brand_key, brand_info)` → saves brand
|
|
327
|
+
- `brands()` → returns array of all `BrandInfo`
|
|
328
|
+
- `get_brands_for_user(user_key)` → filters by team membership
|
|
329
|
+
- `key?(key)` → check if brand exists
|
|
330
|
+
- `print()` → tabular display of all brands
|
|
331
|
+
- [ ] Type-safe classes: `BrandInfo`, `BrandLocation`, `BrandAws`, `BrandSettings`
|
|
332
|
+
- [ ] Default data structure
|
|
333
|
+
- [ ] Config file: `~/.config/appydave/brands.json`
|
|
334
|
+
|
|
335
|
+
**Acceptance Criteria**:
|
|
336
|
+
- BrandsConfig loads/saves brands.json correctly
|
|
337
|
+
- All 7 brands can be configured
|
|
338
|
+
- Validation ensures required fields present
|
|
339
|
+
- Print displays tabular brand information
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### Feature 2: Integration with Configuration::Config
|
|
344
|
+
|
|
345
|
+
**Description**: Register brands configuration in central config system
|
|
346
|
+
|
|
347
|
+
**Requirements**:
|
|
348
|
+
- [ ] Update `lib/appydave/tools/configuration/config.rb`
|
|
349
|
+
- [ ] Add `register_config(:brands, Models::BrandsConfig)`
|
|
350
|
+
- [ ] Method: `Config.brands` returns `BrandsConfig` instance
|
|
351
|
+
- [ ] Method: `Config.configure` includes brands setup
|
|
352
|
+
|
|
353
|
+
**Acceptance Criteria**:
|
|
354
|
+
- `ad_config -p brands` prints brands configuration
|
|
355
|
+
- `ad_config -c` creates default brands.json if missing
|
|
356
|
+
- `ad_config -e` opens brands.json in editor
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
### Feature 3: Migrate VAT to Use brands.json
|
|
361
|
+
|
|
362
|
+
**Description**: Remove dependency on `.video-tools.env`, use `brands.json` instead
|
|
363
|
+
|
|
364
|
+
**Requirements**:
|
|
365
|
+
|
|
366
|
+
**3a. Update Vat::Config**:
|
|
367
|
+
- [ ] Remove hardcoded brand shortcuts (joy, ss)
|
|
368
|
+
- [ ] Read brand shortcuts from `brands.json`
|
|
369
|
+
- [ ] `brand_path()` reads from `brands.json` locations
|
|
370
|
+
- [ ] `expand_brand()` reads from `brands.json` shortcuts
|
|
371
|
+
- [ ] `available_brands()` reads from `brands.json`
|
|
372
|
+
- [ ] Remove `valid_brand?()` check for `.video-tools.env`
|
|
373
|
+
|
|
374
|
+
**3b. Update Vat::ConfigLoader**:
|
|
375
|
+
- [ ] Deprecate `ConfigLoader` entirely (no longer needed)
|
|
376
|
+
- [ ] OR: Refactor to load from `brands.json` instead of `.video-tools.env`
|
|
377
|
+
- [ ] Method: `ConfigLoader.load_brand(brand_key)` → loads from `brands.json`
|
|
378
|
+
- [ ] Fix bug: `ConfigLoader.load()` doesn't exist (called by S3Operations:19)
|
|
379
|
+
|
|
380
|
+
**3c. Update S3Operations**:
|
|
381
|
+
- [ ] Initialize with `brand_key` instead of `brand_path`
|
|
382
|
+
- [ ] Load config from `brands.json`: `config = Config.brands.get_brand(brand_key)`
|
|
383
|
+
- [ ] Get AWS profile: `config.aws.profile`
|
|
384
|
+
- [ ] Get S3 bucket: `config.aws.s3_bucket`
|
|
385
|
+
- [ ] Get S3 prefix: `config.aws.s3_prefix`
|
|
386
|
+
|
|
387
|
+
**Acceptance Criteria**:
|
|
388
|
+
- VAT commands work with brands.json
|
|
389
|
+
- No dependency on `.video-tools.env`
|
|
390
|
+
- All 7 brands accessible
|
|
391
|
+
- `vat list` shows all configured brands
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### Feature 4: AWS SDK Integration
|
|
396
|
+
|
|
397
|
+
**Description**: Replace AWS CLI shell commands with AWS SDK gem
|
|
398
|
+
|
|
399
|
+
**Requirements**:
|
|
400
|
+
- [ ] Add gem dependency: `spec.add_dependency 'aws-sdk-s3', '~> 1.0'`
|
|
401
|
+
- [ ] Update `S3Operations` to use AWS SDK
|
|
402
|
+
- [ ] Initialize S3 client with profile from `brands.json`:
|
|
403
|
+
```ruby
|
|
404
|
+
Aws::S3::Client.new(
|
|
405
|
+
profile: config.aws.profile,
|
|
406
|
+
region: config.aws.region
|
|
407
|
+
)
|
|
408
|
+
```
|
|
409
|
+
- [ ] Replace 5 AWS CLI operations:
|
|
410
|
+
1. `aws s3api head-object` → `s3_client.head_object()`
|
|
411
|
+
2. `aws s3 cp` (upload) → `s3_client.put_object()`
|
|
412
|
+
3. `aws s3 cp` (download) → `s3_client.get_object()`
|
|
413
|
+
4. `aws s3 rm` → `s3_client.delete_object()`
|
|
414
|
+
5. `aws s3api list-objects-v2` → `s3_client.list_objects_v2()`
|
|
415
|
+
|
|
416
|
+
**Acceptance Criteria**:
|
|
417
|
+
- No AWS CLI dependency
|
|
418
|
+
- S3 operations use SDK gem
|
|
419
|
+
- AWS credentials from `~/.aws/credentials` profiles
|
|
420
|
+
- Error handling for missing/invalid credentials
|
|
421
|
+
- All existing VAT S3 commands work (s3-up, s3-down, s3-status, s3-cleanup)
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
### Feature 5: Update bin/vat Command
|
|
426
|
+
|
|
427
|
+
**Description**: Ensure VAT CLI works with new brands.json system
|
|
428
|
+
|
|
429
|
+
**Requirements**:
|
|
430
|
+
- [ ] Update `parse_s3_args()` to use brands config
|
|
431
|
+
- [ ] Remove `ENV['BRAND_PATH']` workaround (line 203)
|
|
432
|
+
- [ ] Update help text to reference brands.json
|
|
433
|
+
- [ ] Update `vat help config` to show brands.json setup
|
|
434
|
+
|
|
435
|
+
**Acceptance Criteria**:
|
|
436
|
+
- `vat list` shows all brands from brands.json
|
|
437
|
+
- `vat s3-*` commands use AWS SDK with correct profiles
|
|
438
|
+
- Help text accurate
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
### Feature 6: Migration Tool
|
|
443
|
+
|
|
444
|
+
**Description**: Migrate existing `.video-tools.env` → `brands.json` + `~/.aws/credentials`
|
|
445
|
+
|
|
446
|
+
**Requirements**:
|
|
447
|
+
- [ ] Create `bin/migrate_brands_config.rb`
|
|
448
|
+
- [ ] Read existing `.video-tools.env` files
|
|
449
|
+
- [ ] Generate `brands.json` structure
|
|
450
|
+
- [ ] Generate `~/.aws/credentials` profiles
|
|
451
|
+
- [ ] Show migration summary
|
|
452
|
+
- [ ] Backup original files
|
|
453
|
+
|
|
454
|
+
**Acceptance Criteria**:
|
|
455
|
+
- Migration tool converts v-appydave/.video-tools.env successfully
|
|
456
|
+
- Generates complete brands.json with all 7 brands
|
|
457
|
+
- AWS credentials extracted to ~/.aws/credentials
|
|
458
|
+
- User can review before committing changes
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
### Feature 7: Documentation
|
|
463
|
+
|
|
464
|
+
**Requirements**:
|
|
465
|
+
- [ ] Update `docs/vat/vat-testing-plan.md`
|
|
466
|
+
- Remove references to `.video-tools.env`
|
|
467
|
+
- Add references to `brands.json`
|
|
468
|
+
- Update setup instructions
|
|
469
|
+
- [ ] Create `docs/brands-configuration.md`
|
|
470
|
+
- Explain brands.json structure
|
|
471
|
+
- Setup guide for new team members
|
|
472
|
+
- AWS profile setup instructions
|
|
473
|
+
- [ ] Update `CLAUDE.md`
|
|
474
|
+
- Document brands configuration system
|
|
475
|
+
- Update VAT configuration section
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Technical Specifications
|
|
480
|
+
|
|
481
|
+
### Code Structure
|
|
482
|
+
|
|
483
|
+
```
|
|
484
|
+
lib/appydave/tools/
|
|
485
|
+
├── configuration/
|
|
486
|
+
│ ├── config.rb # Update: register brands
|
|
487
|
+
│ └── models/
|
|
488
|
+
│ ├── brands_config.rb # NEW
|
|
489
|
+
│ ├── channels_config.rb # Existing
|
|
490
|
+
│ └── settings_config.rb # Existing
|
|
491
|
+
│
|
|
492
|
+
└── vat/
|
|
493
|
+
├── config.rb # Update: use brands.json
|
|
494
|
+
├── config_loader.rb # Deprecate or refactor
|
|
495
|
+
├── s3_operations.rb # Update: AWS SDK + brands.json
|
|
496
|
+
├── project_listing.rb # Update: use brands.json
|
|
497
|
+
└── project_resolver.rb # Update: use brands.json
|
|
498
|
+
|
|
499
|
+
bin/
|
|
500
|
+
├── configuration.rb # Update: support brands
|
|
501
|
+
├── vat # Update: use brands.json
|
|
502
|
+
└── migrate_brands_config.rb # NEW
|
|
503
|
+
|
|
504
|
+
docs/
|
|
505
|
+
├── prd-unified-brands-configuration.md # This file
|
|
506
|
+
├── brands-configuration.md # NEW: User guide
|
|
507
|
+
└── vat/
|
|
508
|
+
└── vat-testing-plan.md # Update references
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Testing Strategy
|
|
514
|
+
|
|
515
|
+
### Unit Tests
|
|
516
|
+
|
|
517
|
+
- [ ] `spec/appydave/tools/configuration/models/brands_config_spec.rb`
|
|
518
|
+
- Test load/save brands.json
|
|
519
|
+
- Test get_brand(), brands(), get_brands_for_user()
|
|
520
|
+
- Test validation
|
|
521
|
+
- Test print()
|
|
522
|
+
|
|
523
|
+
- [ ] Update `spec/appydave/tools/vat/config_spec.rb`
|
|
524
|
+
- Test brand_path() reads from brands.json
|
|
525
|
+
- Test expand_brand() uses brands.json shortcuts
|
|
526
|
+
- Test available_brands() from brands.json
|
|
527
|
+
|
|
528
|
+
- [ ] Update `spec/appydave/tools/vat/s3_operations_spec.rb`
|
|
529
|
+
- Mock AWS SDK client
|
|
530
|
+
- Test all 5 S3 operations with SDK
|
|
531
|
+
- Test AWS profile loading
|
|
532
|
+
|
|
533
|
+
### Integration Tests
|
|
534
|
+
|
|
535
|
+
- [ ] Test `ad_config -p brands` prints all brands
|
|
536
|
+
- [ ] Test `ad_config -c` creates brands.json
|
|
537
|
+
- [ ] Test `vat list` with brands.json
|
|
538
|
+
- [ ] Test `vat s3-up` with AWS SDK and profiles
|
|
539
|
+
- [ ] Test migration tool with sample .video-tools.env
|
|
540
|
+
|
|
541
|
+
### Manual Testing
|
|
542
|
+
|
|
543
|
+
- [ ] Setup brands.json on David's machine
|
|
544
|
+
- [ ] Setup AWS profiles for David
|
|
545
|
+
- [ ] Test all VAT commands
|
|
546
|
+
- [ ] Verify other team members can set up their profiles
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Migration Plan
|
|
551
|
+
|
|
552
|
+
### Phase 1: Foundation (Week 1) ✅ COMPLETED
|
|
553
|
+
|
|
554
|
+
**Goal**: Create brands.json infrastructure
|
|
555
|
+
|
|
556
|
+
1. ✅ Create `BrandsConfig` model
|
|
557
|
+
2. ✅ Register with `Configuration::Config`
|
|
558
|
+
3. ✅ Write unit tests
|
|
559
|
+
4. ✅ Test `ad_config` commands
|
|
560
|
+
5. ✅ Populate all 6 brands (appydave, voz, aitldr, kiros, joy, ss)
|
|
561
|
+
|
|
562
|
+
**Deliverable**: Working brands.json system
|
|
563
|
+
|
|
564
|
+
**Status**: Complete (2025-11-09)
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
### Phase 2: VAT Integration (Week 2) ✅ COMPLETED
|
|
569
|
+
|
|
570
|
+
**Goal**: VAT uses brands.json
|
|
571
|
+
|
|
572
|
+
1. ✅ Update `Vat::Config` to read brands.json
|
|
573
|
+
2. ✅ Refactor/deprecate `ConfigLoader`
|
|
574
|
+
3. ✅ Update VAT commands
|
|
575
|
+
4. ✅ Update unit tests
|
|
576
|
+
|
|
577
|
+
**Deliverable**: VAT works with brands.json (still using AWS CLI)
|
|
578
|
+
|
|
579
|
+
**Status**: Complete (2025-11-09)
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
### Phase 3: AWS SDK (Week 2-3) ✅ COMPLETED
|
|
584
|
+
|
|
585
|
+
**Goal**: Replace AWS CLI with SDK
|
|
586
|
+
|
|
587
|
+
1. ✅ Add aws-sdk-s3 gem
|
|
588
|
+
2. ✅ Refactor `S3Operations` to use SDK
|
|
589
|
+
3. ✅ Test with AWS profiles
|
|
590
|
+
4. ✅ Update integration tests
|
|
591
|
+
5. ✅ Implement dependency injection pattern
|
|
592
|
+
6. ✅ Add S3 cleanup local command
|
|
593
|
+
7. ✅ Fix S3 status to show local-only files
|
|
594
|
+
8. ✅ Rename cleanup commands (s3-cleanup-remote, s3-cleanup-local)
|
|
595
|
+
|
|
596
|
+
**Deliverable**: VAT uses AWS SDK with profiles from brands.json
|
|
597
|
+
|
|
598
|
+
**Status**: Complete (2025-11-09)
|
|
599
|
+
- 289 tests passing
|
|
600
|
+
- 90.59% code coverage
|
|
601
|
+
- RuboCop clean
|
|
602
|
+
- Manually tested by David
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
### Phase 4: Migration & Cleanup (Week 3)
|
|
607
|
+
|
|
608
|
+
**Goal**: Complete migration, remove old system
|
|
609
|
+
|
|
610
|
+
1. Create migration tool
|
|
611
|
+
2. Migrate David's setup
|
|
612
|
+
3. Test all VAT workflows
|
|
613
|
+
4. Update documentation
|
|
614
|
+
5. Remove `.video-tools.env` dependency
|
|
615
|
+
6. Update testing plan
|
|
616
|
+
|
|
617
|
+
**Deliverable**: Production-ready unified configuration system
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
### Phase 5: Team Onboarding (Week 4)
|
|
622
|
+
|
|
623
|
+
**Goal**: Enable team members to configure their access
|
|
624
|
+
|
|
625
|
+
1. Document setup process
|
|
626
|
+
2. Create AWS IAM users (if needed)
|
|
627
|
+
3. Help Jan/Vasilios/Ronnie configure profiles
|
|
628
|
+
4. Test multi-user access
|
|
629
|
+
|
|
630
|
+
**Deliverable**: All team members using VAT with their own credentials
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Success Criteria
|
|
635
|
+
|
|
636
|
+
### Must Have (MVP)
|
|
637
|
+
|
|
638
|
+
- [ ] All 7 brands configured in brands.json
|
|
639
|
+
- [ ] AWS credentials in ~/.aws/credentials profiles
|
|
640
|
+
- [ ] VAT commands work with brands.json
|
|
641
|
+
- [ ] S3 operations use AWS SDK gem
|
|
642
|
+
- [ ] No dependency on .video-tools.env
|
|
643
|
+
- [ ] All existing tests pass
|
|
644
|
+
- [ ] Migration tool works
|
|
645
|
+
- [ ] Documentation complete
|
|
646
|
+
|
|
647
|
+
### Should Have
|
|
648
|
+
|
|
649
|
+
- [ ] Team members can configure their own profiles
|
|
650
|
+
- [ ] Multi-user access tested
|
|
651
|
+
- [ ] Error messages helpful for missing credentials
|
|
652
|
+
- [ ] `ad_config` prints brand summary
|
|
653
|
+
|
|
654
|
+
### Nice to Have
|
|
655
|
+
|
|
656
|
+
- [ ] Brand-channel linking visible in `ad_config`
|
|
657
|
+
- [ ] Validate AWS profiles are configured
|
|
658
|
+
- [ ] Auto-detect current user
|
|
659
|
+
- [ ] Brand access enforcement (by team membership)
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## Risks & Mitigations
|
|
664
|
+
|
|
665
|
+
| Risk | Impact | Mitigation |
|
|
666
|
+
|------|--------|------------|
|
|
667
|
+
| Breaking existing VAT workflows | High | Thorough testing, migration tool, rollback plan |
|
|
668
|
+
| AWS SDK complexity | Medium | Start with simple operations, test extensively |
|
|
669
|
+
| Team member setup friction | Medium | Clear documentation, setup scripts |
|
|
670
|
+
| ConfigLoader refactoring breaks things | High | Incremental changes, test coverage |
|
|
671
|
+
| .video-tools.env still needed for legacy scripts | Low | Audit all usages first |
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
## Open Questions
|
|
676
|
+
|
|
677
|
+
1. **User detection**: How should VAT detect current user (david, jan, etc.)?
|
|
678
|
+
- Option A: `whoami` system user
|
|
679
|
+
- Option B: Config setting `~/.config/appydave/settings.json` → `current_user`
|
|
680
|
+
- Option C: Environment variable `APPYDAVE_USER`
|
|
681
|
+
|
|
682
|
+
2. **AWS profile fallback**: What if profile doesn't exist?
|
|
683
|
+
- Try user's default profile?
|
|
684
|
+
- Error with setup instructions?
|
|
685
|
+
|
|
686
|
+
3. **Brand access enforcement**: Should VAT check team membership?
|
|
687
|
+
- Or rely on AWS IAM to deny access?
|
|
688
|
+
|
|
689
|
+
4. **SSD backup**: Should all brands share same SSD path structure?
|
|
690
|
+
- Current: `/Volumes/T7/youtube-PUBLISHED/{brand}/`
|
|
691
|
+
- Or allow custom per-brand paths?
|
|
692
|
+
|
|
693
|
+
5. **Legacy bin/ scripts**: What about `archive_project.rb`, `sync_from_ssd.rb`, `generate_manifest.rb`?
|
|
694
|
+
- Migrate to brands.json?
|
|
695
|
+
- Integrate into `vat` command?
|
|
696
|
+
- Leave as-is?
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## Appendix A: Current vs. Proposed
|
|
701
|
+
|
|
702
|
+
### Current System
|
|
703
|
+
|
|
704
|
+
```
|
|
705
|
+
Configuration Sources:
|
|
706
|
+
1. settings.json → video-projects-root only
|
|
707
|
+
2. channels.json → 2/7 brands, YouTube metadata
|
|
708
|
+
3. .video-tools.env → 1/7 brands, AWS credentials
|
|
709
|
+
|
|
710
|
+
AWS Access:
|
|
711
|
+
- Hardcoded in .video-tools.env
|
|
712
|
+
- Only David's credentials
|
|
713
|
+
- AWS CLI shell commands
|
|
714
|
+
|
|
715
|
+
Brand Discovery:
|
|
716
|
+
- Hardcoded shortcuts (joy, ss)
|
|
717
|
+
- Scans filesystem for v-* directories
|
|
718
|
+
- No central registration
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### Proposed System
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
Configuration Sources:
|
|
725
|
+
1. settings.json → global paths (unchanged)
|
|
726
|
+
2. channels.json → YouTube metadata (unchanged)
|
|
727
|
+
3. brands.json → ALL brand metadata (NEW)
|
|
728
|
+
4. ~/.aws/credentials → AWS profiles (standard)
|
|
729
|
+
|
|
730
|
+
AWS Access:
|
|
731
|
+
- Per-user profiles in ~/.aws/credentials
|
|
732
|
+
- AWS SDK gem (no CLI dependency)
|
|
733
|
+
- Profile name from brands.json
|
|
734
|
+
|
|
735
|
+
Brand Discovery:
|
|
736
|
+
- Registered in brands.json
|
|
737
|
+
- Shortcuts defined in brands.json
|
|
738
|
+
- Team membership tracked
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
## Appendix B: Example Workflows
|
|
744
|
+
|
|
745
|
+
### Setup New Brand (VOZ)
|
|
746
|
+
|
|
747
|
+
```bash
|
|
748
|
+
# 1. Add brand to brands.json
|
|
749
|
+
ad_config -e
|
|
750
|
+
# Add voz brand config with Vasilios's AWS profile
|
|
751
|
+
|
|
752
|
+
# 2. Vasilios configures his AWS credentials
|
|
753
|
+
aws configure --profile vasilios-voz
|
|
754
|
+
# Enters his AWS_ACCESS_KEY_ID and SECRET
|
|
755
|
+
|
|
756
|
+
# 3. Test access
|
|
757
|
+
vat list voz
|
|
758
|
+
vat s3-status voz boy-baker
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Developer Using VAT
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
# List all brands I have access to
|
|
765
|
+
vat list
|
|
766
|
+
|
|
767
|
+
# Work with specific brand (auto-detects profile)
|
|
768
|
+
cd ~/dev/video-projects/v-appydave/b65-*
|
|
769
|
+
vat s3-up --dry-run
|
|
770
|
+
|
|
771
|
+
# Explicit brand
|
|
772
|
+
vat s3-up appydave b65
|
|
773
|
+
# Uses aws.profile from brands.json → david-appydave
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
---
|
|
777
|
+
|
|
778
|
+
## Sign-Off
|
|
779
|
+
|
|
780
|
+
**Product Owner**: David Cruwys
|
|
781
|
+
**Developer**: Claude
|
|
782
|
+
**Reviewer**: ___________
|
|
783
|
+
|
|
784
|
+
**Approval Date**: ___________
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
**Next Steps After Approval**:
|
|
789
|
+
1. Review and approve PRD
|
|
790
|
+
2. Create implementation plan with tasks
|
|
791
|
+
3. Begin Phase 1: BrandsConfig model
|
|
792
|
+
4. Weekly progress reviews
|