@l4yercak3/cli 1.0.6 → 1.1.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.
@@ -0,0 +1,606 @@
1
+ # CLI Requirements - What CLI Teams Need to Implement
2
+
3
+ **Purpose:** This document tells CLI teams exactly what to build to register and manage connected applications in L4YERCAK3.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ The CLI needs to:
10
+ 1. **Authenticate** users via browser OAuth flow
11
+ 2. **Detect** project framework and models
12
+ 3. **Register** the application with L4YERCAK3 backend
13
+ 4. **Generate** API client code and types
14
+ 5. **Sync** data between local app and L4YERCAK3
15
+
16
+ ---
17
+
18
+ ## Part 1: Authentication (Already Implemented)
19
+
20
+ CLI authentication is working. For reference:
21
+
22
+ ```bash
23
+ l4yercak3 login
24
+ ```
25
+
26
+ **Flow:**
27
+ 1. CLI opens browser to `https://l4yercak3.com/cli/login?state={uuid}`
28
+ 2. User authenticates with L4YERCAK3
29
+ 3. Backend creates CLI session token
30
+ 4. Browser redirects to localhost callback OR user copies token
31
+ 5. CLI stores token in `~/.l4yercak3/config.json`
32
+
33
+ **Token Format:** `cli_session_{64_hex_chars}`
34
+ **Token Lifetime:** 30 days
35
+
36
+ ---
37
+
38
+ ## Part 2: Application Registration (NEW - Priority 1)
39
+
40
+ ### Command: `l4yercak3 init`
41
+
42
+ This is the main command CLI teams need to implement.
43
+
44
+ **What it does:**
45
+ 1. Detects project framework
46
+ 2. Asks user which features to enable
47
+ 3. Registers application with L4YERCAK3 backend
48
+ 4. Generates API client files
49
+
50
+ ### Step 2.1: Project Detection
51
+
52
+ CLI must detect and collect:
53
+
54
+ ```typescript
55
+ interface ProjectDetection {
56
+ // Framework detection
57
+ framework: "nextjs" | "remix" | "astro" | "vite" | "nuxt" | "sveltekit" | "other";
58
+ frameworkVersion?: string; // From package.json
59
+ hasTypeScript: boolean; // tsconfig.json exists
60
+ routerType?: "app" | "pages"; // For Next.js only
61
+
62
+ // Project identification
63
+ projectPath: string; // Absolute path
64
+ projectPathHash: string; // SHA256(projectPath) - for identifying returning projects
65
+ projectName: string; // From package.json name or directory name
66
+
67
+ // Database detection (optional)
68
+ hasFrontendDatabase: boolean;
69
+ frontendDatabaseType?: "convex" | "prisma" | "drizzle" | "other";
70
+ }
71
+ ```
72
+
73
+ **Detection Logic:**
74
+
75
+ ```typescript
76
+ // Framework detection
77
+ if (existsSync('next.config.js') || existsSync('next.config.ts')) {
78
+ framework = 'nextjs';
79
+ routerType = existsSync('app/') ? 'app' : 'pages';
80
+ }
81
+ if (existsSync('remix.config.js')) framework = 'remix';
82
+ if (existsSync('astro.config.mjs')) framework = 'astro';
83
+ // etc.
84
+
85
+ // TypeScript detection
86
+ hasTypeScript = existsSync('tsconfig.json');
87
+
88
+ // Database detection
89
+ hasFrontendDatabase = existsSync('convex/') || existsSync('prisma/schema.prisma');
90
+ if (existsSync('convex/')) frontendDatabaseType = 'convex';
91
+ if (existsSync('prisma/')) frontendDatabaseType = 'prisma';
92
+
93
+ // Project hash for identification
94
+ projectPathHash = sha256(absolutePath);
95
+ ```
96
+
97
+ ### Step 2.2: Feature Selection
98
+
99
+ CLI should prompt user for features:
100
+
101
+ ```
102
+ ? Which L4YERCAK3 features do you want to use?
103
+ ◉ CRM (contacts, organizations)
104
+ ◉ Events (event management, registrations)
105
+ ◉ Products (product catalog)
106
+ ◉ Checkout (payment processing)
107
+ ◉ Tickets (ticket generation)
108
+ ◉ Invoicing (invoice creation)
109
+ ◉ Forms (dynamic forms)
110
+ ◉ Projects (project management)
111
+ ◯ Workflows (automation)
112
+ ◯ Templates (document templates)
113
+ ◯ AI (AI assistant)
114
+ ```
115
+
116
+ Result:
117
+
118
+ ```typescript
119
+ const selectedFeatures: string[] = [
120
+ "crm", "events", "products", "checkout", "tickets", "invoicing", "forms"
121
+ ];
122
+ ```
123
+
124
+ ### Step 2.3: API Registration
125
+
126
+ **Endpoint:** `POST /api/v1/cli/applications`
127
+
128
+ **Headers:**
129
+ ```
130
+ Authorization: Bearer cli_session_xxx
131
+ Content-Type: application/json
132
+ ```
133
+
134
+ **Request Body:**
135
+
136
+ ```typescript
137
+ interface RegisterApplicationRequest {
138
+ // Organization (from login)
139
+ organizationId: string;
140
+
141
+ // Basic info
142
+ name: string; // Project name (user can edit)
143
+ description?: string; // Optional description
144
+
145
+ // Source detection
146
+ source: {
147
+ type: "cli";
148
+ projectPathHash: string; // SHA256 of absolute path
149
+ cliVersion: string; // "1.0.0"
150
+ framework: string; // "nextjs"
151
+ frameworkVersion?: string; // "15.0.0"
152
+ hasTypeScript: boolean;
153
+ routerType?: "app" | "pages";
154
+ };
155
+
156
+ // Connection config
157
+ connection: {
158
+ features: string[]; // ["crm", "events", "checkout"]
159
+ hasFrontendDatabase: boolean;
160
+ frontendDatabaseType?: string;
161
+ };
162
+
163
+ // Optional: Model mappings if detected
164
+ modelMappings?: Array<{
165
+ localModel: string; // "User", "Event"
166
+ layerCakeType: string; // "contact", "event"
167
+ syncDirection: "push" | "pull" | "bidirectional" | "none";
168
+ confidence: number; // 0-100
169
+ isAutoDetected: boolean;
170
+ }>;
171
+ }
172
+ ```
173
+
174
+ **Response:**
175
+
176
+ ```typescript
177
+ interface RegisterApplicationResponse {
178
+ success: boolean;
179
+ applicationId: string; // ID of created connected_application
180
+
181
+ // API credentials
182
+ apiKey: {
183
+ id: string;
184
+ key: string; // Full key, only shown once: "org_xxx_sk_live_yyy"
185
+ prefix: string; // "org_xxx_sk_live_..."
186
+ };
187
+
188
+ // Backend URLs
189
+ backendUrl: string; // "https://agreeable-lion-828.convex.site"
190
+
191
+ // If application already exists (same projectPathHash)
192
+ existingApplication?: boolean;
193
+ message?: string;
194
+ }
195
+ ```
196
+
197
+ **Error Responses:**
198
+
199
+ ```typescript
200
+ // 401 Unauthorized
201
+ { error: "Invalid or expired CLI session", code: "INVALID_SESSION" }
202
+
203
+ // 400 Bad Request
204
+ { error: "Missing required field: name", code: "VALIDATION_ERROR" }
205
+
206
+ // 409 Conflict (optional - if we want to prevent duplicates)
207
+ {
208
+ error: "Application already registered for this project",
209
+ code: "DUPLICATE_APPLICATION",
210
+ existingApplicationId: "app_xxx"
211
+ }
212
+ ```
213
+
214
+ ### Step 2.4: Check Existing Application
215
+
216
+ Before registering, CLI should check if app already exists:
217
+
218
+ **Endpoint:** `GET /api/v1/cli/applications/by-path?hash={projectPathHash}`
219
+
220
+ **Response:**
221
+
222
+ ```typescript
223
+ interface ExistingApplicationResponse {
224
+ found: boolean;
225
+ application?: {
226
+ id: string;
227
+ name: string;
228
+ status: string;
229
+ features: string[];
230
+ lastActivityAt: number;
231
+ };
232
+ }
233
+ ```
234
+
235
+ If found, CLI should ask: "Application already registered. Update it? (Y/n)"
236
+
237
+ ---
238
+
239
+ ## Part 3: Code Generation (Priority 2)
240
+
241
+ After registration, CLI generates files.
242
+
243
+ ### Files to Generate
244
+
245
+ **1. API Client: `src/lib/layercake.ts`**
246
+
247
+ ```typescript
248
+ // Auto-generated by L4YERCAK3 CLI v1.0.0
249
+ // Do not edit manually - run `l4yercak3 generate` to regenerate
250
+
251
+ const API_URL = process.env.NEXT_PUBLIC_L4YERCAK3_URL!;
252
+ const API_KEY = process.env.NEXT_PUBLIC_L4YERCAK3_KEY!;
253
+ const ORG_ID = process.env.NEXT_PUBLIC_L4YERCAK3_ORG_ID!;
254
+
255
+ async function apiFetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
256
+ const response = await fetch(`${API_URL}${endpoint}`, {
257
+ ...options,
258
+ headers: {
259
+ 'Content-Type': 'application/json',
260
+ 'Authorization': `Bearer ${API_KEY}`,
261
+ ...options.headers,
262
+ },
263
+ });
264
+
265
+ if (!response.ok) {
266
+ const error = await response.json().catch(() => ({}));
267
+ throw new Error(error.message || `API Error: ${response.status}`);
268
+ }
269
+
270
+ return response.json();
271
+ }
272
+
273
+ // Feature modules based on selection...
274
+ export const eventApi = { /* ... */ };
275
+ export const crmApi = { /* ... */ };
276
+ // etc.
277
+ ```
278
+
279
+ **2. Types: `src/types/layercake.ts`**
280
+
281
+ ```typescript
282
+ // Auto-generated by L4YERCAK3 CLI v1.0.0
283
+
284
+ export interface Event {
285
+ id: string;
286
+ name: string;
287
+ description?: string;
288
+ status: string;
289
+ startDate?: number;
290
+ endDate?: number;
291
+ // ...
292
+ }
293
+
294
+ export interface Contact {
295
+ id: string;
296
+ email: string;
297
+ firstName?: string;
298
+ lastName?: string;
299
+ // ...
300
+ }
301
+
302
+ // Types for each enabled feature...
303
+ ```
304
+
305
+ **3. Environment: `.env.local.example`**
306
+
307
+ ```bash
308
+ # L4YERCAK3 Backend - Generated by CLI
309
+ NEXT_PUBLIC_L4YERCAK3_URL=https://agreeable-lion-828.convex.site
310
+ NEXT_PUBLIC_L4YERCAK3_KEY=your_api_key_here
311
+ NEXT_PUBLIC_L4YERCAK3_ORG_ID=org_xxx
312
+ ```
313
+
314
+ **4. Update actual `.env.local`**
315
+
316
+ CLI should either:
317
+ - Append to existing `.env.local` with comments
318
+ - Ask user permission before modifying
319
+
320
+ ### Generation Templates
321
+
322
+ CLI needs templates for each feature. Store in CLI package:
323
+
324
+ ```
325
+ cli/
326
+ ├── templates/
327
+ │ ├── api-client.ts.hbs # Handlebars template
328
+ │ ├── types/
329
+ │ │ ├── event.ts.hbs
330
+ │ │ ├── contact.ts.hbs
331
+ │ │ ├── product.ts.hbs
332
+ │ │ └── ...
333
+ │ └── hooks/
334
+ │ ├── use-events.ts.hbs
335
+ │ └── ...
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Part 4: Update Application (Priority 3)
341
+
342
+ ### Command: `l4yercak3 update`
343
+
344
+ Re-runs detection and updates backend.
345
+
346
+ **Endpoint:** `PATCH /api/v1/cli/applications/:id`
347
+
348
+ **Request:**
349
+
350
+ ```typescript
351
+ interface UpdateApplicationRequest {
352
+ // Any fields from RegisterApplicationRequest
353
+ name?: string;
354
+ description?: string;
355
+ connection?: {
356
+ features?: string[];
357
+ };
358
+ modelMappings?: ModelMapping[];
359
+ }
360
+ ```
361
+
362
+ ---
363
+
364
+ ## Part 5: Sync Status (Priority 3)
365
+
366
+ ### Command: `l4yercak3 status`
367
+
368
+ Shows connection status and sync info.
369
+
370
+ **Endpoint:** `GET /api/v1/cli/applications/:id`
371
+
372
+ **Response:**
373
+
374
+ ```typescript
375
+ interface ApplicationStatusResponse {
376
+ id: string;
377
+ name: string;
378
+ status: "active" | "paused" | "disconnected";
379
+
380
+ connection: {
381
+ features: string[];
382
+ apiKeyPrefix: string;
383
+ };
384
+
385
+ sync: {
386
+ enabled: boolean;
387
+ lastSyncAt?: number;
388
+ lastSyncStatus?: "success" | "partial" | "failed";
389
+ };
390
+
391
+ deployment?: {
392
+ productionUrl?: string;
393
+ stagingUrl?: string;
394
+ deploymentStatus: string;
395
+ lastDeployedAt?: number;
396
+ };
397
+
398
+ cli: {
399
+ registeredAt: number;
400
+ lastActivityAt: number;
401
+ generatedFiles: Array<{
402
+ path: string;
403
+ type: string;
404
+ generatedAt: number;
405
+ }>;
406
+ };
407
+ }
408
+ ```
409
+
410
+ ### Command: `l4yercak3 sync`
411
+
412
+ Syncs data between local and backend.
413
+
414
+ **Endpoint:** `POST /api/v1/cli/applications/:id/sync`
415
+
416
+ **Request:**
417
+
418
+ ```typescript
419
+ interface SyncRequest {
420
+ direction: "push" | "pull" | "bidirectional";
421
+ models?: string[]; // Optional: specific models to sync
422
+ dryRun?: boolean; // Preview without making changes
423
+ }
424
+ ```
425
+
426
+ **Response:**
427
+
428
+ ```typescript
429
+ interface SyncResponse {
430
+ success: boolean;
431
+ direction: string;
432
+ results: Array<{
433
+ model: string;
434
+ recordsProcessed: number;
435
+ recordsCreated: number;
436
+ recordsUpdated: number;
437
+ errors: number;
438
+ }>;
439
+ duration: number;
440
+ }
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Part 6: Model Detection (Priority 4)
446
+
447
+ ### Detecting Local Models
448
+
449
+ CLI should detect models from:
450
+
451
+ **Prisma:**
452
+ ```typescript
453
+ // Parse prisma/schema.prisma
454
+ model User {
455
+ id String @id @default(cuid())
456
+ email String @unique
457
+ firstName String?
458
+ lastName String?
459
+ }
460
+ ```
461
+
462
+ **TypeScript interfaces:**
463
+ ```typescript
464
+ // Scan src/types/*.ts for interface definitions
465
+ interface User {
466
+ id: string;
467
+ email: string;
468
+ firstName?: string;
469
+ }
470
+ ```
471
+
472
+ ### Mapping to L4YERCAK3 Types
473
+
474
+ ```typescript
475
+ const TYPE_MAPPINGS = {
476
+ // Model name patterns → L4YERCAK3 type
477
+ 'user': 'contact',
478
+ 'customer': 'contact',
479
+ 'member': 'contact',
480
+ 'company': 'crm_organization',
481
+ 'organization': 'crm_organization',
482
+ 'event': 'event',
483
+ 'meeting': 'event',
484
+ 'product': 'product',
485
+ 'item': 'product',
486
+ 'order': 'transaction',
487
+ 'invoice': 'invoice',
488
+ 'ticket': 'ticket',
489
+ 'form': 'form',
490
+ 'project': 'project',
491
+ };
492
+
493
+ function detectModelMapping(localModel: string): {
494
+ layerCakeType: string;
495
+ confidence: number;
496
+ } {
497
+ const normalized = localModel.toLowerCase();
498
+
499
+ for (const [pattern, type] of Object.entries(TYPE_MAPPINGS)) {
500
+ if (normalized.includes(pattern)) {
501
+ return { layerCakeType: type, confidence: 80 };
502
+ }
503
+ }
504
+
505
+ return { layerCakeType: 'unknown', confidence: 0 };
506
+ }
507
+ ```
508
+
509
+ ---
510
+
511
+ ## Summary: Implementation Priority
512
+
513
+ ### Week 1-2: Core Registration
514
+
515
+ 1. **`l4yercak3 init`** command
516
+ - Project detection (framework, TypeScript, databases)
517
+ - Feature selection prompt
518
+ - API call to register application
519
+ - Basic code generation (API client + types)
520
+
521
+ 2. **Backend endpoints** (we build these)
522
+ - `POST /api/v1/cli/applications`
523
+ - `GET /api/v1/cli/applications/by-path`
524
+
525
+ ### Week 3-4: Status & Updates
526
+
527
+ 3. **`l4yercak3 status`** command
528
+ - Show application status
529
+ - Show connected features
530
+ - Show last sync time
531
+
532
+ 4. **`l4yercak3 update`** command
533
+ - Re-run detection
534
+ - Update features
535
+ - Regenerate code
536
+
537
+ 5. **Backend endpoints**
538
+ - `GET /api/v1/cli/applications/:id`
539
+ - `PATCH /api/v1/cli/applications/:id`
540
+
541
+ ### Week 5-6: Sync & Models
542
+
543
+ 6. **`l4yercak3 sync`** command
544
+ - Push/pull data
545
+ - Dry run mode
546
+
547
+ 7. **Model detection**
548
+ - Prisma schema parsing
549
+ - TypeScript interface detection
550
+ - Mapping suggestions
551
+
552
+ 8. **Backend endpoints**
553
+ - `POST /api/v1/cli/applications/:id/sync`
554
+
555
+ ---
556
+
557
+ ## CLI Team Deliverables Checklist
558
+
559
+ ### Phase 1 (Start Now)
560
+
561
+ - [ ] **Project detection function** - Detect framework, TypeScript, databases
562
+ - [ ] **Project hash function** - SHA256 of absolute path
563
+ - [ ] **Feature selection UI** - Multi-select prompt for features
564
+ - [ ] **Register application API call** - POST to `/api/v1/cli/applications`
565
+ - [ ] **Check existing application** - GET `/api/v1/cli/applications/by-path`
566
+ - [ ] **API client template** - Generate `layercake.ts`
567
+ - [ ] **Types template** - Generate `layercake.types.ts`
568
+ - [ ] **Env file handling** - Create/update `.env.local`
569
+
570
+ ### Phase 2 (After Phase 1)
571
+
572
+ - [ ] **Status command** - Show application status
573
+ - [ ] **Update command** - Update application config
574
+ - [ ] **Regenerate command** - Regenerate files from templates
575
+
576
+ ### Phase 3 (After Phase 2)
577
+
578
+ - [ ] **Sync command** - Push/pull data
579
+ - [ ] **Model detection** - Parse Prisma/TypeScript
580
+ - [ ] **Mapping suggestions** - Auto-suggest model mappings
581
+
582
+ ---
583
+
584
+ ## Questions for CLI Team
585
+
586
+ 1. **Config storage location?** Currently `~/.l4yercak3/config.json` - is this correct?
587
+ 2. **Multiple organizations?** How should CLI handle users with access to multiple orgs?
588
+ 3. **Offline mode?** Should CLI work offline with cached data?
589
+ 4. **Interactive vs flags?** Support both `l4yercak3 init` (interactive) and `l4yercak3 init --features=crm,events` (flags)?
590
+
591
+ ---
592
+
593
+ ## Backend Endpoints We Need to Build
594
+
595
+ For CLI teams to work, we need to implement these endpoints:
596
+
597
+ | Endpoint | Method | Priority | Description |
598
+ |----------|--------|----------|-------------|
599
+ | `/api/v1/cli/applications` | POST | P1 | Register new application |
600
+ | `/api/v1/cli/applications/by-path` | GET | P1 | Find by project hash |
601
+ | `/api/v1/cli/applications/:id` | GET | P2 | Get application details |
602
+ | `/api/v1/cli/applications/:id` | PATCH | P2 | Update application |
603
+ | `/api/v1/cli/applications/:id/sync` | POST | P3 | Trigger/report sync |
604
+ | `/api/v1/cli/applications` | GET | P2 | List all applications |
605
+
606
+ **These endpoints will be built in parallel with CLI work.**