Skip to content

feat(create with template): add an option to choose a template#16

Merged
kfirstri merged 5 commits intomainfrom
create-from-template
Jan 12, 2026
Merged

feat(create with template): add an option to choose a template#16
kfirstri merged 5 commits intomainfrom
create-from-template

Conversation

@kfirstri
Copy link
Collaborator

Summary

Choose a template from a list to generate a new project

@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.0.1-pr.16.6c1f17f

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.0.1-pr.16.6c1f17f"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.0.1-pr.16.6c1f17f"
  }
}

Preview published to npm registry — try new features instantly!

@claude
Copy link

claude bot commented Jan 12, 2026

Code Review - PR #16: Template-based Project Creation

Summary

This PR introduces a template system for project creation, replacing the simple init command with a more flexible create command that allows users to choose from predefined project templates. The refactoring is well-structured and the feature is a valuable addition.

✅ Strengths

Architecture & Design

  • Good separation of concerns: Template management is cleanly separated into template.ts with clear responsibilities
  • Type safety: Proper Zod schemas for template validation (TemplateSchema, TemplatesConfigSchema)
  • EJS templating: Smart use of EJS for dynamic file generation (only .ejs files are rendered, others are copied)
  • Clean migration path: Renamed initcreate while maintaining similar user experience

Code Quality

  • Improved UX: Using @clack/prompts group for better prompt organization
  • Better abstraction: onPromptCancel handler is more reusable than the previous inline approach
  • Consistent error handling: Maintains the existing error handling pattern with try-catch blocks

⚠️ Issues & Concerns

1. CRITICAL: Missing .env.local file for backend-and-client template

The backend-and-client template is missing the base44/.env.local.ejs file that exists in the backend-only template. This means:

  • The BASE44_CLIENT_ID won't be written to a file in the base44 directory
  • Users would need to manually configure environment variables
  • Inconsistent with the backend-only template

Files affected:

  • templates/backend-and-client/base44/.env.local.ejs (missing)

Recommended fix:

cp templates/backend-only/base44/.env.local.ejs templates/backend-and-client/base44/.env.local.ejs

2. Potential Issue: Duplicate projectId configuration

In the backend-and-client template, the projectId is used in two places:

  • base44/.env.local.ejs (missing, should have BASE44_CLIENT_ID)
  • src/api/base44Client.js.ejs (hardcoded as appId)

This creates potential confusion. The client is using appId directly in code, while the backend convention uses BASE44_CLIENT_ID in env files.

Recommendation: Consider standardizing on one approach:

  • Option A: Use env variable in both (requires bundler support for env vars)
  • Option B: Document this design decision clearly
  • Option C: Only use the client-side hardcoded approach and skip the .env.local file

3. Security Consideration: Exposing projectId in frontend code

The base44Client.js.ejs file hardcodes the projectId:

export const base44 = createClient({
  appId: '<%= projectId %>',
});

Question: Is the projectId considered sensitive? If it's meant to be public (like a Firebase project ID), this is fine. Otherwise, consider documenting security implications.

4. Type Safety: Template type not validated in command

In src/cli/commands/project/create.ts:26, the template selection returns Template type but the value comes from a select prompt. While functionally correct, the type annotation on line 6 ensures type safety:

const template: Template = ...

✅ This is actually fine since the templateOptions map ensures type safety.

5. Error Handling: Partial template rendering failure

If renderTemplate() fails midway (e.g., disk full, permission error), some files may be written while others fail. Consider:

  • Adding rollback logic
  • Or document that users should delete the directory and retry

6. Testing: No tests for new functionality

The PR adds substantial new code but no tests for:

  • listTemplates() function
  • renderTemplate() function
  • createProjectFiles() function
  • Template rendering with EJS

Recommendation: Add tests following the pattern in tests/core/project.test.ts

7. Documentation: Command name change

