lapeh 1.0.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/prisma/seed.ts ADDED
@@ -0,0 +1,350 @@
1
+ import { prisma } from "../src/prisma";
2
+ import bcrypt from "bcryptjs";
3
+ import { v4 as uuidv4 } from "uuid";
4
+ import slugify from "slugify";
5
+
6
+ async function main() {
7
+ console.log("Start seeding...");
8
+
9
+ // 1. Create Users (Super Admin, Admin & User)
10
+ const passwordHash = await bcrypt.hash("string", 10);
11
+
12
+ const superAdmin = await prisma.users.upsert({
13
+ where: { email: "sa@sa.com" },
14
+ update: {},
15
+ create: {
16
+ uuid: uuidv4(),
17
+ name: "Super Admin",
18
+ email: "sa@sa.com",
19
+ password: passwordHash,
20
+ created_at: new Date(),
21
+ updated_at: new Date(),
22
+ },
23
+ });
24
+ console.log(`Created super admin: ${superAdmin.name}`);
25
+
26
+ const admin = await prisma.users.upsert({
27
+ where: { email: "a@a.com" },
28
+ update: {},
29
+ create: {
30
+ uuid: uuidv4(),
31
+ name: "Admin User",
32
+ email: "a@a.com",
33
+ password: passwordHash,
34
+ created_at: new Date(),
35
+ updated_at: new Date(),
36
+ },
37
+ });
38
+ console.log(`Created admin: ${admin.name}`);
39
+
40
+ const user = await prisma.users.upsert({
41
+ where: { email: "u@u.com" },
42
+ update: {},
43
+ create: {
44
+ uuid: uuidv4(),
45
+ name: "Regular User",
46
+ email: "u@u.com",
47
+ password: passwordHash,
48
+ created_at: new Date(),
49
+ updated_at: new Date(),
50
+ },
51
+ });
52
+ console.log(`Created user: ${user.name}`);
53
+
54
+ // 2. Seed Roles
55
+ const superAdminRole = await prisma.roles.upsert({
56
+ where: { slug: "super_admin" },
57
+ update: {},
58
+ create: {
59
+ name: "Super Admin",
60
+ slug: "super_admin",
61
+ description: "Full access to all resources",
62
+ created_at: new Date(),
63
+ updated_at: new Date(),
64
+ },
65
+ });
66
+
67
+ const adminRole = await prisma.roles.upsert({
68
+ where: { slug: "admin" },
69
+ update: {},
70
+ create: {
71
+ name: "Admin",
72
+ slug: "admin",
73
+ description: "Administrator",
74
+ created_at: new Date(),
75
+ updated_at: new Date(),
76
+ },
77
+ });
78
+
79
+ const userRole = await prisma.roles.upsert({
80
+ where: { slug: "user" },
81
+ update: {},
82
+ create: {
83
+ name: "User",
84
+ slug: "user",
85
+ description: "Regular user",
86
+ created_at: new Date(),
87
+ updated_at: new Date(),
88
+ },
89
+ });
90
+
91
+ console.log("Seeded roles");
92
+
93
+ // 3. Seed Permissions
94
+ const manageUsers = await prisma.permissions.upsert({
95
+ where: { slug: "users.manage" },
96
+ update: {},
97
+ create: {
98
+ name: "Manage Users",
99
+ slug: "users.manage",
100
+ description: "Create, update, and delete users",
101
+ created_at: new Date(),
102
+ updated_at: new Date(),
103
+ },
104
+ });
105
+ const manageUsersCreate = await prisma.permissions.upsert({
106
+ where: { slug: "users.create" },
107
+ update: {},
108
+ create: {
109
+ name: "Create Users",
110
+ slug: "users.create",
111
+ description: "Create users",
112
+ created_at: new Date(),
113
+ updated_at: new Date(),
114
+ },
115
+ });
116
+ const manageUsersView = await prisma.permissions.upsert({
117
+ where: { slug: "users.view" },
118
+ update: {},
119
+ create: {
120
+ name: "View Users",
121
+ slug: "users.view",
122
+ description: "View users",
123
+ created_at: new Date(),
124
+ updated_at: new Date(),
125
+ },
126
+ });
127
+ const manageUsersUpdate = await prisma.permissions.upsert({
128
+ where: { slug: "users.update" },
129
+ update: {},
130
+ create: {
131
+ name: "Update Users",
132
+ slug: "users.update",
133
+ description: "Update users",
134
+ created_at: new Date(),
135
+ updated_at: new Date(),
136
+ },
137
+ });
138
+ const manageUsersDelete = await prisma.permissions.upsert({
139
+ where: { slug: "users.delete" },
140
+ update: {},
141
+ create: {
142
+ name: "Delete Users",
143
+ slug: "users.delete",
144
+ description: "Delete users",
145
+ created_at: new Date(),
146
+ updated_at: new Date(),
147
+ },
148
+ });
149
+
150
+ const manageRoles = await prisma.permissions.upsert({
151
+ where: { slug: "roles.manage" },
152
+ update: {},
153
+ create: {
154
+ name: "Manage Roles",
155
+ slug: "roles.manage",
156
+ description: "Create, update, and delete roles",
157
+ created_at: new Date(),
158
+ updated_at: new Date(),
159
+ },
160
+ });
161
+
162
+ const managePermissions = await prisma.permissions.upsert({
163
+ where: { slug: "permissions.manage" },
164
+ update: {},
165
+ create: {
166
+ name: "Manage Permissions",
167
+ slug: "permissions.manage",
168
+ description: "Create, update, and delete permissions",
169
+ created_at: new Date(),
170
+ updated_at: new Date(),
171
+ },
172
+ });
173
+
174
+ const manageProfiles = await prisma.permissions.upsert({
175
+ where: { slug: "profiles.manage" },
176
+ update: {},
177
+ create: {
178
+ name: "Manage Profiles",
179
+ slug: "profiles.manage",
180
+ description: "Manage user profiles",
181
+ created_at: new Date(),
182
+ updated_at: new Date(),
183
+ },
184
+ });
185
+
186
+ console.log("Seeded permissions");
187
+
188
+ // 4. Assign permissions to roles
189
+ const postsCreate = await prisma.permissions.upsert({
190
+ where: { slug: "posts.create" },
191
+ update: {},
192
+ create: {
193
+ name: "Create Posts",
194
+ slug: "posts.create",
195
+ description: "Create posts",
196
+ created_at: new Date(),
197
+ updated_at: new Date(),
198
+ },
199
+ });
200
+
201
+ const postsUpdate = await prisma.permissions.upsert({
202
+ where: { slug: "posts.update" },
203
+ update: {},
204
+ create: {
205
+ name: "Update Posts",
206
+ slug: "posts.update",
207
+ description: "Update posts",
208
+ created_at: new Date(),
209
+ updated_at: new Date(),
210
+ },
211
+ });
212
+
213
+ const postsDelete = await prisma.permissions.upsert({
214
+ where: { slug: "posts.delete" },
215
+ update: {},
216
+ create: {
217
+ name: "Delete Posts",
218
+ slug: "posts.delete",
219
+ description: "Delete posts",
220
+ created_at: new Date(),
221
+ updated_at: new Date(),
222
+ },
223
+ });
224
+
225
+ const postsView = await prisma.permissions.upsert({
226
+ where: { slug: "posts.view" },
227
+ update: {},
228
+ create: {
229
+ name: "View Posts",
230
+ slug: "posts.view",
231
+ description: "View posts",
232
+ created_at: new Date(),
233
+ updated_at: new Date(),
234
+ },
235
+ });
236
+
237
+ const categoriesManage = await prisma.permissions.upsert({
238
+ where: { slug: "categories.manage" },
239
+ update: {},
240
+ create: {
241
+ name: "Manage Categories",
242
+ slug: "categories.manage",
243
+ description: "Manage categories",
244
+ created_at: new Date(),
245
+ updated_at: new Date(),
246
+ },
247
+ });
248
+
249
+ const commentsManage = await prisma.permissions.upsert({
250
+ where: { slug: "comments.manage" },
251
+ update: {},
252
+ create: {
253
+ name: "Manage Comments",
254
+ slug: "comments.manage",
255
+ description: "Manage comments",
256
+ created_at: new Date(),
257
+ updated_at: new Date(),
258
+ },
259
+ });
260
+
261
+ console.log("Seeded resource permissions");
262
+
263
+ // 4. Assign permissions to roles
264
+ const rolePermPairs: { roleId: bigint; permId: bigint }[] = [
265
+ // super_admin gets all users permissions + other management permissions
266
+ { roleId: superAdminRole.id, permId: manageUsers.id },
267
+ { roleId: superAdminRole.id, permId: manageUsersCreate.id },
268
+ { roleId: superAdminRole.id, permId: manageUsersView.id },
269
+ { roleId: superAdminRole.id, permId: manageUsersUpdate.id },
270
+ { roleId: superAdminRole.id, permId: manageUsersDelete.id },
271
+ { roleId: superAdminRole.id, permId: manageRoles.id },
272
+ { roleId: superAdminRole.id, permId: managePermissions.id },
273
+ { roleId: superAdminRole.id, permId: manageProfiles.id },
274
+ { roleId: superAdminRole.id, permId: postsCreate.id },
275
+ { roleId: superAdminRole.id, permId: postsUpdate.id },
276
+ { roleId: superAdminRole.id, permId: postsDelete.id },
277
+ { roleId: superAdminRole.id, permId: postsView.id },
278
+ { roleId: superAdminRole.id, permId: categoriesManage.id },
279
+ { roleId: superAdminRole.id, permId: commentsManage.id },
280
+ // admin gets users permissions except delete
281
+ { roleId: adminRole.id, permId: manageUsersCreate.id },
282
+ { roleId: adminRole.id, permId: manageUsersView.id },
283
+ { roleId: adminRole.id, permId: manageUsersUpdate.id },
284
+ // admin gets other management permissions
285
+ { roleId: adminRole.id, permId: manageRoles.id },
286
+ { roleId: adminRole.id, permId: managePermissions.id },
287
+ { roleId: adminRole.id, permId: postsCreate.id },
288
+ { roleId: adminRole.id, permId: postsUpdate.id },
289
+ { roleId: adminRole.id, permId: postsDelete.id },
290
+ { roleId: adminRole.id, permId: postsView.id },
291
+ { roleId: adminRole.id, permId: categoriesManage.id },
292
+ { roleId: adminRole.id, permId: commentsManage.id },
293
+ // user gets read-only posts
294
+ { roleId: userRole.id, permId: postsView.id },
295
+ ];
296
+
297
+ for (const pair of rolePermPairs) {
298
+ await prisma.role_permissions.upsert({
299
+ where: {
300
+ role_id_permission_id: {
301
+ role_id: pair.roleId,
302
+ permission_id: pair.permId,
303
+ },
304
+ },
305
+ create: {
306
+ role_id: pair.roleId,
307
+ permission_id: pair.permId,
308
+ created_at: new Date(),
309
+ },
310
+ update: {},
311
+ });
312
+ }
313
+
314
+ console.log("Assigned permissions to roles");
315
+
316
+ // 5. Assign roles to users
317
+ const userRolePairs: { userId: bigint; roleId: bigint }[] = [
318
+ { userId: superAdmin.id, roleId: superAdminRole.id },
319
+ { userId: admin.id, roleId: adminRole.id },
320
+ { userId: user.id, roleId: userRole.id },
321
+ ];
322
+
323
+ for (const pair of userRolePairs) {
324
+ await prisma.user_roles.upsert({
325
+ where: {
326
+ user_id_role_id: {
327
+ user_id: pair.userId,
328
+ role_id: pair.roleId,
329
+ },
330
+ },
331
+ create: {
332
+ user_id: pair.userId,
333
+ role_id: pair.roleId,
334
+ created_at: new Date(),
335
+ },
336
+ update: {},
337
+ });
338
+ }
339
+
340
+ console.log("Assigned roles to users");
341
+ }
342
+
343
+ main()
344
+ .catch((e) => {
345
+ console.error(e);
346
+ process.exit(1);
347
+ })
348
+ .finally(async () => {
349
+ await prisma.$disconnect();
350
+ });
@@ -0,0 +1,15 @@
1
+ // This file was generated by Prisma, and assumes you have installed the following:
2
+ // npm install --save-dev prisma dotenv
3
+ import "dotenv/config";
4
+ import { defineConfig, env } from "prisma/config";
5
+
6
+ export default defineConfig({
7
+ schema: "prisma/schema.prisma",
8
+ migrations: {
9
+ path: "prisma/migrations",
10
+ seed: "ts-node prisma/seed.ts",
11
+ },
12
+ datasource: {
13
+ url: env("DATABASE_URL"),
14
+ },
15
+ });
package/readme.md ADDED
@@ -0,0 +1,120 @@
1
+ # API Lapeh Framework
2
+
3
+ **API Lapeh** adalah framework berbasis Express.js yang terstandarisasi, dirancang untuk mempercepat pengembangan REST API dengan struktur yang solid, aman, dan scalable. Terinspirasi oleh struktur Laravel dan NestJS, namun tetap menjaga kesederhanaan Express.
4
+
5
+ ## 🚀 Fitur Utama
6
+
7
+ - **Struktur Modular**: Terorganisir rapi dengan Controllers, Services, Routes, dan Middleware.
8
+ - **TypeScript Ready**: Full TypeScript support untuk type-safety.
9
+ - **Prisma ORM**: Integrasi database yang modern dan type-safe.
10
+ - **Schema Terpisah**: Mendukung pemisahan schema Prisma per model (mirip Eloquent).
11
+ - **Generator Tools**: CLI commands untuk generate Module dan Model dengan cepat.
12
+ - **Security Best Practices**: Dilengkapi dengan Helmet, Rate Limiting, CORS, dan JWT Authentication.
13
+ - **Validasi Data**: Menggunakan Zod untuk validasi request yang kuat.
14
+
15
+ ## 📦 Instalasi & Penggunaan
16
+
17
+ Buat project baru cukup dengan satu perintah:
18
+
19
+ ```bash
20
+ npx lapeh-cli nama-project-anda
21
+ ```
22
+
23
+ ### Apa yang terjadi otomatis?
24
+
25
+ 1. Struktur project dibuat.
26
+ 2. Dependencies diinstall.
27
+ 3. Environment variable (`.env`) disiapkan.
28
+ 4. **JWT Secret** di-generate otomatis.
29
+
30
+ Masuk ke folder project dan jalankan:
31
+
32
+ ```bash
33
+ cd nama-project-anda
34
+ npm run dev
35
+ ```
36
+
37
+ Server akan berjalan di `http://localhost:4000`.
38
+
39
+ ---
40
+
41
+ ## 🛠 Development Tools
42
+
43
+ API Lapeh menyediakan tools untuk mempercepat development, mirip dengan `artisan` di Laravel.
44
+
45
+ ### 1. Membuat Module (Resource)
46
+
47
+ Membuat Controller, Service, dan Route sekaligus.
48
+
49
+ ```bash
50
+ npm run make:module NamaResource
51
+ # Contoh: npm run make:module Product
52
+ ```
53
+
54
+ Command ini akan membuat:
55
+
56
+ - `src/controllers/product.controller.ts`
57
+ - `src/services/product.service.ts`
58
+ - `src/routes/product.route.ts` (dan otomatis didaftarkan di `src/routes/index.ts` jika memungkinkan)
59
+
60
+ ### 2. Membuat Model Database
61
+
62
+ Membuat file model Prisma baru di dalam folder `src/models/` (atau `prisma/models` tergantung konfigurasi).
63
+
64
+ ```bash
65
+ npm run make:model NamaModel
66
+ # Contoh: npm run make:model User
67
+ ```
68
+
69
+ Ini akan membuat file `src/models/User.prisma`.
70
+
71
+ ### 3. Workflow Database (Prisma)
72
+
73
+ Karena framework ini menggunakan **Schema Terpisah** (split schema), Anda **TIDAK BOLEH** mengedit `prisma/schema.prisma` secara manual.
74
+
75
+ - **Edit Models**: Lakukan perubahan di `src/models/*.prisma`.
76
+ - **Apply Changes**: Jalankan perintah migrasi standar, sistem akan otomatis menggabungkan (compile) schema Anda.
77
+
78
+ ```bash
79
+ # Generate Prisma Client (setiap ada perubahan model)
80
+ npm run prisma:generate
81
+
82
+ # Migrasi Database (Development)
83
+ npm run prisma:migrate
84
+
85
+ # Deploy ke Production
86
+ npm run prisma:deploy
87
+ ```
88
+
89
+ > **Catatan:** Script `compile-schema.js` akan otomatis berjalan sebelum perintah prisma di atas dieksekusi.
90
+
91
+ ### 4. Generate JWT Secret
92
+
93
+ Jika Anda perlu me-refresh secret key JWT:
94
+
95
+ ```bash
96
+ npm run generate:jwt
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 📂 Struktur Folder
102
+
103
+ ```text
104
+ src/
105
+ ├── controllers/ # Logika Request & Response
106
+ ├── services/ # Business Logic
107
+ ├── routes/ # Definisi Route API
108
+ ├── models/ # Definisi Schema Prisma per Model
109
+ ├── middleware/ # Auth, Validation, Error Handling
110
+ ├── schema/ # Zod Validation Schemas
111
+ ├── utils/ # Helper Functions
112
+ └── index.ts # App Entry Point
113
+ prisma/
114
+ ├── schema.prisma # [GENERATED] Jangan edit file ini
115
+ └── base.prisma # Konfigurasi Datasource & Generator
116
+ ```
117
+
118
+ ## 📝 Lisensi
119
+
120
+ MIT
@@ -0,0 +1,29 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const prismaDir = path.join(__dirname, '..', 'prisma');
5
+ const modelsDir = path.join(__dirname, '..', 'src', 'models');
6
+ const schemaFile = path.join(prismaDir, 'schema.prisma');
7
+ const baseFile = path.join(prismaDir, 'base.prisma');
8
+
9
+ // Ensure models directory exists
10
+ if (!fs.existsSync(modelsDir)) {
11
+ fs.mkdirSync(modelsDir, { recursive: true });
12
+ }
13
+
14
+ // Read base schema (datasource & generator)
15
+ let schemaContent = fs.readFileSync(baseFile, 'utf8');
16
+
17
+ // Read all .prisma files in src/models
18
+ const modelFiles = fs.readdirSync(modelsDir).filter(file => file.endsWith('.prisma'));
19
+
20
+ modelFiles.forEach(file => {
21
+ const content = fs.readFileSync(path.join(modelsDir, file), 'utf8');
22
+ schemaContent += '\n\n' + content;
23
+ });
24
+
25
+ // Write concatenated content to prisma/schema.prisma
26
+ fs.writeFileSync(schemaFile, schemaContent);
27
+
28
+ console.log('✅ Prisma schema compiled successfully!');
29
+ console.log(` Merged ${modelFiles.length} model files from src/models/ into prisma/schema.prisma`);
@@ -0,0 +1,38 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const crypto = require('crypto');
4
+
5
+ const envPath = path.join(__dirname, '..', '.env');
6
+
7
+ function generateSecret() {
8
+ return crypto.randomBytes(64).toString('hex');
9
+ }
10
+
11
+ try {
12
+ const secret = generateSecret();
13
+ let envContent = '';
14
+
15
+ if (fs.existsSync(envPath)) {
16
+ envContent = fs.readFileSync(envPath, 'utf8');
17
+ } else {
18
+ console.log('.env file not found, creating one...');
19
+ }
20
+
21
+ // Check if JWT_SECRET exists
22
+ if (envContent.match(/^JWT_SECRET=/m)) {
23
+ envContent = envContent.replace(/^JWT_SECRET=.*/m, `JWT_SECRET="${secret}"`);
24
+ } else {
25
+ // Ensure there is a newline before appending if the file is not empty
26
+ if (envContent && !envContent.endsWith('\n')) {
27
+ envContent += '\n';
28
+ }
29
+ envContent += `JWT_SECRET="${secret}"\n`;
30
+ }
31
+
32
+ fs.writeFileSync(envPath, envContent);
33
+ console.log('✅ JWT Secret generated and updated in .env file.');
34
+ console.log('🔑 New Secret has been set.');
35
+ } catch (error) {
36
+ console.error('❌ Error updating .env file:', error);
37
+ process.exit(1);
38
+ }
@@ -0,0 +1,42 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const modelName = process.argv[2];
5
+
6
+ if (!modelName) {
7
+ console.error('❌ Please specify the model name.');
8
+ console.error(' Usage: npm run make:model <ModelName>');
9
+ console.error(' Example: npm run make:model Product');
10
+ process.exit(1);
11
+ }
12
+
13
+ const PascalCaseName = modelName.charAt(0).toUpperCase() + modelName.slice(1);
14
+ const tableName = modelName.toLowerCase() + 's'; // simple pluralization
15
+
16
+ const modelsDir = path.join(__dirname, '..', 'src', 'models');
17
+ const modelPath = path.join(modelsDir, `${PascalCaseName}.prisma`);
18
+
19
+ if (fs.existsSync(modelPath)) {
20
+ console.error(`❌ Model ${PascalCaseName} already exists at ${modelPath}`);
21
+ process.exit(1);
22
+ }
23
+
24
+ // Ensure models directory exists
25
+ if (!fs.existsSync(modelsDir)) {
26
+ fs.mkdirSync(modelsDir, { recursive: true });
27
+ }
28
+
29
+ const content = `model ${tableName} {
30
+ id BigInt @id @default(autoincrement())
31
+ name String @db.VarChar(255)
32
+ createdAt DateTime? @default(now()) @db.Timestamp(0)
33
+ updatedAt DateTime? @updatedAt @db.Timestamp(0)
34
+ }
35
+ `;
36
+
37
+ fs.writeFileSync(modelPath, content);
38
+
39
+ console.log(`✅ Model created: src/models/${PascalCaseName}.prisma`);
40
+ console.log(`\nNext steps:`);
41
+ console.log(`1. Edit the model file.`);
42
+ console.log(`2. Run 'npm run prisma:migrate' to update the database.`);