create-propelkit 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/README.md +131 -0
- package/bin/cli.js +6 -0
- package/package.json +31 -0
- package/src/cli-detector.js +104 -0
- package/src/config.js +25 -0
- package/src/design-flow.js +442 -0
- package/src/index.js +126 -0
- package/src/launcher.js +42 -0
- package/src/license-validator.js +85 -0
- package/src/messages.js +119 -0
- package/src/orchestrators/existing-designs.ts +176 -0
- package/src/page-mapper.js +247 -0
- package/src/prompt-generator.js +429 -0
- package/src/scenarios.js +217 -0
- package/src/setup-wizard.js +315 -0
- package/src/validators.js +153 -0
package/src/messages.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
const messages = {
|
|
4
|
+
welcome: () => {
|
|
5
|
+
console.log('');
|
|
6
|
+
console.log(chalk.cyan.bold('PropelKit'));
|
|
7
|
+
console.log(chalk.dim('AI-powered SaaS boilerplate for India'));
|
|
8
|
+
console.log('');
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
detectingCLIs: () => {
|
|
12
|
+
console.log(chalk.dim('Detecting installed tools...'));
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
claudeRequired: (installUrl) => {
|
|
16
|
+
console.log('');
|
|
17
|
+
console.log(chalk.red.bold('Claude Code is required to use PropelKit'));
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log('PropelKit uses Claude Code as the AI PM to build your project.');
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.cyan('Install Claude Code:'));
|
|
22
|
+
console.log(chalk.dim(` ${installUrl}`));
|
|
23
|
+
console.log('');
|
|
24
|
+
console.log('After installing, run this command again.');
|
|
25
|
+
console.log('');
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
supabaseBenefits: () => {
|
|
29
|
+
console.log(chalk.cyan('Supabase CLI Benefits:'));
|
|
30
|
+
console.log(chalk.dim(' - Automatic database migrations after each phase'));
|
|
31
|
+
console.log(chalk.dim(' - No need to manually copy SQL to Supabase dashboard'));
|
|
32
|
+
console.log(chalk.dim(' - Local development with supabase start'));
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(chalk.dim('Without Supabase CLI:'));
|
|
35
|
+
console.log(chalk.dim(' - SQL will be shown inline for you to paste manually'));
|
|
36
|
+
console.log(chalk.dim(' - Migration files saved to supabase/migrations/'));
|
|
37
|
+
console.log('');
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
githubBenefits: () => {
|
|
41
|
+
console.log(chalk.cyan('GitHub CLI Benefits:'));
|
|
42
|
+
console.log(chalk.dim(' - Automatic repo creation'));
|
|
43
|
+
console.log(chalk.dim(' - Automatic push after each phase'));
|
|
44
|
+
console.log(chalk.dim(' - Branch management'));
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log(chalk.dim('Without GitHub CLI:'));
|
|
47
|
+
console.log(chalk.dim(' - Local git commits still happen'));
|
|
48
|
+
console.log(chalk.dim(' - You push to remote manually'));
|
|
49
|
+
console.log('');
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
launchingClaude: (projectDir) => {
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log(chalk.cyan.bold('Launching Claude Code...'));
|
|
55
|
+
console.log(chalk.dim(`Directory: ${projectDir}`));
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log(chalk.yellow('When Claude Code opens, type:'));
|
|
58
|
+
console.log(chalk.white.bold(' /propelkit:new-project'));
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(chalk.dim('This starts the AI PM conversation to build your project.'));
|
|
61
|
+
console.log('');
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
cloneInstructions: (repoUrl, targetDir) => {
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(chalk.cyan('Cloning PropelKit...'));
|
|
67
|
+
console.log(chalk.dim(` From: ${repoUrl}`));
|
|
68
|
+
console.log(chalk.dim(` To: ${targetDir}`));
|
|
69
|
+
console.log('');
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
resumeInstructions: (command) => {
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(chalk.yellow('To resume, run:'));
|
|
75
|
+
console.log(chalk.white.bold(` ${command}`));
|
|
76
|
+
console.log('');
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
starterLicenseValid: () => {
|
|
80
|
+
console.log(chalk.green('License validated: STARTER'));
|
|
81
|
+
console.log('');
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
proLicenseValid: () => {
|
|
85
|
+
console.log(chalk.green('License validated: PRO'));
|
|
86
|
+
console.log('');
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
licenseInvalid: (message) => {
|
|
90
|
+
console.log('');
|
|
91
|
+
console.log(chalk.red('License validation failed'));
|
|
92
|
+
console.log(chalk.dim(message || 'Invalid license key'));
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(`Purchase a license at: ${chalk.cyan('https://propelkit.dev')}`);
|
|
95
|
+
console.log('');
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
starterWizardComplete: () => {
|
|
99
|
+
console.log('');
|
|
100
|
+
console.log(chalk.green.bold('PropelKit Starter is ready!'));
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(chalk.dim('Run these commands to start:'));
|
|
103
|
+
console.log(chalk.cyan(' npm install'));
|
|
104
|
+
console.log(chalk.cyan(' npm run dev'));
|
|
105
|
+
console.log('');
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
proLaunchingAIPM: (projectDir) => {
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(chalk.cyan.bold('Launching AI PM in Claude Code...'));
|
|
111
|
+
console.log(chalk.dim(`Project: ${projectDir}`));
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(chalk.dim('When Claude Code opens, type:'));
|
|
114
|
+
console.log(chalk.white.bold(' /propelkit:new-project'));
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
module.exports = messages;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Existing Designs Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* TypeScript orchestrator that chains import → translation → integration
|
|
5
|
+
* for the "I have existing designs" CLI path.
|
|
6
|
+
*
|
|
7
|
+
* Spawned by design-flow.js via npx tsx.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { importProject } from '@/lib/import';
|
|
11
|
+
import { translateProject } from '@/lib/translation';
|
|
12
|
+
import { analyzeIntegration, generateIntegrationReport } from '@/lib/integration';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
interface CliArgs {
|
|
16
|
+
projectDir: string;
|
|
17
|
+
sourceBase64: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface ImportSource {
|
|
21
|
+
type: 'github' | 'local';
|
|
22
|
+
url?: string;
|
|
23
|
+
path?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parse command-line arguments.
|
|
28
|
+
*
|
|
29
|
+
* Expected format: --project-dir <path> --source-base64 <json>
|
|
30
|
+
*/
|
|
31
|
+
function parseArgs(argv: string[]): CliArgs {
|
|
32
|
+
const args: Record<string, string> = {};
|
|
33
|
+
|
|
34
|
+
for (let i = 2; i < argv.length; i++) {
|
|
35
|
+
const arg = argv[i];
|
|
36
|
+
|
|
37
|
+
if (arg.startsWith('--')) {
|
|
38
|
+
const key = arg.slice(2);
|
|
39
|
+
const value = argv[i + 1];
|
|
40
|
+
|
|
41
|
+
if (value && !value.startsWith('--')) {
|
|
42
|
+
args[key] = value;
|
|
43
|
+
i++; // Skip next item since we consumed it
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!args.projectDir || !args.sourceBase64) {
|
|
49
|
+
console.error('');
|
|
50
|
+
console.error('Usage: tsx existing-designs.ts --project-dir <path> --source-base64 <json>');
|
|
51
|
+
console.error('');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
projectDir: args.projectDir,
|
|
57
|
+
sourceBase64: args.sourceBase64,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Main orchestration function.
|
|
63
|
+
*
|
|
64
|
+
* Chains import → translation → integration pipeline.
|
|
65
|
+
*/
|
|
66
|
+
async function main() {
|
|
67
|
+
const args = parseArgs(process.argv);
|
|
68
|
+
|
|
69
|
+
// Decode source from base64
|
|
70
|
+
const sourceJson = Buffer.from(args.sourceBase64, 'base64').toString('utf-8');
|
|
71
|
+
const source: ImportSource = JSON.parse(sourceJson);
|
|
72
|
+
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
75
|
+
console.log(' PropelKit: Existing Designs Import');
|
|
76
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
77
|
+
console.log('');
|
|
78
|
+
|
|
79
|
+
// Step 1: Import
|
|
80
|
+
console.log('[1/3] Importing project...');
|
|
81
|
+
console.log('');
|
|
82
|
+
|
|
83
|
+
const importResult = await importProject({
|
|
84
|
+
source,
|
|
85
|
+
destinationBase: path.join(args.projectDir, 'src', 'imported'),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (!importResult.success) {
|
|
89
|
+
console.error('');
|
|
90
|
+
console.error('❌ Import failed:');
|
|
91
|
+
importResult.errors.forEach((err) => console.error(` - ${err}`));
|
|
92
|
+
console.error('');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(`✓ Imported to: ${importResult.projectPath}`);
|
|
97
|
+
if (importResult.warnings.length > 0) {
|
|
98
|
+
console.log(`⚠ ${importResult.warnings.length} warnings (see below)`);
|
|
99
|
+
importResult.warnings.forEach((w) => console.log(` - ${w}`));
|
|
100
|
+
}
|
|
101
|
+
console.log('');
|
|
102
|
+
|
|
103
|
+
// Step 2: Translation
|
|
104
|
+
console.log('[2/3] Translating to Next.js App Router...');
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
const translationResult = await translateProject({
|
|
108
|
+
sourceDir: importResult.projectPath,
|
|
109
|
+
targetDir: path.join(args.projectDir, 'src', 'app'),
|
|
110
|
+
preserveComments: true,
|
|
111
|
+
incremental: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!translationResult.success) {
|
|
115
|
+
console.error('');
|
|
116
|
+
console.error('❌ Translation failed:');
|
|
117
|
+
translationResult.errors.forEach((err) => console.error(` - ${err}`));
|
|
118
|
+
console.error('');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`✓ Translated ${translationResult.components.length} components`);
|
|
123
|
+
console.log(`✓ Migrated ${translationResult.routes.length} routes`);
|
|
124
|
+
if (translationResult.warnings.length > 0) {
|
|
125
|
+
console.log(`⚠ ${translationResult.warnings.length} warnings (see report)`);
|
|
126
|
+
}
|
|
127
|
+
console.log('');
|
|
128
|
+
|
|
129
|
+
// Step 3: Integration Analysis
|
|
130
|
+
console.log('[3/3] Analyzing backend integration needs...');
|
|
131
|
+
console.log('');
|
|
132
|
+
|
|
133
|
+
const integrationResult = await analyzeIntegration(importResult.projectPath);
|
|
134
|
+
|
|
135
|
+
if (integrationResult.errors.length > 0) {
|
|
136
|
+
console.error('');
|
|
137
|
+
console.error('⚠ Integration analysis had errors:');
|
|
138
|
+
integrationResult.errors.forEach((err) => console.error(` - ${err}`));
|
|
139
|
+
console.error('');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const reportPath = await generateIntegrationReport(
|
|
143
|
+
integrationResult,
|
|
144
|
+
path.join(args.projectDir, 'INTEGRATION.md')
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
console.log(`✓ Integration report generated`);
|
|
148
|
+
console.log('');
|
|
149
|
+
|
|
150
|
+
// Summary
|
|
151
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
152
|
+
console.log(' Summary');
|
|
153
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
154
|
+
console.log(` Components analyzed: ${integrationResult.components.length}`);
|
|
155
|
+
console.log(` Auth migrations needed: ${integrationResult.summary.authMigrations}`);
|
|
156
|
+
console.log(` Data components: ${integrationResult.summary.dataComponents}`);
|
|
157
|
+
console.log(` Total TODOs: ${integrationResult.summary.totalTodos}`);
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log(`📄 Next steps: Review ${path.basename(reportPath)}`);
|
|
160
|
+
console.log('');
|
|
161
|
+
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Execute with error handling
|
|
166
|
+
main().catch((err) => {
|
|
167
|
+
console.error('');
|
|
168
|
+
console.error('💥 Fatal error:');
|
|
169
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
170
|
+
console.error('');
|
|
171
|
+
if (err instanceof Error && err.stack) {
|
|
172
|
+
console.error('Stack trace:');
|
|
173
|
+
console.error(err.stack);
|
|
174
|
+
}
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature-to-page template mapping
|
|
3
|
+
* Derives page suggestions from PropelKit feature flags
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Page templates organized by feature category
|
|
8
|
+
* Each category contains pages that are relevant when that feature is enabled
|
|
9
|
+
*/
|
|
10
|
+
const PAGE_TEMPLATES = {
|
|
11
|
+
// Core pages (always included)
|
|
12
|
+
core: ['Home', 'Dashboard', 'Settings', '404'],
|
|
13
|
+
|
|
14
|
+
// Auth pages (always included)
|
|
15
|
+
auth: ['Login', 'Signup', 'Forgot Password', 'Reset Password'],
|
|
16
|
+
|
|
17
|
+
// Payment pages (always included)
|
|
18
|
+
payments: ['Pricing', 'Checkout', 'Billing History'],
|
|
19
|
+
|
|
20
|
+
// Multi-tenancy pages (optional - based on features.multiTenancy)
|
|
21
|
+
multiTenancy: ['Team Settings', 'Invite Members', 'Role Management'],
|
|
22
|
+
|
|
23
|
+
// Credits pages (optional - based on features.credits)
|
|
24
|
+
credits: ['Usage Dashboard', 'Purchase Credits'],
|
|
25
|
+
|
|
26
|
+
// GST pages (always included for India)
|
|
27
|
+
gst: ['Invoice Settings'],
|
|
28
|
+
|
|
29
|
+
// Admin pages (always included)
|
|
30
|
+
admin: ['Admin Panel']
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Page detail templates for Lovable prompt generation
|
|
35
|
+
* Contains purpose, elements, components, and user flow for each known page
|
|
36
|
+
*/
|
|
37
|
+
const PAGE_DETAILS = {
|
|
38
|
+
// Core pages
|
|
39
|
+
'Home': {
|
|
40
|
+
purpose: 'Landing page introducing the product and converting visitors',
|
|
41
|
+
elements: ['Hero section with value proposition', 'Feature highlights grid', 'Social proof/testimonials', 'Pricing preview', 'Call-to-action buttons', 'Footer with links'],
|
|
42
|
+
components: ['Hero', 'FeatureGrid', 'TestimonialCarousel', 'PricingPreview', 'Button', 'Footer'],
|
|
43
|
+
userFlow: 'Visitor lands on page -> Reads value proposition -> Explores features -> Clicks CTA to sign up'
|
|
44
|
+
},
|
|
45
|
+
'Dashboard': {
|
|
46
|
+
purpose: 'Main user interface showing key metrics and quick actions after login',
|
|
47
|
+
elements: ['Welcome message', 'Metrics cards with key stats', 'Recent activity feed', 'Quick action buttons', 'Navigation sidebar'],
|
|
48
|
+
components: ['Card', 'Chart', 'Table', 'Button', 'Sidebar'],
|
|
49
|
+
userFlow: 'User logs in -> Views overview metrics -> Takes quick actions or navigates to detailed sections'
|
|
50
|
+
},
|
|
51
|
+
'Settings': {
|
|
52
|
+
purpose: 'User profile and account preferences management',
|
|
53
|
+
elements: ['Profile information form', 'Account preferences', 'Notification settings', 'Security settings', 'Danger zone (delete account)'],
|
|
54
|
+
components: ['Form', 'Input', 'Toggle', 'Select', 'Button', 'Alert'],
|
|
55
|
+
userFlow: 'User navigates to settings -> Modifies preferences -> Saves changes'
|
|
56
|
+
},
|
|
57
|
+
'404': {
|
|
58
|
+
purpose: 'Error page for routes that do not exist',
|
|
59
|
+
elements: ['Friendly error message', 'Illustration', 'Home navigation link', 'Search option'],
|
|
60
|
+
components: ['ErrorMessage', 'Illustration', 'Link', 'SearchInput'],
|
|
61
|
+
userFlow: 'User hits invalid URL -> Sees error page -> Navigates back to home or searches'
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Auth pages
|
|
65
|
+
'Login': {
|
|
66
|
+
purpose: 'Authenticate existing users to access their account',
|
|
67
|
+
elements: ['Email input field', 'Password input field', 'Remember me checkbox', 'Login button', 'Forgot password link', 'Sign up redirect link'],
|
|
68
|
+
components: ['Form', 'Input', 'Checkbox', 'Button', 'Link'],
|
|
69
|
+
userFlow: 'User enters credentials -> Submits form -> Redirects to dashboard on success'
|
|
70
|
+
},
|
|
71
|
+
'Signup': {
|
|
72
|
+
purpose: 'Register new users and create their account',
|
|
73
|
+
elements: ['Name input field', 'Email input field', 'Password input field', 'Confirm password field', 'Terms acceptance checkbox', 'Sign up button', 'Login redirect link'],
|
|
74
|
+
components: ['Form', 'Input', 'Checkbox', 'Button', 'Link'],
|
|
75
|
+
userFlow: 'User fills registration form -> Submits -> Email verification sent -> Redirects to onboarding'
|
|
76
|
+
},
|
|
77
|
+
'Forgot Password': {
|
|
78
|
+
purpose: 'Allow users to request password reset via email',
|
|
79
|
+
elements: ['Email input field', 'Submit button', 'Back to login link', 'Success message'],
|
|
80
|
+
components: ['Form', 'Input', 'Button', 'Link', 'Alert'],
|
|
81
|
+
userFlow: 'User enters email -> Submits request -> Receives reset link via email'
|
|
82
|
+
},
|
|
83
|
+
'Reset Password': {
|
|
84
|
+
purpose: 'Set a new password after clicking reset link',
|
|
85
|
+
elements: ['New password input', 'Confirm password input', 'Submit button', 'Password requirements hint'],
|
|
86
|
+
components: ['Form', 'Input', 'Button', 'Alert'],
|
|
87
|
+
userFlow: 'User clicks email link -> Enters new password -> Submits -> Redirects to login'
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Payment pages
|
|
91
|
+
'Pricing': {
|
|
92
|
+
purpose: 'Display subscription plans and pricing options for comparison',
|
|
93
|
+
elements: ['Plan cards with pricing', 'Feature comparison table', 'Toggle for monthly/annual', 'CTA buttons per plan', 'FAQ section'],
|
|
94
|
+
components: ['PricingCard', 'Badge', 'Toggle', 'Button', 'Accordion'],
|
|
95
|
+
userFlow: 'User views plans -> Compares features -> Selects plan -> Proceeds to checkout'
|
|
96
|
+
},
|
|
97
|
+
'Checkout': {
|
|
98
|
+
purpose: 'Complete purchase with payment details',
|
|
99
|
+
elements: ['Order summary', 'Payment form', 'Billing address form', 'GST number input', 'Coupon code input', 'Pay button'],
|
|
100
|
+
components: ['Form', 'Input', 'Card', 'Button', 'Alert'],
|
|
101
|
+
userFlow: 'User reviews order -> Enters payment details -> Submits -> Payment processed -> Confirmation'
|
|
102
|
+
},
|
|
103
|
+
'Billing History': {
|
|
104
|
+
purpose: 'View past invoices and payment history',
|
|
105
|
+
elements: ['Invoice list table', 'Download invoice buttons', 'Filter by date', 'Payment status badges'],
|
|
106
|
+
components: ['Table', 'Button', 'Badge', 'DatePicker', 'Pagination'],
|
|
107
|
+
userFlow: 'User views invoice list -> Filters by date if needed -> Downloads specific invoice'
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// Multi-tenancy pages
|
|
111
|
+
'Team Settings': {
|
|
112
|
+
purpose: 'Manage organization settings and details',
|
|
113
|
+
elements: ['Organization name and logo', 'Organization details form', 'Team member list', 'Billing settings', 'Delete organization option'],
|
|
114
|
+
components: ['Form', 'Input', 'Avatar', 'Table', 'Button', 'Alert'],
|
|
115
|
+
userFlow: 'Admin navigates to settings -> Updates org details -> Saves changes'
|
|
116
|
+
},
|
|
117
|
+
'Invite Members': {
|
|
118
|
+
purpose: 'Invite new team members to the organization',
|
|
119
|
+
elements: ['Email input field', 'Role selector', 'Send invite button', 'Pending invitations list', 'Resend/cancel invite options'],
|
|
120
|
+
components: ['Form', 'Input', 'Select', 'Button', 'Table', 'Badge'],
|
|
121
|
+
userFlow: 'Admin enters email -> Selects role -> Sends invite -> Manages pending invites'
|
|
122
|
+
},
|
|
123
|
+
'Role Management': {
|
|
124
|
+
purpose: 'Manage team member roles and permissions',
|
|
125
|
+
elements: ['Team members table', 'Role dropdown per member', 'Remove member option', 'Role descriptions'],
|
|
126
|
+
components: ['Table', 'Select', 'Button', 'Badge', 'Dialog'],
|
|
127
|
+
userFlow: 'Admin views members -> Changes roles as needed -> Removes members if necessary'
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
// Credits pages
|
|
131
|
+
'Usage Dashboard': {
|
|
132
|
+
purpose: 'Monitor credit usage and consumption patterns',
|
|
133
|
+
elements: ['Current balance display', 'Usage chart over time', 'Usage breakdown by feature', 'Low balance warning', 'Purchase credits CTA'],
|
|
134
|
+
components: ['Card', 'Chart', 'Table', 'Alert', 'Button', 'Progress'],
|
|
135
|
+
userFlow: 'User views balance -> Checks usage history -> Clicks to purchase if low'
|
|
136
|
+
},
|
|
137
|
+
'Purchase Credits': {
|
|
138
|
+
purpose: 'Buy additional credits for the account',
|
|
139
|
+
elements: ['Credit package options', 'Custom amount input', 'Payment summary', 'Purchase button', 'Volume discounts display'],
|
|
140
|
+
components: ['Card', 'Input', 'Button', 'Badge', 'Alert'],
|
|
141
|
+
userFlow: 'User selects package -> Reviews total -> Completes payment -> Credits added'
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
// GST pages
|
|
145
|
+
'Invoice Settings': {
|
|
146
|
+
purpose: 'Configure GST and invoice details for Indian billing',
|
|
147
|
+
elements: ['GST number input', 'Business name', 'Business address', 'State selector', 'Invoice preferences'],
|
|
148
|
+
components: ['Form', 'Input', 'Select', 'Button', 'Alert'],
|
|
149
|
+
userFlow: 'User enters GST details -> Saves settings -> Future invoices use these details'
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// Admin pages
|
|
153
|
+
'Admin Panel': {
|
|
154
|
+
purpose: 'Superadmin dashboard for managing the entire platform',
|
|
155
|
+
elements: ['Platform metrics', 'User management table', 'Revenue overview', 'System health status', 'Recent activity log'],
|
|
156
|
+
components: ['Card', 'Chart', 'Table', 'Badge', 'Button', 'Tabs'],
|
|
157
|
+
userFlow: 'Admin views platform stats -> Manages users -> Monitors system health'
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Derive list of pages based on feature flags
|
|
163
|
+
* @param {object} featuresConfig - Object with feature flags (multiTenancy, credits, etc.)
|
|
164
|
+
* @returns {string[]} - Sorted array of unique page names
|
|
165
|
+
*/
|
|
166
|
+
function derivePages(featuresConfig) {
|
|
167
|
+
const pages = new Set();
|
|
168
|
+
|
|
169
|
+
// Core pages (always included)
|
|
170
|
+
PAGE_TEMPLATES.core.forEach(page => pages.add(page));
|
|
171
|
+
|
|
172
|
+
// Auth pages (always included)
|
|
173
|
+
PAGE_TEMPLATES.auth.forEach(page => pages.add(page));
|
|
174
|
+
|
|
175
|
+
// Payment pages (always included)
|
|
176
|
+
PAGE_TEMPLATES.payments.forEach(page => pages.add(page));
|
|
177
|
+
|
|
178
|
+
// GST pages (always included for India-first SaaS)
|
|
179
|
+
PAGE_TEMPLATES.gst.forEach(page => pages.add(page));
|
|
180
|
+
|
|
181
|
+
// Admin pages (always included)
|
|
182
|
+
PAGE_TEMPLATES.admin.forEach(page => pages.add(page));
|
|
183
|
+
|
|
184
|
+
// Multi-tenancy pages (optional)
|
|
185
|
+
if (featuresConfig && featuresConfig.multiTenancy) {
|
|
186
|
+
PAGE_TEMPLATES.multiTenancy.forEach(page => pages.add(page));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Credits pages (optional)
|
|
190
|
+
if (featuresConfig && featuresConfig.credits) {
|
|
191
|
+
PAGE_TEMPLATES.credits.forEach(page => pages.add(page));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Convert to array and sort alphabetically
|
|
195
|
+
return Array.from(pages).sort();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get detailed page information for Lovable prompt generation
|
|
200
|
+
* @param {string} pageName - Name of the page
|
|
201
|
+
* @returns {{ purpose: string, elements: string[], components: string[], userFlow: string }}
|
|
202
|
+
*/
|
|
203
|
+
function getPageDetails(pageName) {
|
|
204
|
+
// Return specific details if available
|
|
205
|
+
if (PAGE_DETAILS[pageName]) {
|
|
206
|
+
return PAGE_DETAILS[pageName];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Return generic fallback for custom/unknown pages
|
|
210
|
+
return {
|
|
211
|
+
purpose: `${pageName} page functionality`,
|
|
212
|
+
elements: ['Main content area', 'Navigation elements', 'Action buttons'],
|
|
213
|
+
components: ['Card', 'Button', 'Form'],
|
|
214
|
+
userFlow: 'User navigates to page -> Interacts with content -> Completes action'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get all page names from a specific category
|
|
220
|
+
* @param {string} category - Category name (core, auth, payments, etc.)
|
|
221
|
+
* @returns {string[]} - Array of page names in that category
|
|
222
|
+
*/
|
|
223
|
+
function getPagesInCategory(category) {
|
|
224
|
+
return PAGE_TEMPLATES[category] || [];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check if a page is optional (depends on feature flags)
|
|
229
|
+
* @param {string} pageName - Name of the page
|
|
230
|
+
* @returns {boolean} - True if page is optional
|
|
231
|
+
*/
|
|
232
|
+
function isOptionalPage(pageName) {
|
|
233
|
+
const optionalPages = [
|
|
234
|
+
...PAGE_TEMPLATES.multiTenancy,
|
|
235
|
+
...PAGE_TEMPLATES.credits
|
|
236
|
+
];
|
|
237
|
+
return optionalPages.includes(pageName);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
module.exports = {
|
|
241
|
+
PAGE_TEMPLATES,
|
|
242
|
+
PAGE_DETAILS,
|
|
243
|
+
derivePages,
|
|
244
|
+
getPageDetails,
|
|
245
|
+
getPagesInCategory,
|
|
246
|
+
isOptionalPage
|
|
247
|
+
};
|