The command changed from init to create, but:

  • README.md likely needs updating (line 49 references project commands)
  • Users upgrading might be confused by the breaking change
  • Consider keeping init as an alias temporarily

Note: I see in the old code that init had .alias('create'), so the semantic shift is actually aligning the primary command with its alias. Good call, but worth documenting in a changelog.

🔍 Minor Issues

Code Style

  1. Line 59 in create.ts: projectPath || "./" - This fallback is unnecessary since initialValue is set. The prompt will always return a string.

  2. Unused import?: Check if all imports in create.ts are necessary after refactoring.

  3. Comment style: The backend-and-client/base44/config.jsonc.ejs comment mentions "Full-stack template" which is good, but ensure it matches the backend-only template style for consistency.

📋 Testing Checklist

Before merging, verify:

  • base44 create prompts for template selection
  • Backend-only template creates correct file structure with .env.local
  • Backend-and-client template creates correct file structure with .env.local (currently missing)
  • EJS variables are properly rendered in all template files
  • Both templates work end-to-end (entities push, deploy, etc.)
  • Error messages are clear when project already exists
  • TypeScript builds without errors
  • Linter passes
  • Existing tests still pass

🎯 Performance & Security

Performance: ✅ Good - File operations are efficient, no obvious bottlenecks

Security:

  • ✅ Input validation on project name
  • ✅ Path resolution uses resolve() to prevent directory traversal
  • ⚠️ Consider validating template.path to ensure it doesn't escape templates directory

📝 Recommendations Summary

Must fix before merge:

  1. Add templates/backend-and-client/base44/.env.local.ejs file

Should fix:
2. Add tests for template functionality
3. Document projectId exposure in frontend code

Nice to have:
4. Add rollback/cleanup on template rendering failure
5. Update README with new command structure
6. Add template validation to prevent path traversal

Overall Assessment

This is a solid PR that adds valuable functionality. The code quality is good, the architecture is clean, and it follows existing patterns well. The main blocker is the missing .env.local file in the backend-and-client template, which should be a quick fix.

Recommendation: Request changes for the critical .env.local issue, then approve after fix.


🤖 Review by Claude Code

@claude
Copy link

claude bot commented Jan 12, 2026

PR Review: Template-based Project Creation

Thank you for this contribution! This is a solid refactoring that adds template support to the project creation flow.


✅ Strengths

  1. Good Architecture: Clean separation of template listing, rendering, and project creation
  2. Proper Validation: Using Zod schemas for template configuration
  3. EJS Template Handling: Clean logic for rendering .ejs files and copying others
  4. Kebab-case Conversion: Nice UX improvement for project folder names
  5. Consistent Error Handling: Follows existing patterns

🔴 Critical Security Issue

Path Traversal Vulnerability (src/core/project/template.ts:42-54)

  • The renderTemplate function does NOT validate that files from globby stay within the template directory
  • A malicious template could include files like ../../../etc/passwd
  • Must fix before merge: Validate each file path using path.resolve() to ensure destFilePath is within destPath

🐛 High Priority Bugs

  1. Missing Template Directory Validation (src/core/project/template.ts:32)

    • No check if templateDir exists before calling globby
    • Will give cryptic errors if template path is invalid
    • Fix: Add pathExists check with clear error message
  2. Breaking Change: init command removed

    • Old code had initCommand with alias create
    • New code only has createCommand
    • Users expecting base44 init will get unknown command error
    • Recommendation: Add .alias(init) for backwards compatibility

🟡 Medium Priority Issues

  1. Empty Template Handling - silently succeeds if template has no files
  2. Destination Path Validation - does not check if destPath is writable or is a file
  3. EJS Error Context - rendering errors will not show which file failed
  4. Race Condition - mkdir in copyFile/writeFile not atomic if processing files concurrently

🧪 Test Coverage

Missing Tests:

  • No tests for renderTemplate function
  • No tests for listTemplates
  • Existing tests do not cover new template flow

Recommendation: Add test fixture template directory and test the full rendering pipeline


