create-rykira-app 1.0.1 → 2.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/bin/cli.js CHANGED
@@ -1,156 +1,162 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
- import inquirer from 'inquirer';
5
- import fs from 'fs-extra';
6
- import path from 'path';
7
- import { fileURLToPath } from 'url';
8
- import chalk from 'chalk';
9
- import ora from 'ora';
10
- import Handlebars from 'handlebars';
11
- import { createRequire } from 'module';
12
-
13
- const require = createRequire(import.meta.url);
14
- const pkg = require('../package.json');
15
-
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = path.dirname(__filename);
18
-
19
- const program = new Command();
20
-
21
- program
22
- .name('create-rykira-app')
23
- .description('Scaffold a new Rykira Starter Package project')
24
- .version(pkg.version)
25
- .argument('[project-directory]', 'Directory to create the project in')
26
- .action(async (projectDirectory) => {
27
- console.log(chalk.bold.blue('🚀 Welcome to Rykira Starter App Generator!'));
28
-
29
- let targetDir = projectDirectory;
30
-
31
- if (!targetDir) {
32
- const answers = await inquirer.prompt([
33
- {
34
- type: 'input',
35
- name: 'projectName',
36
- message: 'What is the name of your project?',
37
- default: 'my-rykira-app',
38
- validate: (input) => {
39
- if (/^([a-z0-9\-\_\.]+)$/.test(input)) return true;
40
- return 'Project name may only include lower-case letters, numbers, dashes, underscores, and dots.';
41
- },
42
- },
43
- ]);
44
- targetDir = answers.projectName;
45
- }
46
-
47
- const rootDir = path.resolve(process.cwd(), targetDir);
48
-
49
- if (fs.existsSync(rootDir)) {
50
- console.error(chalk.red(`Error: Directory ${targetDir} already exists.`));
51
- process.exit(1);
52
- }
53
-
54
- const promptAnswers = await inquirer.prompt([
55
- {
56
- type: 'input',
57
- name: 'description',
58
- message: 'Project description:',
59
- default: 'A modern full-stack application',
60
- },
61
- {
62
- type: 'input',
63
- name: 'author',
64
- message: 'Author name:',
65
- default: 'Rykira User',
66
- },
67
- {
68
- type: 'confirm',
69
- name: 'includeAdmin',
70
- message: 'Include Admin Panel?',
71
- default: true,
72
- },
73
- {
74
- type: 'confirm',
75
- name: 'includeApi',
76
- message: 'Include Express API?',
77
- default: true,
78
- },
79
- ]);
80
-
81
- const spinner = ora(`Creating project in ${chalk.green(rootDir)}...`).start();
82
-
83
- try {
84
- // Copy template files
85
- const templateDir = path.resolve(__dirname, '../template');
86
- await fs.copy(templateDir, rootDir, {
87
- filter: (src) => {
88
- // Avoid copying node_modules and build artifacts
89
- if (src.includes('node_modules')) return false;
90
-
91
- const basename = path.basename(src);
92
- return !['.next', '.turbo', 'dist', 'coverage', 'build', '.DS_Store'].includes(basename);
93
- }
94
- });
95
-
96
- // Process Handlebars templates
97
- const packageJsonPath = path.join(rootDir, 'package.json');
98
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
99
- const template = Handlebars.compile(packageJsonContent);
100
- const result = template({
101
- projectName: path.basename(rootDir),
102
- projectDescription: promptAnswers.description,
103
- authorName: promptAnswers.author,
104
- });
105
- await fs.writeFile(packageJsonPath, result);
106
-
107
- // Handle Admin Panel removal
108
- if (!promptAnswers.includeAdmin) {
109
- spinner.text = 'Removing Admin Panel...';
110
- await fs.remove(path.join(rootDir, 'apps/admin'));
111
- await fs.remove(path.join(rootDir, 'infrastructure/docker/Dockerfile.admin'));
112
- // Note: You might need to clean up pnpm-workspace.yaml or turbo.json if strict
113
- }
114
-
115
- // Handle API removal
116
- if (!promptAnswers.includeApi) {
117
- spinner.text = 'Removing Express API...';
118
- await fs.remove(path.join(rootDir, 'apps/api'));
119
- await fs.remove(path.join(rootDir, 'infrastructure/docker/Dockerfile.api'));
120
- }
121
-
122
- // Update Compose files with project name
123
- const composeProdPath = path.join(rootDir, 'infrastructure/docker/compose.prod.yml');
124
- const composeDevPath = path.join(rootDir, 'infrastructure/docker/compose.dev.yml');
125
-
126
- const updateComposeFile = async (filePath) => {
127
- if (fs.existsSync(filePath)) {
128
- const content = await fs.readFile(filePath, 'utf-8');
129
- const composeTemplate = Handlebars.compile(content);
130
- const composeResult = composeTemplate({
131
- projectName: path.basename(rootDir)
132
- });
133
- await fs.writeFile(filePath, composeResult);
134
- }
135
- };
136
-
137
- await updateComposeFile(composeProdPath);
138
- await updateComposeFile(composeDevPath);
139
-
140
-
141
- spinner.succeed(chalk.green('Project created successfully!'));
142
-
143
- console.log('\nNext steps:');
144
- console.log(chalk.cyan(` cd ${targetDir}`));
145
- console.log(chalk.cyan(' pnpm install'));
146
- console.log(chalk.cyan(' cp .env.example .env'));
147
- console.log(chalk.cyan(' pnpm dev'));
148
-
149
- } catch (error) {
150
- spinner.fail(chalk.red('Failed to create project'));
151
- console.error(error);
152
- process.exit(1);
153
- }
154
- });
155
-
156
- program.parse(process.argv);
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import inquirer from 'inquirer';
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import chalk from 'chalk';
9
+ import ora from 'ora';
10
+ import Handlebars from 'handlebars';
11
+ import { createRequire } from 'module';
12
+
13
+ const require = createRequire(import.meta.url);
14
+ const pkg = require('../package.json');
15
+
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+
19
+ const program = new Command();
20
+
21
+ program
22
+ .name('create-rykira-app')
23
+ .description('Scaffold a new Rykira Starter Package project')
24
+ .version(pkg.version)
25
+ .argument('[project-directory]', 'Directory to create the project in')
26
+ .action(async (projectDirectory) => {
27
+ console.log(chalk.bold.blue('🚀 Welcome to Rykira Starter App Generator!'));
28
+
29
+ let targetDir = projectDirectory;
30
+
31
+ if (!targetDir) {
32
+ const answers = await inquirer.prompt([
33
+ {
34
+ type: 'input',
35
+ name: 'projectName',
36
+ message: 'What is the name of your project?',
37
+ default: 'my-rykira-app',
38
+ validate: (input) => {
39
+ if (/^([a-z0-9\-\_\.]+)$/.test(input)) return true;
40
+ return 'Project name may only include lower-case letters, numbers, dashes, underscores, and dots.';
41
+ },
42
+ },
43
+ ]);
44
+ targetDir = answers.projectName;
45
+ }
46
+
47
+ const rootDir = path.resolve(process.cwd(), targetDir);
48
+
49
+ if (fs.existsSync(rootDir)) {
50
+ console.error(chalk.red(`Error: Directory ${targetDir} already exists.`));
51
+ process.exit(1);
52
+ }
53
+
54
+ const promptAnswers = await inquirer.prompt([
55
+ {
56
+ type: 'input',
57
+ name: 'description',
58
+ message: 'Project description:',
59
+ default: 'A modern full-stack application',
60
+ },
61
+ {
62
+ type: 'input',
63
+ name: 'author',
64
+ message: 'Author name:',
65
+ default: 'Rykira User',
66
+ },
67
+ {
68
+ type: 'confirm',
69
+ name: 'includeAdmin',
70
+ message: 'Include Admin Panel?',
71
+ default: true,
72
+ },
73
+ {
74
+ type: 'confirm',
75
+ name: 'includeApi',
76
+ message: 'Include Express API?',
77
+ default: true,
78
+ }
79
+ ]);
80
+
81
+ const spinner = ora(`Creating project in ${chalk.green(rootDir)}...`).start();
82
+
83
+ try {
84
+ // Copy template files
85
+ const templateDir = path.resolve(__dirname, '../template');
86
+ await fs.copy(templateDir, rootDir, {
87
+ filter: (src) => {
88
+ // Avoid copying node_modules and build artifacts
89
+ if (src.includes('node_modules')) return false;
90
+
91
+ const basename = path.basename(src);
92
+ return !['.next', '.turbo', 'dist', 'coverage', 'build', '.DS_Store'].includes(basename);
93
+ }
94
+ });
95
+
96
+ // Process Handlebars templates for package.json
97
+ const packageJsonPath = path.join(rootDir, 'package.json');
98
+ const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
99
+ const template = Handlebars.compile(packageJsonContent);
100
+ const result = template({
101
+ projectName: path.basename(rootDir),
102
+ projectDescription: promptAnswers.description,
103
+ authorName: promptAnswers.author,
104
+ });
105
+ await fs.writeFile(packageJsonPath, result);
106
+
107
+ // Handle Admin Panel removal
108
+ if (!promptAnswers.includeAdmin) {
109
+ spinner.text = 'Removing Admin Panel...';
110
+ await fs.remove(path.join(rootDir, 'apps/admin'));
111
+ // Note: You might need to clean up pnpm-workspace.yaml or turbo.json if strict
112
+ }
113
+
114
+ // Handle API removal
115
+ if (!promptAnswers.includeApi) {
116
+ spinner.text = 'Removing Express API...';
117
+ await fs.remove(path.join(rootDir, 'apps/api'));
118
+ }
119
+
120
+ // Deployment Variables (Forced to Coolify)
121
+ const isCoolify = true;
122
+
123
+ // Update Compose files with project name and deployment logic
124
+ const composeDevPath = path.join(rootDir, 'docker-compose.yml');
125
+
126
+ const updateFileWithContext = async (filePath) => {
127
+ if (fs.existsSync(filePath)) {
128
+ const content = await fs.readFile(filePath, 'utf-8');
129
+ const compiledTemplate = Handlebars.compile(content);
130
+ const compiledResult = compiledTemplate({
131
+ projectName: path.basename(rootDir),
132
+ isCoolify,
133
+ includeAdmin: promptAnswers.includeAdmin,
134
+ includeApi: promptAnswers.includeApi,
135
+ deploymentStrategy: 'coolify'
136
+ });
137
+ await fs.writeFile(filePath, compiledResult);
138
+ }
139
+ };
140
+
141
+ await updateFileWithContext(composeDevPath);
142
+
143
+ // Update README.md
144
+ const readmePath = path.join(rootDir, 'README.md');
145
+ await updateFileWithContext(readmePath);
146
+
147
+ spinner.succeed(chalk.green('Project created successfully!'));
148
+
149
+ console.log('\nNext steps:');
150
+ console.log(chalk.cyan(` cd ${targetDir}`));
151
+ console.log(chalk.cyan(' pnpm install'));
152
+ console.log(chalk.cyan(' cp .env.example .env'));
153
+ console.log(chalk.cyan(' pnpm dev'));
154
+
155
+ } catch (error) {
156
+ spinner.fail(chalk.red('Failed to create project'));
157
+ console.error(error);
158
+ process.exit(1);
159
+ }
160
+ });
161
+
162
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-rykira-app",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "CLI to scaffold Rykira Starter Package",
5
5
  "bin": {
6
6
  "create-rykira-app": "./bin/cli.js"
@@ -1,21 +1,44 @@
1
- # shadcn/ui monorepo template
2
-
3
- This is a Next.js monorepo template with shadcn/ui.
4
-
5
- ## Adding components
6
-
7
- To add components to your app, run the following command at the root of your `web` app:
8
-
9
- ```bash
10
- pnpm dlx shadcn@latest add button -c apps/web
11
- ```
12
-
13
- This will place the ui components in the `packages/ui/src/components` directory.
14
-
15
- ## Using components
16
-
17
- To use the components in your app, import them from the `ui` package.
18
-
19
- ```tsx
20
- import { Button } from "@workspace/ui/components/button";
21
- ```
1
+ # {{projectName}}
2
+
3
+ This is a Next.js monorepo template with shadcn/ui.
4
+
5
+ ## Getting Started
6
+
7
+ 1. Install dependencies:
8
+ ```bash
9
+ pnpm install
10
+ ```
11
+
12
+ 2. Start the development server:
13
+ ```bash
14
+ pnpm dev
15
+ ```
16
+
17
+ ## Deployment
18
+
19
+ This project is configured to be deployed easily using [Coolify](https://coolify.io/).
20
+
21
+ ### Coolify Setup
22
+ 1. Create a project in your Coolify dashboard.
23
+ 2. Connect this Git repository.
24
+ 3. Add a resource for each application (`web`, `admin`, `api`).
25
+ 4. Set the Base Directory to `/` (root) for all of them.
26
+ 5. Set the respective build and start commands for each app (e.g. `pnpm install && pnpm turbo build --filter=web...` and `pnpm --filter web start`).
27
+
28
+ ## Adding components
29
+
30
+ To add components to your app, run the following command at the root of your `web` app:
31
+
32
+ ```bash
33
+ pnpm dlx shadcn@latest add button -c apps/web
34
+ ```
35
+
36
+ This will place the ui components in the `packages/ui/src/components` directory.
37
+
38
+ ## Using components
39
+
40
+ To use the components in your app, import them from the `ui` package.
41
+
42
+ ```tsx
43
+ import { Button } from "@workspace/ui/components/button";
44
+ ```
@@ -5,4 +5,4 @@ nixPkgs = ['nodejs', 'pnpm']
5
5
  cmds = ['pnpm install', 'pnpm turbo build --filter=admin...']
6
6
 
7
7
  [start]
8
- cmd = 'pnpm start:admin'
8
+ cmd = 'pnpm --filter admin start'
@@ -5,4 +5,4 @@ nixPkgs = ['nodejs', 'pnpm']
5
5
  cmds = ['pnpm install', 'pnpm turbo build --filter=web...']
6
6
 
7
7
  [start]
8
- cmd = 'pnpm start:web'
8
+ cmd = 'pnpm --filter web start'
@@ -0,0 +1,19 @@
1
+ version: "3.9"
2
+
3
+ services:
4
+
5
+ postgres:
6
+ image: postgres:16
7
+ container_name: {{projectName}}-postgres-dev
8
+ environment:
9
+ POSTGRES_DB: ${POSTGRES_DB}
10
+ POSTGRES_USER: ${POSTGRES_USER}
11
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
12
+ ports:
13
+ - "5432:5432"
14
+
15
+ redis:
16
+ image: redis:7
17
+ container_name: {{projectName}}-redis-dev
18
+ ports:
19
+ - "6379:6379"
package/deployment.md DELETED
@@ -1,168 +0,0 @@
1
- # Deployment Guide
2
-
3
- This guide covers how to deploy the Rykira Starter Package application using Coolify (automated) or manually using Docker and Traefik on a VPS.
4
-
5
- ## Table of Contents
6
-
7
- - [Prerequisites](#prerequisites)
8
- - [Environment Configuration](#environment-configuration)
9
- - [Option 1: Deploy with Coolify (Recommended)](#option-1-deploy-with-coolify-recommended)
10
- - [Option 2: Manual Deployment (Docker & Traefik)](#option-2-manual-deployment-docker--traefik)
11
- - [Post-Deployment Verification](#post-deployment-verification)
12
- - [Troubleshooting](#troubleshooting)
13
-
14
- ---
15
-
16
- ## Prerequisites
17
-
18
- - **Domain Name**: A domain name pointing to your server IP (e.g., `example.com`, `*.example.com`).
19
- - **VPS/Server**: A server running Ubuntu 22.04/24.04 (minimum 2GB RAM, 2 vCPUs recommended).
20
- - **Git Repository**: Your project pushed to a Git provider (GitHub, GitLab, etc.).
21
-
22
- ---
23
-
24
- ## Environment Configuration
25
-
26
- All deployments require a `.env` file. Use the `.env.example` as a template.
27
-
28
- ### Required Variables
29
-
30
- ```env
31
- # Domain Configuration
32
- DOMAIN=example.com
33
- ACME_EMAIL=admin@example.com
34
-
35
- # Postgres Configuration
36
- POSTGRES_USER=postgres
37
- POSTGRES_PASSWORD=secure_password_here
38
- POSTGRES_DB=rykira
39
-
40
- # Redis Configuration
41
- REDIS_PASSWORD=secure_redis_password_here
42
-
43
- # Database Connection Strings (Internal Docker Network)
44
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
45
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
46
-
47
- # App Secrets
48
- NEXTAUTH_SECRET=generate_a_long_random_string
49
- auth_secret=generate_a_long_random_string
50
- ```
51
-
52
- ---
53
-
54
- ## Option 1: Deploy with Coolify (Recommended)
55
-
56
- Coolify is an open-source, self-hostable Heroku alternative that makes deployment easy.
57
-
58
- ### Step 1: Prepare Your Project
59
- 1. Ensure `nixpacks.toml` files exist in `apps/web`, `apps/admin`, and `apps/api` (included in this template).
60
- 2. Push your code to a GitHub repository.
61
-
62
- ### Step 2: Configure Coolify
63
- 1. **Create a Project** in your Coolify dashboard.
64
- 2. **Add a Resource**: Select **Git Repository** (Private or Public).
65
- 3. **Select Repository**: Choose your project repo.
66
-
67
- ### Step 3: Add Services
68
- You will deploy each app as a separate resource, or use a Docker Compose stack.
69
-
70
- #### Method A: Docker Compose Stack (Easiest)
71
- 1. In Coolify, select **Docker Compose**.
72
- 2. Paste the contents of `infrastructure/docker/compose.prod.yml`.
73
- 3. **IMPORTANT**: Replace `{{projectName}}` with your actual project name in the Compose file content before pasting, or ensure you set it as a variable if Coolify supports it.
74
- 4. Go to **Environment Variables** in Coolify and add all variables from your `.env` file.
75
- 5. Click **Deploy**.
76
-
77
- #### Method B: Individual Services (Nixpacks)
78
- 1. **Web App (`apps/web`)**:
79
- - **Build Pack**: Nixpacks
80
- - **Base Directory**: `/`
81
- - **Build Command**: `pnpm install && pnpm turbo build --filter=web...`
82
- - **Start Command**: `pnpm start:web`
83
- - **Environment Variables**: Add all required envs.
84
- - **Domains**: Set to `https://app.example.com`.
85
-
86
- 2. **API (`apps/api`)**:
87
- - **Build Pack**: Nixpacks
88
- - **Base Directory**: `/`
89
- - **Build Command**: `pnpm install && pnpm turbo build --filter=api...`
90
- - **Start Command**: `node apps/api/dist/index.js`
91
- - **Environment Variables**: Add all required envs.
92
- - **Domains**: Set to `https://api.example.com`.
93
-
94
- 3. **Database & Redis**:
95
- - Use Coolify's **Databases** tab to provision PostgreSQL and Redis.
96
- - Update your App's `DATABASE_URL` and `REDIS_URL` to point to these internal Coolify databases.
97
-
98
- ---
99
-
100
- ## Option 2: Manual Deployment (Docker & Traefik)
101
-
102
- This method gives you full control using standard Docker Compose and Traefik v3 as a reverse proxy.
103
-
104
- ### Step 1: Server Setup
105
- 1. SSH into your server.
106
- 2. Clone your repository:
107
- ```bash
108
- git clone https://github.com/your/repo.git my-app
109
- cd my-app
110
- ```
111
- 3. Run the setup script to install Docker and configure UFW firewall:
112
- ```bash
113
- chmod +x infrastructure/scripts/setup-server.sh
114
- ./infrastructure/scripts/setup-server.sh
115
- ```
116
- *You may need to log out and log back in for Docker group changes to take effect.*
117
-
118
- ### Step 2: Traefik Initialization
119
- 1. Initialize the ACME JSON file for SSL certificates:
120
- ```bash
121
- chmod +x infrastructure/scripts/init-traefik.sh
122
- ./infrastructure/scripts/init-traefik.sh
123
- ```
124
-
125
- ### Step 3: Deploy
126
- 1. Create your `.env` file:
127
- ```bash
128
- cp .env.example .env
129
- nano .env
130
- # Fill in your secrets and domain
131
- ```
132
- 2. Run the deployment script:
133
- ```bash
134
- chmod +x infrastructure/scripts/deploy.sh
135
- ./infrastructure/scripts/deploy.sh
136
- ```
137
-
138
- ### Step 4: Verify
139
- - Check running containers: `docker compose ps`
140
- - View logs: `docker compose logs -f`
141
-
142
- ---
143
-
144
- ## Post-Deployment Verification
145
-
146
- 1. **Check Health**:
147
- - Visit `https://api.example.com/health` (should return JSON status).
148
- 2. **Check SSL**:
149
- - Visit `https://app.example.com` - ensure lock icon is present.
150
- 3. **Database Connection**:
151
- - Verify the API can read/write to the database (try logging in or creating a user).
152
-
153
- ---
154
-
155
- ## Troubleshooting
156
-
157
- ### "Acme.json permission denied"
158
- - Run: `chmod 600 infrastructure/traefik/acme.json`
159
-
160
- ### "Gateway Timeout" (504)
161
- - Check if the app container is running: `docker compose ps`
162
- - Check logs: `docker compose logs web`
163
- - Ensure the port in `compose.prod.yml` matches the app's listening port (default 3000 for web, 4000 for api).
164
-
165
- ### Database Connection Error
166
- - Ensure `DATABASE_URL` is using the container name `postgres` (not `localhost`) if running inside Docker.
167
- - Check if Postgres is healthy: `docker compose ps postgres`
168
-