lapeh 2.6.17 → 3.0.2

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.
Files changed (67) hide show
  1. package/.env.example +1 -6
  2. package/README.md +19 -85
  3. package/bin/index.js +84 -180
  4. package/dist/lib/bootstrap.d.ts.map +1 -1
  5. package/dist/lib/bootstrap.js +17 -16
  6. package/dist/lib/core/store.d.ts +55 -0
  7. package/dist/lib/core/store.d.ts.map +1 -0
  8. package/dist/lib/core/store.js +66 -0
  9. package/dist/lib/middleware/error.d.ts.map +1 -1
  10. package/dist/lib/middleware/error.js +1 -20
  11. package/dist/lib/utils/validator.d.ts.map +1 -1
  12. package/dist/lib/utils/validator.js +3 -32
  13. package/dist/src/modules/Auth/auth.controller.d.ts.map +1 -1
  14. package/dist/src/modules/Auth/auth.controller.js +118 -105
  15. package/dist/src/modules/Rbac/rbac.controller.d.ts.map +1 -1
  16. package/dist/src/modules/Rbac/rbac.controller.js +141 -140
  17. package/dist/src/routes/index.d.ts.map +1 -1
  18. package/dist/src/routes/index.js +0 -5
  19. package/doc/en/CHEATSHEET.md +3 -7
  20. package/doc/en/CLI.md +16 -41
  21. package/doc/en/DEPLOYMENT.md +171 -245
  22. package/doc/en/GETTING_STARTED.md +1 -25
  23. package/doc/en/PACKAGES.md +2 -3
  24. package/doc/en/STRUCTURE.md +1 -11
  25. package/doc/en/TUTORIAL.md +61 -119
  26. package/doc/id/CHANGELOG.md +16 -0
  27. package/doc/id/CHEATSHEET.md +0 -4
  28. package/doc/id/CLI.md +19 -54
  29. package/doc/id/DEPLOYMENT.md +171 -245
  30. package/doc/id/GETTING_STARTED.md +91 -115
  31. package/doc/id/PACKAGES.md +0 -1
  32. package/doc/id/STRUCTURE.md +1 -11
  33. package/doc/id/TUTORIAL.md +51 -109
  34. package/gitignore.template +0 -10
  35. package/lib/bootstrap.ts +39 -38
  36. package/lib/core/store.ts +116 -0
  37. package/lib/middleware/error.ts +1 -21
  38. package/lib/utils/validator.ts +3 -39
  39. package/package.json +4 -18
  40. package/scripts/init-project.js +2 -108
  41. package/scripts/make-module.js +1 -12
  42. package/scripts/seed-json.js +158 -0
  43. package/src/modules/Auth/auth.controller.ts +156 -106
  44. package/src/modules/Rbac/rbac.controller.ts +193 -138
  45. package/src/routes/index.ts +0 -3
  46. package/src/routes/rbac.ts +42 -42
  47. package/storage/logs/.0337f5062fe676994d1dc340156e089444e3d6e0-audit.json +5 -10
  48. package/storage/logs/lapeh-2025-12-30.log +1093 -0
  49. package/tsconfig.build.json +1 -3
  50. package/tsconfig.json +0 -1
  51. package/lib/core/database.ts +0 -5
  52. package/prisma/base.prisma.template +0 -8
  53. package/prisma/migrations/20251225163737_init/migration.sql +0 -236
  54. package/prisma/migrations/20251226000329_create_pets_table/migration.sql +0 -11
  55. package/prisma/migrations/20251226001249_create_pets_table/migration.sql +0 -82
  56. package/prisma/migrations/20251226001717_restore_core_models/migration.sql +0 -236
  57. package/prisma/migrations/migration_lock.toml +0 -3
  58. package/prisma/schema.prisma +0 -197
  59. package/prisma/seed.ts +0 -411
  60. package/scripts/compile-schema.js +0 -64
  61. package/src/modules/Auth/auth.prisma +0 -106
  62. package/src/modules/Pets/pets.controller.ts +0 -238
  63. package/src/modules/Pets/pets.prisma +0 -9
  64. package/src/modules/Rbac/rbac.prisma +0 -68
  65. package/src/routes/pets.ts +0 -13
  66. package/storage/logs/lapeh-2025-12-26.log +0 -88
  67. package/storage/logs/lapeh-2025-12-27.log +0 -217