📝 Code Quality Suggestions

  1. TODO Comment (src/cli/commands/project/create.ts:17) - has typo and unclear intent
  2. Type Safety (src/cli/commands/project/create.ts:61) - unnecessary as string cast
  3. Magic Numbers (src/core/project/template.ts:46) - .slice(0, -4) is not self-documenting
  4. Error Messages (src/core/project/create.ts:30) - could provide more guidance

⚡ Performance

  • Files are processed sequentially - consider Promise.all for large templates
  • pathExists checks in writeFile/copyFile could be removed (mkdir recursive: true is idempotent)

🔒 Security Summary

  1. Path Traversal - CRITICAL, must fix
  2. Template Injection - EJS has full JS execution (ok since bundled with CLI)
  3. Project ID Exposure - IDs in client code (ok if public, ensure API validates auth)

🎯 Architecture Notes

  1. Templates bundled with CLI via tsdown - limits extensibility but safe
  2. No template versioning - could be issue if Backend API changes
  3. Command rename from init to create is a breaking change

🚀 Recommended Actions

Must Fix Before Merge:

  1. Fix path traversal vulnerability
  2. Add template directory existence check
  3. Add backwards compatibility: .alias(init)

Should Fix:
4. Add try-catch with file context for EJS rendering
5. Validate destPath is writable
6. Fix or remove TODO comment

Nice to Have:
7. Add comprehensive tests for template rendering
8. Consider parallel file processing
9. Improve error messages


📊 Summary

Category Rating Notes
Code Quality 🟡 Good Clean structure, minor improvements needed
Security 🔴 Needs Work Path traversal must be fixed
Tests 🟡 Moderate Core tested, new features need coverage
Documentation 🟢 Good Clear commits, template docs included
Performance 🟢 Good Fine for typical use, room for optimization

Overall: Solid feature with good architecture. Main blocker is the path traversal security issue. Once fixed, ready to merge!

Great work on this refactoring! Let me know if you have questions about any of the feedback.

@claude
Copy link

claude bot commented Jan 12, 2026

PR Review: Add Template-Based Project Creation

Summary

This PR successfully refactors the project initialization from a simple config generator to a template-based system. The changes are well-structured and follow existing codebase patterns. Overall, this is a solid implementation with a few areas for improvement.

✅ Strengths

  1. Good Architecture: The separation between CLI, core logic, and template handling is clean and maintainable
  2. Consistent Patterns: Error handling matches other commands, uses @clack/prompts, proper Zod schemas
  3. User Experience: The kebab-case path suggestion is a nice touch
  4. Template System: EJS-based rendering is flexible

🐛 Potential Bugs & Issues

Critical

  1. Missing Error Handling for Template Directory (src/core/project/template.ts:32) - No validation that template directory exists before reading files

  2. Empty Description Handling (src/cli/commands/project/create.ts:42-45) - Empty strings are truthy, would be passed as description: "" instead of undefined

Medium Priority

  1. Inconsistent Error Messages (src/core/project/create.ts:30-32) - Uses config file path vs user-provided base path
  2. No Validation of Template Data - projectId from API passed directly to templates without validation

🔒 Security Concerns

  1. Path Traversal Risk (src/core/project/template.ts:35-55) - No explicit sanitization of template paths. Add validation to ensure resolved paths stay within templateDir
  2. EJS Injection (src/core/project/template.ts:48) - User input rendered without sanitization
  3. No Validation of templates.json - File is trusted implicitly

🧪 Test Coverage

Missing Tests for:

  • listTemplates()
  • renderTemplate()
  • createProjectFiles()
  • Edge cases: invalid paths, missing directories, EJS errors, file write failures

This is a significant gap that should be addressed.

📝 Code Quality

Good: Type safety, async handling, error messages, code organization

