create-okjt-app 0.1.0 → 0.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.
- package/README.md +48 -48
- package/bin/create-okjt-app.mjs +88 -88
- package/package.json +29 -29
- package/src/answers.mjs +93 -93
- package/src/create.mjs +132 -132
- package/src/palette.mjs +42 -42
- package/src/templates/backend.mjs +828 -837
- package/src/templates/frontend.mjs +877 -877
- package/src/templates/root.mjs +145 -137
package/src/templates/root.mjs
CHANGED
|
@@ -1,137 +1,145 @@
|
|
|
1
|
-
/** The project's root: README, .gitignore, and the GitHub workflow (tests, then deploy). */
|
|
2
|
-
import { FEATURES, PRESETS } from '../answers.mjs';
|
|
3
|
-
|
|
4
|
-
export function rootFiles(p) {
|
|
5
|
-
return {
|
|
6
|
-
'README.md': readme(p),
|
|
7
|
-
'.gitignore': 'node_modules/\n.DS_Store\n.idea/\n.vscode/\n',
|
|
8
|
-
'.github/workflows/deploy.yml': workflow(p),
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function readme(p) {
|
|
13
|
-
const w = p.workspace;
|
|
14
|
-
const features = Object.entries(p.features).filter(([, on]) => on).map(([f]) => FEATURES[f]);
|
|
15
|
-
return `# ${p.name}
|
|
16
|
-
|
|
17
|
-
${p.tagline}
|
|
18
|
-
|
|
19
|
-
Made with \`create-okjt-app\`: a Laravel API (\`backend/\`) on
|
|
20
|
-
[okjt/laravel-kit](https://packagist.org/packages/okjt/laravel-kit) and a React
|
|
21
|
-
app (\`frontend/\`) on \`@okjt/site\` and \`@okjt/dashboard\`.
|
|
22
|
-
|
|
23
|
-
* **Roles:** \`${p.preset}\`: ${PRESETS[p.preset]}
|
|
24
|
-
* **What people work on together:** ${w.plural} (\`${w.Model}\`, header \`X-Workspace\`)
|
|
25
|
-
* **Features:** ${features.length ? features.join(', ') : 'the essentials (sign-in, two-step verification, sharing, version history, notifications)'}
|
|
26
|
-
|
|
27
|
-
## Run it on your computer
|
|
28
|
-
|
|
29
|
-
\`\`\`bash
|
|
30
|
-
cd backend
|
|
31
|
-
php artisan migrate --seed # the first user: OKJT_ADMIN_EMAIL / OKJT_ADMIN_PASSWORD in .env
|
|
32
|
-
php artisan serve # the API on http://127.0.0.1:8000
|
|
33
|
-
\`\`\`
|
|
34
|
-
|
|
35
|
-
\`\`\`bash
|
|
36
|
-
cd frontend
|
|
37
|
-
npm run dev # the app on http://localhost:5173 (it calls the API through /api)
|
|
38
|
-
\`\`\`
|
|
39
|
-
|
|
40
|
-
Emails (verification, invitations) go to \`backend/storage/logs/laravel.log\`
|
|
41
|
-
until \`MAIL_*\` is set in \`backend/.env\`.
|
|
42
|
-
|
|
43
|
-
## Where things are
|
|
44
|
-
|
|
45
|
-
| What | Where |
|
|
46
|
-
|---|---|
|
|
47
|
-
| Colours and fonts | \`frontend/okjt.config.js\` (\`npm run theme\` writes \`src/okjt-theme.css\`) |
|
|
48
|
-
| Public pages: words, links, footer, SEO | \`frontend/src/site.config.jsx\`, \`frontend/src/pages/Home.jsx\` |
|
|
49
|
-
| Dashboard: sidebar, roles, modules | \`frontend/src/dashboard.config.js\` |
|
|
50
|
-
| Roles, messages, features on the server | \`backend/config/okjt.php\` (over the kit's \`vendor/okjt/laravel-kit/config/okjt.php\`) |
|
|
51
|
-
| The starter module to copy | Notes: \`backend/app/Models/Note.php\`, \`NoteController.php\`, \`frontend/src/pages/dashboard/Notes.jsx\` |
|
|
52
|
-
|
|
53
|
-
## Add a module
|
|
54
|
-
|
|
55
|
-
1. **Server:** a model with \`BelongsToWorkspace\` and \`RecordsRevisions\` (\`$revisionModule = 'tasks'\`), its migration (with \`${w.foreignKey}\`), a controller, and routes inside the \`auth:sanctum\` group of \`routes/api.php\`.
|
|
56
|
-
2. **App:** a page in \`src/pages/dashboard/\`, its route in \`App.jsx\`, a sidebar item and a \`MODULES\` entry in \`dashboard.config.js\`.
|
|
57
|
-
|
|
58
|
-
## Deploy (deploy-kit, about 30 minutes)
|
|
59
|
-
|
|
60
|
-
Pushing to \`main\` runs the tests, then deploys to the VPS through
|
|
61
|
-
[deploy-kit](https://github.com/Juniortambo2628/OKJT/tree/main/deploy-kit).
|
|
62
|
-
Once:
|
|
63
|
-
|
|
64
|
-
1. **Hestia:** add the domain \`${p.domain}\` and a MySQL
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
\`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
on
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
run:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
1
|
+
/** The project's root: README, .gitignore, and the GitHub workflow (tests, then deploy). */
|
|
2
|
+
import { FEATURES, PRESETS } from '../answers.mjs';
|
|
3
|
+
|
|
4
|
+
export function rootFiles(p) {
|
|
5
|
+
return {
|
|
6
|
+
'README.md': readme(p),
|
|
7
|
+
'.gitignore': 'node_modules/\n.DS_Store\n.idea/\n.vscode/\n',
|
|
8
|
+
'.github/workflows/deploy.yml': workflow(p),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function readme(p) {
|
|
13
|
+
const w = p.workspace;
|
|
14
|
+
const features = Object.entries(p.features).filter(([, on]) => on).map(([f]) => FEATURES[f]);
|
|
15
|
+
return `# ${p.name}
|
|
16
|
+
|
|
17
|
+
${p.tagline}
|
|
18
|
+
|
|
19
|
+
Made with \`create-okjt-app\`: a Laravel API (\`backend/\`) on
|
|
20
|
+
[okjt/laravel-kit](https://packagist.org/packages/okjt/laravel-kit) and a React
|
|
21
|
+
app (\`frontend/\`) on \`@okjt/site\` and \`@okjt/dashboard\`.
|
|
22
|
+
|
|
23
|
+
* **Roles:** \`${p.preset}\`: ${PRESETS[p.preset]}
|
|
24
|
+
* **What people work on together:** ${w.plural} (\`${w.Model}\`, header \`X-Workspace\`)
|
|
25
|
+
* **Features:** ${features.length ? features.join(', ') : 'the essentials (sign-in, two-step verification, sharing, version history, notifications)'}
|
|
26
|
+
|
|
27
|
+
## Run it on your computer
|
|
28
|
+
|
|
29
|
+
\`\`\`bash
|
|
30
|
+
cd backend
|
|
31
|
+
php artisan migrate --seed # the first user: OKJT_ADMIN_EMAIL / OKJT_ADMIN_PASSWORD in .env
|
|
32
|
+
php artisan serve # the API on http://127.0.0.1:8000
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
\`\`\`bash
|
|
36
|
+
cd frontend
|
|
37
|
+
npm run dev # the app on http://localhost:5173 (it calls the API through /api)
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
Emails (verification, invitations) go to \`backend/storage/logs/laravel.log\`
|
|
41
|
+
until \`MAIL_*\` is set in \`backend/.env\`.
|
|
42
|
+
|
|
43
|
+
## Where things are
|
|
44
|
+
|
|
45
|
+
| What | Where |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Colours and fonts | \`frontend/okjt.config.js\` (\`npm run theme\` writes \`src/okjt-theme.css\`) |
|
|
48
|
+
| Public pages: words, links, footer, SEO | \`frontend/src/site.config.jsx\`, \`frontend/src/pages/Home.jsx\` |
|
|
49
|
+
| Dashboard: sidebar, roles, modules | \`frontend/src/dashboard.config.js\` |
|
|
50
|
+
| Roles, messages, features on the server | \`backend/config/okjt.php\` (over the kit's \`vendor/okjt/laravel-kit/config/okjt.php\`) |
|
|
51
|
+
| The starter module to copy | Notes: \`backend/app/Models/Note.php\`, \`NoteController.php\`, \`frontend/src/pages/dashboard/Notes.jsx\` |
|
|
52
|
+
|
|
53
|
+
## Add a module
|
|
54
|
+
|
|
55
|
+
1. **Server:** a model with \`BelongsToWorkspace\` and \`RecordsRevisions\` (\`$revisionModule = 'tasks'\`), its migration (with \`${w.foreignKey}\`), a controller, and routes inside the \`auth:sanctum\` group of \`routes/api.php\`.
|
|
56
|
+
2. **App:** a page in \`src/pages/dashboard/\`, its route in \`App.jsx\`, a sidebar item and a \`MODULES\` entry in \`dashboard.config.js\`.
|
|
57
|
+
|
|
58
|
+
## Deploy (deploy-kit, about 30 minutes)
|
|
59
|
+
|
|
60
|
+
Pushing to \`main\` runs the tests, then deploys to the VPS through
|
|
61
|
+
[deploy-kit](https://github.com/Juniortambo2628/OKJT/tree/main/deploy-kit).
|
|
62
|
+
Once:
|
|
63
|
+
|
|
64
|
+
1. **Hestia:** add the domain \`${p.domain}\` (no \`www.\` alias unless its DNS exists) and a MySQL
|
|
65
|
+
database. Hestia prefixes both the database and its user with the account name
|
|
66
|
+
(\`dev_…\`): use the full names from its DB list.
|
|
67
|
+
2. **On the server, as root** (copy the script from an OKJT checkout; from Windows, strip
|
|
68
|
+
carriage returns first: \`sed -i 's/\\r$//' new-site.sh\`):
|
|
69
|
+
\`bash new-site.sh laravel ${p.domain} ${p.slug}\`
|
|
70
|
+
3. **GitHub secrets** on this repository:
|
|
71
|
+
* \`VPS_HOST\`, \`VPS_PORT\`, \`VPS_USER\`, \`VPS_SSH_KEY\`, \`VPS_KNOWN_HOSTS\`: \`deploy-kit/local/set-vps-secrets.ps1 -Repos <owner>/${p.slug}\`
|
|
72
|
+
* \`KIT_TOKEN\`: a fine-grained token with read access to the OKJT repository's contents
|
|
73
|
+
* \`PROD_ENV\`: the server's \`.env\` (start from \`backend/.env.example\`; \`APP_KEY\` from \`php artisan key:generate --show\`; the database; \`APP_URL=https://${p.domain}\`; \`OKJT_ADMIN_*\`)
|
|
74
|
+
Check a database login before the first deploy:
|
|
75
|
+
\`ssh -t dev@<server> "mysql -u dev_… -p dev_… -e 'SELECT 1'"\`
|
|
76
|
+
4. **DNS:** point the A record at the VPS.
|
|
77
|
+
5. Push to \`main\`. After the first deploy, create the first user on the server, as \`dev\`:
|
|
78
|
+
\`php artisan db:seed --force\` (in \`~/web/${p.domain}/private/${p.slug}/current\`).
|
|
79
|
+
6. **HTTPS**, once the site answers on \`http://\`: Hestia › the domain › SSL with Let's
|
|
80
|
+
Encrypt and the HTTPS redirect.
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function workflow(p) {
|
|
85
|
+
return `name: Test and deploy
|
|
86
|
+
|
|
87
|
+
on:
|
|
88
|
+
push:
|
|
89
|
+
branches: [main]
|
|
90
|
+
pull_request:
|
|
91
|
+
workflow_dispatch:
|
|
92
|
+
|
|
93
|
+
jobs:
|
|
94
|
+
backend:
|
|
95
|
+
name: API tests
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
defaults:
|
|
98
|
+
run:
|
|
99
|
+
working-directory: backend
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
- uses: shivammathur/setup-php@v2
|
|
103
|
+
with:
|
|
104
|
+
php-version: '8.3'
|
|
105
|
+
extensions: zip, sqlite3, pdo_sqlite
|
|
106
|
+
- run: composer install --no-interaction --prefer-dist
|
|
107
|
+
- run: cp .env.example .env && php artisan key:generate
|
|
108
|
+
- run: php artisan test
|
|
109
|
+
|
|
110
|
+
frontend:
|
|
111
|
+
name: App build
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
defaults:
|
|
114
|
+
run:
|
|
115
|
+
working-directory: frontend
|
|
116
|
+
steps:
|
|
117
|
+
- uses: actions/checkout@v4
|
|
118
|
+
- uses: actions/setup-node@v4
|
|
119
|
+
with:
|
|
120
|
+
node-version: '24'
|
|
121
|
+
- run: npm ci
|
|
122
|
+
- run: npm run build
|
|
123
|
+
|
|
124
|
+
deploy:
|
|
125
|
+
name: Deploy
|
|
126
|
+
needs: [backend, frontend]
|
|
127
|
+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
|
128
|
+
uses: Juniortambo2628/OKJT/.github/workflows/deploy-laravel.yml@main
|
|
129
|
+
with:
|
|
130
|
+
domain: ${p.domain}
|
|
131
|
+
app_name: ${p.slug}
|
|
132
|
+
app_dir: backend
|
|
133
|
+
spa_dir: frontend
|
|
134
|
+
build_assets: false
|
|
135
|
+
health_path: /up
|
|
136
|
+
secrets:
|
|
137
|
+
VPS_HOST: \${{ secrets.VPS_HOST }}
|
|
138
|
+
VPS_PORT: \${{ secrets.VPS_PORT }}
|
|
139
|
+
VPS_USER: \${{ secrets.VPS_USER }}
|
|
140
|
+
VPS_SSH_KEY: \${{ secrets.VPS_SSH_KEY }}
|
|
141
|
+
VPS_KNOWN_HOSTS: \${{ secrets.VPS_KNOWN_HOSTS }}
|
|
142
|
+
ENV_FILE: \${{ secrets.PROD_ENV }}
|
|
143
|
+
KIT_TOKEN: \${{ secrets.KIT_TOKEN }}
|
|
144
|
+
`;
|
|
145
|
+
}
|