@@ -1,106 +0,0 @@
1
- model cache {
2
- id String @id @default(auto()) @map("_id") @db.ObjectId
3
- key String @unique
4
- value String
5
- expiration Int
6
- }
7
-
8
- model cache_locks {
9
- id String @id @default(auto()) @map("_id") @db.ObjectId
10
- key String @unique
11
- owner String
12
- expiration Int
13
- }
14
-
15
- model failed_jobs {
16
- id String @id @default(auto()) @map("_id") @db.ObjectId
17
- uuid String @unique
18
- connection String
19
- queue String
20
- payload String
21
- exception String
22
- failed_at DateTime @default(now())
23
- }
24
-
25
- model job_batches {
26
- id String @id @map("_id")
27
- name String
28
- total_jobs Int
29
- pending_jobs Int
30
- failed_jobs Int
31
- failed_job_ids String
32
- options String?
33
- cancelled_at Int?
34
- created_at Int
35
- finished_at Int?
36
- }
37
-
38
- model jobs {
39
- id String @id @default(auto()) @map("_id") @db.ObjectId
40
- queue String
41
- payload String
42
- attempts Int
43
- reserved_at Int?
44
- available_at Int
45
- created_at Int
46
-
47
- @@index([queue])
48
- }
49
-
50
- model migrations {
51
- id String @id @default(auto()) @map("_id") @db.ObjectId
52
- migration String
53
- batch Int
54
- }
55
-
56
- model password_reset_tokens {
57
- id String @id @default(auto()) @map("_id") @db.ObjectId
58
- email String @unique
59
- token String
60
- created_at DateTime?
61
- }
62
-
63
- model personal_access_tokens {
64
- id String @id @default(auto()) @map("_id") @db.ObjectId
65
- tokenable_type String
66
- tokenable_id String
67
- name String
68
- token String @unique
69
- abilities String?
70
- last_used_at DateTime?
71
- expires_at DateTime?
72
- created_at DateTime?
73
- updated_at DateTime?
74
-
75
- @@index([expires_at])
76
- @@index([tokenable_type, tokenable_id])
77
- }
78
-
79
- model sessions {
80
- id String @id @map("_id")
81
- user_id String?
82
- ip_address String?
83
- user_agent String?
84
- payload String
85
- last_activity Int
86
-
87
- @@index([last_activity])
88
- @@index([user_id])
89
- }
90
-
91
- model users {
92
- id String @id @default(auto()) @map("_id") @db.ObjectId
93
- uuid String @unique
94
- name String
95
- email String @unique
96
- avatar String?
97
- avatar_url String?
98
- email_verified_at DateTime?
99
- password String
100
- remember_token String?
101
- created_at DateTime?
102
- updated_at DateTime?
103
-
104
- user_roles user_roles[]
105
- user_permissions user_permissions[]
106
- }
@@ -1,238 +0,0 @@
1
- import { Request, Response } from "express";
2
- import { prisma } from "@lapeh/core/database";
3
- import { sendSuccess, sendError, sendFastSuccess } from "@lapeh/utils/response";
4
- import { getPagination, buildPaginationMeta } from "@lapeh/utils/pagination";
5
- import { Validator } from "@lapeh/utils/validator";
6
- import {
7
- getSerializer,
8
- createResponseSchema,
9
- createPaginatedResponseSchema,
10
- } from "@lapeh/core/serializer";
11
- import {
12
- getCache,
13
- setCache,
14
- delCache,
15
- delCachePattern,
16
- } from "../../../lib/core/redis";
17
-
18
- // 1. Definisikan Schema Output untuk performa tinggi
19
- const petSchema = {
20
- type: "object",
21
- properties: {
22
- id: { type: "string" }, // BigInt dikonversi ke string
23
- name: { type: "string" },
24
- species: { type: "string" },
25
- age: { type: "integer" },
26
- created_at: { type: "string", format: "date-time" },
27
- updated_at: { type: "string", format: "date-time" },
28
- },
29
- };
30
-
31
- // 2. Compile Serializer
32
- // Untuk Single Item
33
- const petSerializer = getSerializer(
34
- "pet-single",
35
- createResponseSchema(petSchema)
36
- );
37
-
38
- // Untuk List Item (Paginated)
39
- const petListSerializer = getSerializer(
40
- "pet-list",
41
- createPaginatedResponseSchema(petSchema)
42
- );
43
-
44
- export async function index(req: Request, res: Response) {
45
- const { page, perPage, skip, take } = getPagination(req.query);
46
- const search = req.query.search as string;
47
-
48
- // Cache Strategy: Cache list based on query params
49
- const cacheKey = `pets:list:${JSON.stringify(req.query)}`;
50
- const cached = await getCache(cacheKey);
51
-
52
- if (cached) {
53
- sendFastSuccess(res, 200, petListSerializer, cached);
54
- return;
55
- }
56
-
57
- const where: any = {};
58
- if (search) {
59
- where.OR = [
60
- { name: { contains: search, mode: "insensitive" } },
61
- { species: { contains: search, mode: "insensitive" } },
62
- ];
63
- }
64
-
65
- const [data, total] = await Promise.all([
66
- prisma.pets.findMany({
67
- where,
68
- skip,
69
- take,
70
- orderBy: { created_at: "desc" },
71
- }),
72
- prisma.pets.count({ where }),
73
- ]);
74
-
75
- // Kita perlu convert BigInt ke string sebelum masuk serializer
76
- // Karena fast-json-stringify mengharapkan tipe data yang sesuai dengan schema
77
- const serialized = data.map((item: any) => ({
78
- ...item,
79
- id: item.id.toString(),
80
- }));
81
-
82
- const meta = buildPaginationMeta(page, perPage, total);
83
-
84
- const responseData = {
85
- status: "success",
86
- message: "Pets retrieved successfully",
87
- data: {
88
- data: serialized,
89
- meta,
90
- },
91
- };
92
-
93
- // Cache for 60 seconds
94
- await setCache(cacheKey, responseData, 60);
95
-
96
- // Gunakan sendFastSuccess untuk performa maksimal
97
- // Struktur data disesuaikan dengan createPaginatedResponseSchema: { data: [], meta: {} }
98
- sendFastSuccess(res, 200, petListSerializer, responseData);
99
- }
100
-
101
- export async function show(req: Request, res: Response) {
102
- const { id } = req.params;
103
- const cacheKey = `pets:${id}`;
104
-
105
- const cached = await getCache(cacheKey);
106
- if (cached) {
107
- sendFastSuccess(res, 200, petSerializer, cached);
108
- return;
109
- }
110
-
111
- const pet = await prisma.pets.findUnique({
112
- where: { id: id },
113
- });
114
-
115
- if (!pet) {
116
- sendError(res, 404, "Pet not found");
117
- return;
118
- }
119
-
120
- const responseData = {
121
- status: "success",
122
- message: "Pet retrieved successfully",
123
- data: {
124
- ...pet,
125
- id: pet.id.toString(),
126
- },
127
- };
128
-
129
- // Cache for 5 minutes
130
- await setCache(cacheKey, responseData, 300);
131
-
132
- // Gunakan sendFastSuccess
133
- sendFastSuccess(res, 200, petSerializer, responseData);
134
- }
135
-
136
- export async function store(req: Request, res: Response) {
137
- const validator = Validator.make(req.body || {}, {
138
- name: "required|string",
139
- species: "required|string",
140
- age: "required|integer|min:1",
141
- });
142
-
143
- if (await validator.fails()) {
144
- sendError(res, 422, "Validation error", validator.errors());
145
- return;
146
- }
147
-
148
- const validatedData = await validator.validated();
149
- const pet = await prisma.pets.create({
150
- data: {
151
- ...validatedData,
152
- created_at: new Date(),
153
- updated_at: new Date(),
154
- },
155
- });
156
-
157
- // Invalidate list cache
158
- await delCachePattern("pets:list:*");
159
-
160
- // Gunakan sendFastSuccess
161
- sendFastSuccess(res, 201, petSerializer, {
162
- status: "success",
163
- message: "Pet created successfully",
164
- data: {
165
- ...pet,
166
- id: pet.id.toString(),
167
- },
168
- });
169
- }
170
-
171
- export async function update(req: Request, res: Response) {
172
- const { id } = req.params;
173
- const validator = Validator.make(req.body || {}, {
174
- name: "string",
175
- species: "string",
176
- age: "integer|min:1",
177
- });
178
-
179
- if (await validator.fails()) {
180
- sendError(res, 422, "Validation error", validator.errors());
181
- return;
182
- }
183
-
184
- const existing = await prisma.pets.findUnique({
185
- where: { id: id },
186
- });
187
-
188
- if (!existing) {
189
- sendError(res, 404, "Pet not found");
190
- return;
191
- }
192
-
193
- const validatedData = await validator.validated();
194
- const updated = await prisma.pets.update({
195
- where: { id: id },
196
- data: {
197
- ...validatedData,
198
- updated_at: new Date(),
199
- },
200
- });
201
-
202
- // Invalidate specific cache and list cache
203
- await delCache(`pets:${id}`);
204
- await delCachePattern("pets:list:*");
205
-
206
- // Gunakan sendFastSuccess
207
- sendFastSuccess(res, 200, petSerializer, {
208
- status: "success",
209
- message: "Pet updated successfully",
210
- data: {
211
- ...updated,
212
- id: updated.id.toString(),
213
- },
214
- });
215
- }
216
-
217
- export async function destroy(req: Request, res: Response) {
218
- const { id } = req.params;
219
-
220
- const existing = await prisma.pets.findUnique({
221
- where: { id: id },
222
- });
223
-
224
- if (!existing) {
225
- sendError(res, 404, "Pet not found");
226
- return;
227
- }
228
-
229
- await prisma.pets.delete({
230
- where: { id: id },
231
- });
232
-
233
- // Invalidate specific cache and list cache
234
- await delCache(`pets:${id}`);
235
- await delCachePattern("pets:list:*");
236
-
237
- sendSuccess(res, 200, "Pet deleted successfully", null);
238
- }
@@ -1,9 +0,0 @@
1
-
2
- model pets {
3
- id String @id @default(auto()) @map("_id") @db.ObjectId
4
- name String
5
- species String
6
- age Int
7
- created_at DateTime?
8
- updated_at DateTime?
9
- }
@@ -1,68 +0,0 @@
1
- model roles {
2
- id String @id @default(auto()) @map("_id") @db.ObjectId
3
- name String
4
- slug String @unique
5
- description String?
6
- created_at DateTime @default(now())
7
- updated_at DateTime @updatedAt
8
-
9
- user_roles user_roles[]
10
- role_permissions role_permissions[]
11
- }
12
-
13
- model permissions {
14
- id String @id @default(auto()) @map("_id") @db.ObjectId
15
- name String
16
- slug String @unique
17
- description String?
18
- created_at DateTime @default(now())
19
- updated_at DateTime @updatedAt
20
-
21
- role_permissions role_permissions[]
22
- user_permissions user_permissions[]
23
- }
24
-
25
- model user_roles {
26
- id String @id @default(auto()) @map("_id") @db.ObjectId
27
- user_id String @db.ObjectId
28
- role_id String @db.ObjectId
29
- created_at DateTime @default(now())
30
- updated_at DateTime @updatedAt
31
-
32
- user users @relation(fields: [user_id], references: [id], onDelete: Cascade)
33
- role roles @relation(fields: [role_id], references: [id], onDelete: Cascade)
34
-
35
- @@unique([user_id, role_id])
36
- @@index([user_id])
37
- @@index([role_id])
38
- }
39
-
40
- model role_permissions {
41
- id String @id @default(auto()) @map("_id") @db.ObjectId
42
- role_id String @db.ObjectId
43
- permission_id String @db.ObjectId
44
- created_at DateTime @default(now())
45
- updated_at DateTime @updatedAt
46
-
47
- role roles @relation(fields: [role_id], references: [id], onDelete: Cascade)
48
- permission permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade)
49
-
50
- @@unique([role_id, permission_id])
51
- @@index([role_id])
52
- @@index([permission_id])
53
- }
54
-
55
- model user_permissions {
56
- id String @id @default(auto()) @map("_id") @db.ObjectId
57
- user_id String @db.ObjectId
58
- permission_id String @db.ObjectId
59
- created_at DateTime @default(now())
60
- updated_at DateTime @updatedAt
61
-
62
- user users @relation(fields: [user_id], references: [id], onDelete: Cascade)
63
- permission permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade)
64
-
65
- @@unique([user_id, permission_id])
66
- @@index([user_id])
67
- @@index([permission_id])
68
- }
@@ -1,13 +0,0 @@
1
- import { Router } from "express";
2
- import * as PetController from "@/modules/Pets/pets.controller";
3
- import { parseMultipart } from "@lapeh/middleware/multipart";
4
-
5
- const router = Router();
6
-
7
- router.get("/", PetController.index);
8
- router.get("/:id", PetController.show);
9
- router.post("/", parseMultipart, PetController.store);
10
- router.put("/:id", parseMultipart, PetController.update);
11
- router.delete("/:id", PetController.destroy);
12
-
13
- export default router;
@@ -1,88 +0,0 @@
1
- [2025-12-26 23:24:48] INFO: This is an info message from test script
2
- [2025-12-26 23:24:48] ERROR: This is an error message from test script
3
- [2025-12-26 23:24:48] WARN: This is a warning
4
- [2025-12-26 23:25:18] INFO: This is an info message from test script
5
- [2025-12-26 23:25:18] ERROR: This is an error message from test script
6
- [2025-12-26 23:25:18] WARN: This is a warning
7
- [2025-12-26 23:25:42] INFO: This is an info message from test script
8
- [2025-12-26 23:25:42] ERROR: This is an error message from test script
9
- [2025-12-26 23:25:42] WARN: This is a warning
10
- [2025-12-26 23:35:47] WARN: Validation error
11
- [2025-12-26 23:35:48] WARN: Validation error
12
- [2025-12-26 23:35:49] WARN: Validation error
13
- [2025-12-26 23:35:50] WARN: Validation error
14
- [2025-12-26 23:35:51] WARN: Validation error
15
- [2025-12-26 23:35:54] WARN: Validation error
16
- [2025-12-26 23:36:06] WARN: Validation error
17
- [2025-12-26 23:36:07] WARN: Validation error
18
- [2025-12-26 23:36:08] WARN: Validation error
19
- [2025-12-26 23:36:21] WARN: Validation error
20
- [2025-12-26 23:41:33] WARN: Validation error
21
- Errors: {
22
- "age": [
23
- "Age must be a number"
24
- ]
25
- }
26
- Meta: {"statusCode":422}
27
- [2025-12-26 23:41:36] WARN: Validation error
28
- Errors: {
29
- "age": [
30
- "Age must be a number"
31
- ]
32
- }
33
- Meta: {"statusCode":422}
34
- [2025-12-26 23:41:38] WARN: Validation error
35
- Errors: {
36
- "age": [
37
- "Age must be a number"
38
- ]
39
- }
40
- Meta: {"statusCode":422}
41
- [2025-12-26 23:41:39] WARN: Validation error
42
- Errors: {
43
- "age": [
44
- "Age must be a number"
45
- ]
46
- }
47
- Meta: {"statusCode":422}
48
- [2025-12-26 23:41:47] WARN: Validation error
49
- Errors: {
50
- "species": [
51
- "Species is required"
52
- ],
53
- "age": [
54
- "Age is required"
55
- ]
56
- }
57
- Meta: {"statusCode":422}
58
- [2025-12-26 23:42:10] WARN: Validation error
59
- Errors: {
60
- "species": [
61
- "Species is required"
62
- ],
63
- "age": [
64
- "Age is required"
65
- ]
66
- }
67
- Meta: {"statusCode":422}
68
- [2025-12-26 23:42:27] WARN: Validation error
69
- Errors: {
70
- "age": [
71
- "Age must be a number"
72
- ]
73
- }
74
- Meta: {"statusCode":422}
75
- [2025-12-26 23:56:33] WARN: Validation error
76
- Errors: {
77
- "age": [
78
- "Age must be a number"
79
- ]
80
- }
81
- Meta: {"statusCode":422}
82
- [2025-12-26 23:56:35] WARN: Validation error
83
- Errors: {
84
- "age": [
85
- "Age must be a number"
86
- ]
87
- }
88
- Meta: {"statusCode":422}