Areas for Improvement:

  1. Magic strings - use constants for ".ejs" extension
  2. Inconsistent naming - createProjectFiles vs CreateProjectResult
  3. Missing JSDoc comments on public APIs
  4. Command inconsistency - message says "initialized" but should be "created"
  5. Weak prompt validation - consider validating project name characters

🎯 Template Issues

  1. Backend-Only Template is Sparse - only 2 files
  2. Hardcoded Values - package.json should use EJS variables for name/version
  3. Missing .env.local in backend-and-client template

🔄 Migration Path

The removal of init.ts is a breaking change. Consider deprecation notice, migration docs, and that base44 init will break.

📊 Overall Assessment

Category Rating Notes
Code Quality ⭐⭐⭐⭐ Well-structured
Bug Risk ⚠️ Medium Edge cases not handled
Security ⚠️ Medium Path traversal and injection risks
Performance ⭐⭐⭐⭐⭐ Good for current scale
Test Coverage ⭐⭐ Needs significant additions
Documentation ⭐⭐⭐ Could use more inline docs

✅ Recommendations

Must Fix (P0)

  1. Add path validation to prevent traversal attacks
  2. Handle missing template directories gracefully
  3. Add basic tests for template rendering and project creation

Should Fix (P1)

  1. Fix empty description handling
  2. Sanitize user input before EJS rendering
  3. Update backend-and-client template to use project name in package.json
  4. Add .env.local.ejs to backend-and-client template
  5. Fix "initialized" to "created" wording

Nice to Have (P2)

  1. Add template data validation
  2. Improve error messages with more context
  3. Add JSDoc comments to public APIs
  4. Consider caching templates.json
  5. Add project name validation
  6. Expand backend-only template

Great work overall! The template system is a solid foundation. Once the security and testing gaps are addressed, this will be a robust feature. 🚀

@claude
Copy link

claude bot commented Jan 12, 2026

Pull Request Review - PR #16

Summary

This PR replaces the init command with a new create command that allows users to choose from predefined project templates. The implementation adds template support with a backend-only and a full-stack (backend + client) template.


✅ Strengths

  1. Good architectural design - Clean separation between CLI layer (src/cli/commands/project/create.ts) and core logic (src/core/project/create.ts, src/core/project/template.ts)

  2. Improved UX - Using @clack/prompts group feature for better flow, and kebab-case suggestion for project paths is a nice touch

  3. Template system is flexible - The EJS-based template rendering with .ejs suffix stripping is clean and extensible

  4. Proper error handling - Project existence check prevents accidental overwrites


🐛 Potential Bugs & Issues

Critical Issues

1. Race Condition in Directory Creation (src/core/project/create.ts:24-32)
The existing project check uses globby which may not detect partially created projects if the process is interrupted. Additionally, there's a potential race condition between checking and creating:

// Check if project already exists
const existingConfigs = await globby(getProjectConfigPatterns(), {
  cwd: basePath,
  absolute: true,
});

Issue: If basePath doesn't exist yet, this check might fail silently or behave unexpectedly. Consider adding explicit pathExists(basePath) check first.

2. Template Rendering Error Handling (src/core/project/template.ts:41-55)
The template rendering loop lacks error recovery. If one file fails to copy/render partway through, you'll have a partially created project with no cleanup:

for (const file of files) {
  const srcPath = join(templateDir, file);
  // No try-catch, no rollback mechanism
}

Recommendation: Wrap in try-catch and implement cleanup on failure, or consider creating in a temp directory first and moving on success.

3. Missing Path Validation (src/cli/commands/project/create.ts:47-54)
The project path validation only checks for empty string, but doesn't validate:

  • Path doesn't contain invalid characters
  • Parent directory exists or is creatable
  • User has write permissions

4. Template Path Injection Risk (src/core/project/template.ts:32)

const templateDir = join(getTemplatesDir(), template.path);

If template.path contains .. or absolute paths, this could potentially read from unintended locations. While template comes from parsed JSON, add validation:

if (template.path.includes('..') || isAbsolute(template.path)) {
  throw new Error('Invalid template path');
}

Minor Issues

5. .ejs File Replacement is Brittle (src/core/project/template.ts:46)

const destFile = file.replace(".ejs", "");

This would incorrectly handle a file like my.ejs.backup.ejsmy.ejs.backup. Use:

const destFile = file.replace(/\.ejs$/, "");

6. Empty Description Handling Inconsistency
In src/cli/commands/project/create.ts:68-69, empty strings are converted to undefined, but the prompt allows empty input. Consider trimming and checking in the validation function instead.

7. Missing Type Assertion Safety (src/cli/commands/project/create.ts:61)

const resolvedPath = resolve(projectPath as string);

The as string assertion assumes the prompt returns a string, but prompts can return symbol on cancel. The onCancel handler should prevent this, but consider defensive coding:

if (typeof projectPath !== 'string') {
  throw new Error('Invalid project path');
}

🔒 Security Concerns

  1. EJS Template Injection: The EJS templates receive user-controlled input (name, description). While EJS escapes by default with <%=, ensure templates don't use <%- (unescaped output) for these fields.

  2. Project ID Trust: The projectId from the API (src/core/project/create.ts:36) is used directly in templates without validation. Verify the API sanitizes this value.

  3. File System Traversal: The copyFile and writeFile functions create directories recursively. An attacker-controlled template could potentially create files outside the intended directory via ../../ in filenames from globby.


⚡ Performance Considerations

  1. Sequential File Processing (src/core/project/template.ts:41-55)
    Files are processed sequentially. For templates with many files, consider parallel processing:
await Promise.all(files.map(async (file) => { /* process */ }));
  1. Unnecessary JSON Parsing: readJsonFile is called for templates.json every time listTemplates() is invoked. Consider caching this result.

  2. Multiple Globby Calls: The project existence check does a glob which could be slow in large directories. Consider checking for specific file existence instead.


🧪 Test Coverage

Missing Tests - Critical gap:

  • ❌ No tests for the new createProjectFiles function
  • ❌ No tests for renderTemplate
  • ❌ No tests for listTemplates
  • ❌ No integration tests for the template creation flow
  • ❌ No tests for error cases (invalid template, file system errors, etc.)

The only existing test file (tests/core/project.test.ts) tests readProjectConfig, which is not affected by this PR.

Recommendations:

  1. Add unit tests for src/core/project/create.ts
  2. Add unit tests for src/core/project/template.ts
  3. Add integration tests that create projects from templates in a temp directory
  4. Test error scenarios: missing templates, invalid paths, permission errors
  5. Test both templates (backend-only and backend-and-client)

📝 Code Quality & Best Practices

Good Practices

  • ✅ Consistent TypeScript usage with proper interfaces
  • ✅ Good use of Zod for schema validation
  • ✅ Proper async/await patterns
  • ✅ Clear function naming and organization

Improvements Needed

1. Magic String in template.path
The .ejs extension is hardcoded in multiple places. Consider a constant:

const TEMPLATE_EXTENSION = '.ejs';

2. Missing JSDoc Comments
Functions like createProjectFiles and renderTemplate lack documentation explaining their behavior, especially error cases.

3. Inconsistent Naming

  • Function is called createProjectFiles but returns CreateProjectResult with just projectDir
  • Consider renaming to createProjectFromTemplate for clarity

4. Prompt Utils Refactoring (src/cli/utils/prompts.ts)
The removal of textPrompt wrapper in favor of onPromptCancel is good, but the file comment could be more descriptive about the usage pattern.

5. Type Safety
The template object in src/cli/commands/project/create.ts:25 comes from prompts with as Template assertion (implicit). Ensure type safety at the prompt level.


📋 Additional Recommendations

  1. Add Template Validation: Validate template structure on listTemplates() - check that directories exist and required files are present.

  2. Improve Error Messages: When template rendering fails, provide specific information about which file failed and why.

  3. Add Dry Run Option: Consider adding a --dry-run flag to preview what will be created without actually creating it.

  4. Template Version Management: Consider adding a version field to templates for future migration support.

  5. Documentation: Ensure the change from init to create is documented, and add a migration guide for users.

  6. Backward Compatibility: Consider keeping init as an alias for create with the backend-only template as default for backward compatibility.


🎯 Verdict

This is a solid feature addition with good architecture, but should not be merged without addressing:

  1. Blocker: Add comprehensive test coverage
  2. Blocker: Fix the partial project creation issue (error handling + rollback)
  3. ⚠️ Important: Add path validation and sanitization
  4. ⚠️ Important: Add security checks for template path traversal

The template system design is sound and extensible. Once the critical issues are addressed and tests are added, this will be a valuable improvement to the CLI.


Overall Assessment: 🟡 Needs Work - Good foundation, but requires tests and bug fixes before merge.

@claude
Copy link

claude bot commented Jan 12, 2026

PR Review: Template-based Project Creation

Summary

This PR successfully refactors the project initialization system from a simple config+env generation to a flexible template-based approach. The implementation is solid with good separation of concerns, but there are several areas that need attention before merging.


Critical Issues

1. Security: Missing Path Traversal Validation in User Input 🔴

Location: src/cli/commands/project/create.ts:61

The projectPath provided by the user is resolved directly without validation:

const resolvedPath = resolve(projectPath as string);

While renderTemplate() validates the template path (line 33 of template.ts), there's no validation that the user-provided projectPath doesn't contain path traversal attempts or point to sensitive system directories.

Recommendation:

// Add validation before resolve
if (projectPath.includes('..') || isAbsolute(projectPath) && !projectPath.startsWith(process.cwd())) {
  throw new Error('Invalid project path');
}
const resolvedPath = resolve(projectPath as string);

2. API Call Before File System Check 🟡

Location: src/core/project/create.ts:36

The code creates a project via API before checking if the destination path is writable or if template rendering will succeed. If template rendering fails, you'll have orphaned projects in the database.

Recommendation: Reverse the order or use a transaction pattern:

// Validate template can be rendered first (dry-run or path checks)
await validateTemplateAccess(template);

// Then create the project
const { projectId } = await createProject(name, description);

// Then render with rollback on failure
try {
  await renderTemplate(template, basePath, { name, description, projectId });
} catch (error) {
  // Consider: await deleteProject(projectId); // rollback
  throw error;
}

Code Quality Issues

3. Missing Error Handling in Template Rendering 🟡

Location: src/core/project/template.ts:46-65

The loop processes template files but doesn't handle partial failures well. If file 50 out of 100 fails, you get a partially created project with no cleanup.

Recommendation:

  • Add cleanup logic to remove partially created files on error
  • Or use a two-phase commit: copy to temp dir first, then move atomically

4. Type Assertion Could Be Avoided 🟡

Location: src/cli/commands/project/create.ts:61

const resolvedPath = resolve(projectPath as string);

The group() return type should be properly typed instead of using as string. The template is already typed correctly, but projectPath isn't.

5. Empty Template Files 🟡

Location: templates/backend-only/base44/.env.local.ejs (0 bytes)

The backend-only template has empty .env.local.ejs file. This might be intentional, but:

  • Should it include the projectId like the old template?
  • If intentionally empty, consider not including it or adding a comment explaining why

6. Inconsistent Naming: "Project" vs "App" 🔵

Location: Multiple files

  • User-facing: "project" (createCommand, createProject)
  • API responses: projectId
  • Schema: AppConfig, AppConfigSchema
  • Comments: "app ID" (line 35 of create.ts)

Recommendation: Standardize terminology throughout the codebase.


Missing Test Coverage

7. No Tests for New Functionality 🔴

The PR adds significant new functionality but doesn't update tests:

  • No tests for listTemplates()
  • No tests for renderTemplate()
  • No tests for createProjectFiles()
  • No tests for the EJS rendering logic
  • No tests for path traversal protection

Existing test file (tests/core/project.test.ts) only covers readProjectConfig().

Recommendation: Add comprehensive tests:

describe("Template System", () => {
  describe("listTemplates", () => {
    it("returns all available templates");
    it("validates template schema");
  });
  
  describe("renderTemplate", () => {
    it("renders .ejs files correctly");
    it("copies non-.ejs files");
    it("rejects path traversal attempts");
    it("handles missing template directory");
    it("cleans up on render failure");
  });
  
  describe("createProjectFiles", () => {
    it("creates project with backend-only template");
    it("creates project with backend-and-client template");
    it("rejects duplicate project in same location");
    it("handles API failures gracefully");
  });
});

Performance Considerations

8. Sequential File Processing 🔵

Location: src/core/project/template.ts:46-65

Files are processed sequentially in a for loop. For templates with many files (backend-and-client has 33 files), this could be slow.

Recommendation: Consider parallel processing:

await Promise.all(files.map(async (file) => {
  // ... processing logic
}));

Though be careful with file system pressure - might want to batch in groups of 10-20.


Best Practices & Polish

9. Missing JSDoc for Public APIs 🔵

  • listTemplates() - should document return value format
  • createProjectFiles() - should document what happens on failure
  • Consider adding examples in JSDoc

10. Template Validation 🟡

Location: src/core/project/template.ts:15-19

listTemplates() validates the JSON schema but doesn't verify that template directories actually exist.

Recommendation:

export async function listTemplates(): Promise<Template[]> {
  const configPath = join(getTemplatesDir(), "templates.json");
  const parsed = await readJsonFile(configPath);
  const result = TemplatesConfigSchema.parse(parsed);
  
  // Verify each template directory exists
  for (const template of result.templates) {
    const templateDir = join(getTemplatesDir(), template.path);
    if (!(await pathExists(templateDir))) {
      throw new Error(`Template directory not found: ${template.path}`);
    }
  }
  
  return result.templates;
}

11. Consider Adding a .env.local to Backend-Only Template 🔵

The old init command created a .env.local with the projectId. The new backend-only template has an empty .env.local.ejs. Should it include:

BASE44_PROJECT_ID=<%= projectId %>

Positive Highlights ✅

  1. Clean Architecture: Good separation between CLI layer (create.ts), core logic (create.ts, template.ts), and configuration (schema.ts)

  2. Security-Conscious: The path traversal check in renderTemplate() (line 33) is excellent

  3. User Experience: The kebab-case suggestion for project paths (line 48) is a nice UX touch

  4. Type Safety: Good use of Zod for runtime validation of template configuration

  5. Backward Compatibility Consideration: Removing the init alias helps with the transition to create

  6. Template System Design: The .ejs-based template system is flexible and easy to extend


Recommendations Summary

Must Fix Before Merge:

  1. Add path validation for user-provided projectPath
  2. Add test coverage for new template functionality
  3. Fix the API-before-filesystem-check issue
  4. Clarify/fix empty backend-only .env.local.ejs file

Should Fix:
5. Add cleanup logic for partial template rendering failures
6. Add template directory existence validation
7. Remove type assertion for projectPath

Nice to Have:
8. Add JSDoc documentation
9. Consider parallel file processing for performance
10. Standardize project/app terminology


Verdict

This is a well-structured refactor that sets up a good foundation for template-based project creation. However, the security issue with path validation and lack of test coverage are blockers. Once those are addressed, this will be ready to merge.

Estimated effort to address critical issues: 2-3 hours

@kfirstri kfirstri merged commit b488f5e into main Jan 12, 2026
5 checks passed
@kfirstri kfirstri deleted the create-from-template branch January 12, 2026 15:00
@github-project-automation github-project-automation bot moved this from Backlog to Done in CLI Development Jan 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant