ridho-arachman-portfolio 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.
Files changed (486) hide show
  1. package/.dockerignore +10 -0
  2. package/.gitattributes +21 -0
  3. package/.github/CODEOWNERS +1 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +80 -0
  5. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. package/.github/ISSUE_TEMPLATE/feature_request.yml +35 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +26 -0
  8. package/.github/SECURITY.md +43 -0
  9. package/.github/dependabot.yml +47 -0
  10. package/.github/workflows/ci.yml +171 -0
  11. package/.github/workflows/publish.yml +68 -0
  12. package/.husky/commit-msg +1 -0
  13. package/.husky/pre-commit +1 -0
  14. package/AGENTS.md +170 -0
  15. package/CACHING.md +162 -0
  16. package/DESIGN.md +296 -0
  17. package/LICENSE +21 -0
  18. package/README.md +241 -0
  19. package/commitlint.config.js +3 -0
  20. package/components.json +25 -0
  21. package/eslint.config.mjs +18 -0
  22. package/next.config.ts +146 -0
  23. package/package.json +112 -0
  24. package/playwright.config.ts +46 -0
  25. package/postcss.config.mjs +7 -0
  26. package/prisma/migrations/20260817181904_add_portfolio_fields/migration.sql +285 -0
  27. package/prisma/migrations/20260817193303_add_visit_tracking/migration.sql +28 -0
  28. package/prisma/migrations/20260817205514_add_experience_published/migration.sql +5 -0
  29. package/prisma/migrations/20260820132310_add_multiple_image/migration.sql +2 -0
  30. package/prisma/migrations/20260824000000_rename_skill_icon_url_to_icon_name/migration.sql +3 -0
  31. package/prisma/migrations/20260828144046_change_the_table_name_use_map/migration.sql +204 -0
  32. package/prisma/migrations/20260926182635_add_site_settings_and_translation/migration.sql +31 -0
  33. package/prisma/migrations/20260926214617_add_soft_delete/migration.sql +38 -0
  34. package/prisma/migrations/migration_lock.toml +3 -0
  35. package/prisma/schema.prisma +344 -0
  36. package/prisma.config.ts +14 -0
  37. package/public/apple-touch-icon.png +0 -0
  38. package/public/avatar-hero-sm.webp +0 -0
  39. package/public/avatar-hero.avif +0 -0
  40. package/public/avatar-hero.webp +0 -0
  41. package/public/avatar-nav.webp +0 -0
  42. package/public/avatar.png +0 -0
  43. package/public/favicon-16x16.png +0 -0
  44. package/public/favicon-32x32.png +0 -0
  45. package/public/file.svg +1 -0
  46. package/public/globe.svg +1 -0
  47. package/public/icon-192.png +0 -0
  48. package/public/icon-512.png +0 -0
  49. package/public/logo-optimized.webp +0 -0
  50. package/public/logo.png +0 -0
  51. package/public/manifest.json +42 -0
  52. package/public/next.svg +1 -0
  53. package/public/robots.txt +17 -0
  54. package/public/vercel.svg +1 -0
  55. package/public/window.svg +1 -0
  56. package/scripts/graphify-execute.bash +3 -0
  57. package/scripts/seed-admin.ts +81 -0
  58. package/scripts/seed-portfolio.ts +320 -0
  59. package/scripts/setup-portfolio-issues.sh +274 -0
  60. package/scripts/test-integration-setup.mjs +32 -0
  61. package/src/app/[lang]/(public)/about/about-content.tsx +31 -0
  62. package/src/app/[lang]/(public)/about/page.tsx +52 -0
  63. package/src/app/[lang]/(public)/below-fold-sections.tsx +28 -0
  64. package/src/app/[lang]/(public)/certificates/[slug]/certificate-detail-content.tsx +19 -0
  65. package/src/app/[lang]/(public)/certificates/[slug]/page.test.ts +38 -0
  66. package/src/app/[lang]/(public)/certificates/[slug]/page.tsx +89 -0
  67. package/src/app/[lang]/(public)/certificates/certificates-content.tsx +61 -0
  68. package/src/app/[lang]/(public)/certificates/page.tsx +58 -0
  69. package/src/app/[lang]/(public)/contact/contact-content.tsx +14 -0
  70. package/src/app/[lang]/(public)/contact/page.tsx +33 -0
  71. package/src/app/[lang]/(public)/experience/[slug]/experience-detail-content.tsx +19 -0
  72. package/src/app/[lang]/(public)/experience/[slug]/page.test.ts +51 -0
  73. package/src/app/[lang]/(public)/experience/[slug]/page.tsx +78 -0
  74. package/src/app/[lang]/(public)/experience/experience-content.tsx +61 -0
  75. package/src/app/[lang]/(public)/experience/page.tsx +53 -0
  76. package/src/app/[lang]/(public)/home-content.tsx +111 -0
  77. package/src/app/[lang]/(public)/layout.tsx +43 -0
  78. package/src/app/[lang]/(public)/page.tsx +92 -0
  79. package/src/app/[lang]/(public)/projects/[slug]/page.test.ts +38 -0
  80. package/src/app/[lang]/(public)/projects/[slug]/page.tsx +91 -0
  81. package/src/app/[lang]/(public)/projects/[slug]/project-detail-content.tsx +19 -0
  82. package/src/app/[lang]/(public)/projects/page.tsx +59 -0
  83. package/src/app/[lang]/(public)/projects/projects-content.tsx +150 -0
  84. package/src/app/[lang]/layout.tsx +45 -0
  85. package/src/app/admin/(dashboard)/categories/[id]/edit/page.tsx +21 -0
  86. package/src/app/admin/(dashboard)/categories/new/page.tsx +16 -0
  87. package/src/app/admin/(dashboard)/categories/page.tsx +21 -0
  88. package/src/app/admin/(dashboard)/certificates/[id]/edit/page.tsx +21 -0
  89. package/src/app/admin/(dashboard)/certificates/new/page.tsx +16 -0
  90. package/src/app/admin/(dashboard)/certificates/page.tsx +21 -0
  91. package/src/app/admin/(dashboard)/experience/[id]/edit/page.tsx +21 -0
  92. package/src/app/admin/(dashboard)/experience/new/page.tsx +16 -0
  93. package/src/app/admin/(dashboard)/experience/page.tsx +21 -0
  94. package/src/app/admin/(dashboard)/layout.tsx +40 -0
  95. package/src/app/admin/(dashboard)/messages/page.tsx +16 -0
  96. package/src/app/admin/(dashboard)/page.tsx +16 -0
  97. package/src/app/admin/(dashboard)/projects/[id]/edit/page.tsx +21 -0
  98. package/src/app/admin/(dashboard)/projects/new/page.tsx +16 -0
  99. package/src/app/admin/(dashboard)/projects/page-client.tsx +13 -0
  100. package/src/app/admin/(dashboard)/projects/page.tsx +21 -0
  101. package/src/app/admin/(dashboard)/settings/page.tsx +16 -0
  102. package/src/app/admin/(dashboard)/skills/[id]/edit/page.tsx +21 -0
  103. package/src/app/admin/(dashboard)/skills/new/page.tsx +16 -0
  104. package/src/app/admin/(dashboard)/skills/page.tsx +21 -0
  105. package/src/app/admin/(dashboard)/translations/page.tsx +16 -0
  106. package/src/app/admin/(dashboard)/trash/page.tsx +16 -0
  107. package/src/app/admin/login/page.tsx +22 -0
  108. package/src/app/api/admin/analytics/route.ts +124 -0
  109. package/src/app/api/admin/categories/[id]/purge/route.ts +57 -0
  110. package/src/app/api/admin/categories/[id]/restore/route.ts +41 -0
  111. package/src/app/api/admin/categories/[id]/route.ts +113 -0
  112. package/src/app/api/admin/categories/categories.integration.test.ts +190 -0
  113. package/src/app/api/admin/categories/route.ts +83 -0
  114. package/src/app/api/admin/certificates/[id]/purge/route.ts +59 -0
  115. package/src/app/api/admin/certificates/[id]/restore/route.ts +43 -0
  116. package/src/app/api/admin/certificates/[id]/route.ts +137 -0
  117. package/src/app/api/admin/certificates/certificates.integration.test.ts +90 -0
  118. package/src/app/api/admin/certificates/route.ts +100 -0
  119. package/src/app/api/admin/dashboard-stats/route.ts +31 -0
  120. package/src/app/api/admin/experience/[id]/purge/route.ts +59 -0
  121. package/src/app/api/admin/experience/[id]/restore/route.ts +43 -0
  122. package/src/app/api/admin/experience/[id]/route.ts +130 -0
  123. package/src/app/api/admin/experience/experience.integration.test.ts +104 -0
  124. package/src/app/api/admin/experience/route.ts +93 -0
  125. package/src/app/api/admin/messages/[id]/purge/route.ts +54 -0
  126. package/src/app/api/admin/messages/[id]/restore/route.ts +38 -0
  127. package/src/app/api/admin/messages/[id]/route.ts +92 -0
  128. package/src/app/api/admin/messages/messages.integration.test.ts +111 -0
  129. package/src/app/api/admin/messages/route.ts +57 -0
  130. package/src/app/api/admin/projects/[id]/purge/route.ts +62 -0
  131. package/src/app/api/admin/projects/[id]/restore/route.ts +45 -0
  132. package/src/app/api/admin/projects/[id]/route.test.ts +178 -0
  133. package/src/app/api/admin/projects/[id]/route.ts +154 -0
  134. package/src/app/api/admin/projects/projects.integration.test.ts +107 -0
  135. package/src/app/api/admin/projects/route.test.ts +108 -0
  136. package/src/app/api/admin/projects/route.ts +95 -0
  137. package/src/app/api/admin/settings/reset/route.ts +83 -0
  138. package/src/app/api/admin/settings/route.ts +70 -0
  139. package/src/app/api/admin/settings/settings.integration.test.ts +241 -0
  140. package/src/app/api/admin/skills/[id]/purge/route.ts +54 -0
  141. package/src/app/api/admin/skills/[id]/restore/route.ts +38 -0
  142. package/src/app/api/admin/skills/[id]/route.ts +106 -0
  143. package/src/app/api/admin/skills/route.ts +79 -0
  144. package/src/app/api/admin/skills/skills.integration.test.ts +124 -0
  145. package/src/app/api/admin/translations/route.ts +143 -0
  146. package/src/app/api/admin/translations/translations.integration.test.ts +153 -0
  147. package/src/app/api/admin/upload/route.ts +105 -0
  148. package/src/app/api/auth/[...all]/route.ts +44 -0
  149. package/src/app/api/contact/route.ts +76 -0
  150. package/src/app/api/public/categories/route.ts +24 -0
  151. package/src/app/api/public/certificates/[slug]/route.ts +42 -0
  152. package/src/app/api/public/certificates/route.ts +54 -0
  153. package/src/app/api/public/experience/[slug]/route.ts +42 -0
  154. package/src/app/api/public/experience/route.ts +54 -0
  155. package/src/app/api/public/projects/[slug]/route.ts +53 -0
  156. package/src/app/api/public/projects/route.ts +75 -0
  157. package/src/app/api/public/skills/route.ts +25 -0
  158. package/src/app/api/visit/route.ts +121 -0
  159. package/src/app/favicon.ico +0 -0
  160. package/src/app/globals.css +620 -0
  161. package/src/app/layout.test.ts +85 -0
  162. package/src/app/layout.tsx +143 -0
  163. package/src/app/not-found.tsx +59 -0
  164. package/src/app/robots.ts +21 -0
  165. package/src/app/seo-routes.test.ts +107 -0
  166. package/src/app/sitemap.ts +70 -0
  167. package/src/components/layout/footer/constants.ts +49 -0
  168. package/src/components/layout/footer/footer-bottom.tsx +33 -0
  169. package/src/components/layout/footer/footer-brand.tsx +33 -0
  170. package/src/components/layout/footer/footer-links.test.tsx +70 -0
  171. package/src/components/layout/footer/footer-links.tsx +64 -0
  172. package/src/components/layout/footer/footer-social.test.tsx +77 -0
  173. package/src/components/layout/footer/footer-social.tsx +49 -0
  174. package/src/components/layout/footer/footer.tsx +30 -0
  175. package/src/components/layout/footer/index.ts +1 -0
  176. package/src/components/layout/navbar/constants.ts +11 -0
  177. package/src/components/layout/navbar/cv-download.tsx +125 -0
  178. package/src/components/layout/navbar/desktop-nav.tsx +171 -0
  179. package/src/components/layout/navbar/index.ts +1 -0
  180. package/src/components/layout/navbar/language-switcher.tsx +158 -0
  181. package/src/components/layout/navbar/nav-collapse-client.test.tsx +119 -0
  182. package/src/components/layout/navbar/nav-collapse-client.tsx +120 -0
  183. package/src/components/layout/navbar/navbar-logo.tsx +37 -0
  184. package/src/components/layout/navbar/navbar.tsx +51 -0
  185. package/src/components/providers/motion-provider.tsx +13 -0
  186. package/src/components/providers/nuqs-adapter-loader.tsx +11 -0
  187. package/src/components/providers/public-content-provider.test.tsx +121 -0
  188. package/src/components/providers/public-content-provider.tsx +53 -0
  189. package/src/components/sections/about/about-avatar.tsx +40 -0
  190. package/src/components/sections/about/about-background.tsx +7 -0
  191. package/src/components/sections/about/about-content.tsx +43 -0
  192. package/src/components/sections/about/about.tsx +25 -0
  193. package/src/components/sections/about/avatar-background.tsx +20 -0
  194. package/src/components/sections/about/avatar-badge.tsx +25 -0
  195. package/src/components/sections/about/constants.ts +12 -0
  196. package/src/components/sections/about/index.ts +1 -0
  197. package/src/components/sections/about/skills-section.test.tsx +85 -0
  198. package/src/components/sections/about/skills-section.tsx +63 -0
  199. package/src/components/sections/about-hero/about-hero-background.tsx +51 -0
  200. package/src/components/sections/about-hero/about-hero-content.tsx +50 -0
  201. package/src/components/sections/about-hero/about-hero.tsx +61 -0
  202. package/src/components/sections/about-hero/constants.ts +19 -0
  203. package/src/components/sections/about-hero/floating-tech-icon.tsx +18 -0
  204. package/src/components/sections/about-hero/hero-scroll-progress.test.ts +41 -0
  205. package/src/components/sections/about-hero/hero-scroll-progress.ts +9 -0
  206. package/src/components/sections/about-hero/index.ts +1 -0
  207. package/src/components/sections/about-hero/use-about-hero-animations.ts +61 -0
  208. package/src/components/sections/admin-categories/categories-list.tsx +194 -0
  209. package/src/components/sections/admin-categories/category-form-page-wrapper.tsx +26 -0
  210. package/src/components/sections/admin-categories/category-form-page.tsx +119 -0
  211. package/src/components/sections/admin-categories/category-form.tsx +213 -0
  212. package/src/components/sections/admin-categories/constants.ts +38 -0
  213. package/src/components/sections/admin-categories/index.ts +3 -0
  214. package/src/components/sections/admin-certificates/certificate-form-page.tsx +110 -0
  215. package/src/components/sections/admin-certificates/certificate-form.tsx +438 -0
  216. package/src/components/sections/admin-certificates/certificates-list.tsx +233 -0
  217. package/src/components/sections/admin-certificates/constants.ts +54 -0
  218. package/src/components/sections/admin-certificates/index.ts +3 -0
  219. package/src/components/sections/admin-dashboard/admin-dashboard.tsx +263 -0
  220. package/src/components/sections/admin-dashboard/admin-mobile-sidebar.tsx +161 -0
  221. package/src/components/sections/admin-dashboard/admin-sidebar-context.tsx +36 -0
  222. package/src/components/sections/admin-dashboard/admin-sidebar.tsx +134 -0
  223. package/src/components/sections/admin-dashboard/admin-topbar-wrapper.tsx +14 -0
  224. package/src/components/sections/admin-dashboard/admin-topbar.tsx +59 -0
  225. package/src/components/sections/admin-dashboard/constants.test.ts +64 -0
  226. package/src/components/sections/admin-dashboard/constants.ts +93 -0
  227. package/src/components/sections/admin-dashboard/index.ts +7 -0
  228. package/src/components/sections/admin-dashboard/panel-card.tsx +90 -0
  229. package/src/components/sections/admin-dashboard/stat-card.tsx +59 -0
  230. package/src/components/sections/admin-dashboard/visitor-map-leaflet.css +61 -0
  231. package/src/components/sections/admin-dashboard/visitor-map-leaflet.tsx +249 -0
  232. package/src/components/sections/admin-dashboard/visitor-map.tsx +246 -0
  233. package/src/components/sections/admin-dashboard/visits-chart.tsx +120 -0
  234. package/src/components/sections/admin-experience/constants.ts +81 -0
  235. package/src/components/sections/admin-experience/experience-form-page.tsx +141 -0
  236. package/src/components/sections/admin-experience/experience-form.tsx +312 -0
  237. package/src/components/sections/admin-experience/experiences-list.tsx +222 -0
  238. package/src/components/sections/admin-experience/index.ts +3 -0
  239. package/src/components/sections/admin-login/admin-login-background.tsx +32 -0
  240. package/src/components/sections/admin-login/admin-login-card.tsx +43 -0
  241. package/src/components/sections/admin-login/admin-login-form.test.tsx +142 -0
  242. package/src/components/sections/admin-login/admin-login-form.tsx +277 -0
  243. package/src/components/sections/admin-login/admin-login.tsx +102 -0
  244. package/src/components/sections/admin-login/constants.ts +26 -0
  245. package/src/components/sections/admin-login/index.ts +3 -0
  246. package/src/components/sections/admin-messages/constants.ts +60 -0
  247. package/src/components/sections/admin-messages/index.ts +1 -0
  248. package/src/components/sections/admin-messages/messages-inbox.tsx +429 -0
  249. package/src/components/sections/admin-projects/constants.ts +47 -0
  250. package/src/components/sections/admin-projects/index.ts +3 -0
  251. package/src/components/sections/admin-projects/project-form-page.tsx +124 -0
  252. package/src/components/sections/admin-projects/project-form.tsx +360 -0
  253. package/src/components/sections/admin-projects/projects-list.test.tsx +110 -0
  254. package/src/components/sections/admin-projects/projects-list.tsx +215 -0
  255. package/src/components/sections/admin-settings/constants.ts +71 -0
  256. package/src/components/sections/admin-settings/danger-zone.test.tsx +129 -0
  257. package/src/components/sections/admin-settings/danger-zone.tsx +123 -0
  258. package/src/components/sections/admin-settings/index.ts +1 -0
  259. package/src/components/sections/admin-settings/password-form.test.tsx +116 -0
  260. package/src/components/sections/admin-settings/password-form.tsx +130 -0
  261. package/src/components/sections/admin-settings/profile-form.test.tsx +118 -0
  262. package/src/components/sections/admin-settings/profile-form.tsx +143 -0
  263. package/src/components/sections/admin-settings/save-button.tsx +43 -0
  264. package/src/components/sections/admin-settings/settings-page.tsx +60 -0
  265. package/src/components/sections/admin-settings/settings-section.tsx +38 -0
  266. package/src/components/sections/admin-settings/site-form.test.tsx +135 -0
  267. package/src/components/sections/admin-settings/site-form.tsx +205 -0
  268. package/src/components/sections/admin-settings/socials-form.test.tsx +94 -0
  269. package/src/components/sections/admin-settings/socials-form.tsx +123 -0
  270. package/src/components/sections/admin-skills/constants.test.ts +85 -0
  271. package/src/components/sections/admin-skills/constants.ts +56 -0
  272. package/src/components/sections/admin-skills/index.ts +3 -0
  273. package/src/components/sections/admin-skills/skill-form-page.tsx +106 -0
  274. package/src/components/sections/admin-skills/skill-form.tsx +234 -0
  275. package/src/components/sections/admin-skills/skills-list.tsx +214 -0
  276. package/src/components/sections/admin-translations/constants.ts +21 -0
  277. package/src/components/sections/admin-translations/index.ts +1 -0
  278. package/src/components/sections/admin-translations/message-field.tsx +96 -0
  279. package/src/components/sections/admin-translations/message-tree.ts +95 -0
  280. package/src/components/sections/admin-translations/translations-editor.test.tsx +197 -0
  281. package/src/components/sections/admin-translations/translations-editor.tsx +236 -0
  282. package/src/components/sections/admin-trash/constants.ts +105 -0
  283. package/src/components/sections/admin-trash/index.ts +10 -0
  284. package/src/components/sections/admin-trash/trash-list.test.tsx +163 -0
  285. package/src/components/sections/admin-trash/trash-list.tsx +177 -0
  286. package/src/components/sections/admin-trash/trash-row.tsx +76 -0
  287. package/src/components/sections/certificate-detail/certificate-detail-content.tsx +117 -0
  288. package/src/components/sections/certificate-detail/certificate-detail-hero.tsx +87 -0
  289. package/src/components/sections/certificate-detail/certificate-detail-navigation.tsx +75 -0
  290. package/src/components/sections/certificate-detail/certificate-detail.tsx +29 -0
  291. package/src/components/sections/certificate-detail/constants.ts +4 -0
  292. package/src/components/sections/certificate-detail/index.ts +4 -0
  293. package/src/components/sections/certificates/certificate-card.tsx +138 -0
  294. package/src/components/sections/certificates/certificates-background.tsx +10 -0
  295. package/src/components/sections/certificates/certificates-section.tsx +80 -0
  296. package/src/components/sections/certificates/constants.test.ts +78 -0
  297. package/src/components/sections/certificates/constants.ts +84 -0
  298. package/src/components/sections/certificates/index.ts +3 -0
  299. package/src/components/sections/contact/constants.ts +16 -0
  300. package/src/components/sections/contact/contact-form.test.tsx +167 -0
  301. package/src/components/sections/contact/contact-form.tsx +181 -0
  302. package/src/components/sections/contact/contact-info.test.tsx +74 -0
  303. package/src/components/sections/contact/contact-info.tsx +90 -0
  304. package/src/components/sections/contact/contact.tsx +44 -0
  305. package/src/components/sections/contact/index.ts +4 -0
  306. package/src/components/sections/experience/constants.ts +20 -0
  307. package/src/components/sections/experience/experience-card.tsx +151 -0
  308. package/src/components/sections/experience/experience-timeline.tsx +66 -0
  309. package/src/components/sections/experience/experience.tsx +56 -0
  310. package/src/components/sections/experience/index.ts +1 -0
  311. package/src/components/sections/experience-detail/constants.ts +14 -0
  312. package/src/components/sections/experience-detail/experience-detail-content.tsx +50 -0
  313. package/src/components/sections/experience-detail/experience-detail-gallery.tsx +70 -0
  314. package/src/components/sections/experience-detail/experience-detail-hero.tsx +101 -0
  315. package/src/components/sections/experience-detail/experience-detail-lightbox.tsx +44 -0
  316. package/src/components/sections/experience-detail/experience-detail-navigation.tsx +87 -0
  317. package/src/components/sections/experience-detail/experience-detail.tsx +57 -0
  318. package/src/components/sections/experience-detail/index.ts +1 -0
  319. package/src/components/sections/experience-detail/use-experience-detail.ts +24 -0
  320. package/src/components/sections/experience-list/constants.ts +19 -0
  321. package/src/components/sections/experience-list/experience-list-item.tsx +92 -0
  322. package/src/components/sections/hero/constants.ts +1 -0
  323. package/src/components/sections/hero/hero-background.tsx +29 -0
  324. package/src/components/sections/hero/hero-content.tsx +190 -0
  325. package/src/components/sections/hero/hero.tsx +16 -0
  326. package/src/components/sections/hero/index.ts +1 -0
  327. package/src/components/sections/page-hero/constants.ts +33 -0
  328. package/src/components/sections/page-hero/index.ts +1 -0
  329. package/src/components/sections/page-hero/page-hero.test.tsx +58 -0
  330. package/src/components/sections/page-hero/page-hero.tsx +113 -0
  331. package/src/components/sections/project-detail/constants.ts +14 -0
  332. package/src/components/sections/project-detail/index.ts +1 -0
  333. package/src/components/sections/project-detail/project-detail-content.tsx +101 -0
  334. package/src/components/sections/project-detail/project-detail-gallery.tsx +100 -0
  335. package/src/components/sections/project-detail/project-detail-hero.tsx +78 -0
  336. package/src/components/sections/project-detail/project-detail-lightbox.tsx +51 -0
  337. package/src/components/sections/project-detail/project-detail-navigation.tsx +124 -0
  338. package/src/components/sections/project-detail/project-detail.tsx +54 -0
  339. package/src/components/sections/projects/constants.ts +26 -0
  340. package/src/components/sections/projects/index.ts +3 -0
  341. package/src/components/sections/projects/map-project.ts +38 -0
  342. package/src/components/sections/projects/project-card.tsx +108 -0
  343. package/src/components/sections/projects/projects-background.tsx +10 -0
  344. package/src/components/sections/projects/projects.tsx +73 -0
  345. package/src/components/seo/structured-data.test.tsx +82 -0
  346. package/src/components/seo/structured-data.tsx +96 -0
  347. package/src/components/ui/alert-dialog.tsx +187 -0
  348. package/src/components/ui/badge.tsx +52 -0
  349. package/src/components/ui/button.tsx +58 -0
  350. package/src/components/ui/card.tsx +103 -0
  351. package/src/components/ui/chart.tsx +373 -0
  352. package/src/components/ui/confirm-action-dialog.test.tsx +81 -0
  353. package/src/components/ui/confirm-action-dialog.tsx +69 -0
  354. package/src/components/ui/empty-state.tsx +33 -0
  355. package/src/components/ui/glass-card.test.tsx +43 -0
  356. package/src/components/ui/glass-card.tsx +63 -0
  357. package/src/components/ui/image-upload.tsx +207 -0
  358. package/src/components/ui/input.tsx +24 -0
  359. package/src/components/ui/label.tsx +19 -0
  360. package/src/components/ui/lazy-section.tsx +49 -0
  361. package/src/components/ui/magnetic-button.test.tsx +69 -0
  362. package/src/components/ui/magnetic-button.tsx +102 -0
  363. package/src/components/ui/multi-image-upload.tsx +281 -0
  364. package/src/components/ui/not-found-button.tsx +15 -0
  365. package/src/components/ui/pagination.tsx +110 -0
  366. package/src/components/ui/skeleton.tsx +13 -0
  367. package/src/components/ui/sonner.tsx +49 -0
  368. package/src/components/ui/switch.tsx +41 -0
  369. package/src/components/ui/textarea.tsx +23 -0
  370. package/src/components/ui/theme-toggle-floating.test.tsx +48 -0
  371. package/src/components/ui/theme-toggle-floating.tsx +105 -0
  372. package/src/components/ui/turnstile.tsx +74 -0
  373. package/src/components/visit-tracker.tsx +43 -0
  374. package/src/generated/prisma/browser.ts +89 -0
  375. package/src/generated/prisma/client.ts +113 -0
  376. package/src/generated/prisma/commonInputTypes.ts +671 -0
  377. package/src/generated/prisma/enums.ts +49 -0
  378. package/src/generated/prisma/internal/class.ts +334 -0
  379. package/src/generated/prisma/internal/prismaNamespace.ts +2162 -0
  380. package/src/generated/prisma/internal/prismaNamespaceBrowser.ts +359 -0
  381. package/src/generated/prisma/models/Account.ts +1635 -0
  382. package/src/generated/prisma/models/Category.ts +1469 -0
  383. package/src/generated/prisma/models/Certificate.ts +1566 -0
  384. package/src/generated/prisma/models/Experience.ts +1567 -0
  385. package/src/generated/prisma/models/Message.ts +1265 -0
  386. package/src/generated/prisma/models/Project.ts +1880 -0
  387. package/src/generated/prisma/models/RateLimit.ts +1187 -0
  388. package/src/generated/prisma/models/Session.ts +1450 -0
  389. package/src/generated/prisma/models/SiteSettings.ts +1460 -0
  390. package/src/generated/prisma/models/Skill.ts +1315 -0
  391. package/src/generated/prisma/models/Translation.ts +1115 -0
  392. package/src/generated/prisma/models/User.ts +1710 -0
  393. package/src/generated/prisma/models/Verification.ts +1434 -0
  394. package/src/generated/prisma/models/Visit.ts +1375 -0
  395. package/src/generated/prisma/models.ts +25 -0
  396. package/src/hooks/use-categories.ts +66 -0
  397. package/src/hooks/use-certificates.ts +66 -0
  398. package/src/hooks/use-dashboard-stats.ts +25 -0
  399. package/src/hooks/use-entity-id.test.tsx +89 -0
  400. package/src/hooks/use-entity-id.ts +20 -0
  401. package/src/hooks/use-experience.ts +66 -0
  402. package/src/hooks/use-messages.ts +58 -0
  403. package/src/hooks/use-pagination.ts +66 -0
  404. package/src/hooks/use-projects.ts +85 -0
  405. package/src/hooks/use-settings.ts +53 -0
  406. package/src/hooks/use-skills.ts +59 -0
  407. package/src/hooks/use-translation.ts +36 -0
  408. package/src/hooks/use-translations.ts +54 -0
  409. package/src/hooks/use-trash.ts +62 -0
  410. package/src/lib/api-client.ts +56 -0
  411. package/src/lib/api-helpers.ts +52 -0
  412. package/src/lib/auth-captcha.ts +35 -0
  413. package/src/lib/auth-client.ts +14 -0
  414. package/src/lib/auth-security.integration.test.ts +176 -0
  415. package/src/lib/auth.integration.test.ts +117 -0
  416. package/src/lib/auth.ts +98 -0
  417. package/src/lib/contact.integration.test.ts +99 -0
  418. package/src/lib/env.ts +38 -0
  419. package/src/lib/form-schemas.test.ts +252 -0
  420. package/src/lib/i18n.test.ts +94 -0
  421. package/src/lib/i18n.ts +52 -0
  422. package/src/lib/icon-resolver.ts +97 -0
  423. package/src/lib/lazy-providers.tsx +41 -0
  424. package/src/lib/prisma-errors.test.ts +79 -0
  425. package/src/lib/prisma-errors.ts +94 -0
  426. package/src/lib/prisma.ts +21 -0
  427. package/src/lib/providers.tsx +6 -0
  428. package/src/lib/public-content.test.ts +68 -0
  429. package/src/lib/public-content.ts +43 -0
  430. package/src/lib/public-providers.tsx +12 -0
  431. package/src/lib/quick-links.ts +36 -0
  432. package/src/lib/rate-limit.ts +142 -0
  433. package/src/lib/security-log.test.ts +41 -0
  434. package/src/lib/security-log.ts +23 -0
  435. package/src/lib/session.ts +63 -0
  436. package/src/lib/settings.test.ts +163 -0
  437. package/src/lib/settings.ts +144 -0
  438. package/src/lib/soft-delete.integration.test.ts +497 -0
  439. package/src/lib/soft-delete.test.ts +56 -0
  440. package/src/lib/soft-delete.ts +30 -0
  441. package/src/lib/supabase-storage.ts +160 -0
  442. package/src/lib/translation-types.ts +4 -0
  443. package/src/lib/translations.test.ts +255 -0
  444. package/src/lib/translations.ts +163 -0
  445. package/src/lib/turnstile.ts +57 -0
  446. package/src/lib/utils/experience-mapper.ts +73 -0
  447. package/src/lib/utils/project-filter.test.ts +55 -0
  448. package/src/lib/utils/project-filter.ts +23 -0
  449. package/src/lib/utils/skill-group.test.ts +59 -0
  450. package/src/lib/utils/skill-group.ts +27 -0
  451. package/src/lib/utils.test.ts +26 -0
  452. package/src/lib/utils.ts +6 -0
  453. package/src/lib/zod-resolver.test.ts +55 -0
  454. package/src/lib/zod-resolver.ts +31 -0
  455. package/src/messages/en.json +326 -0
  456. package/src/messages/id.json +326 -0
  457. package/src/providers/theme-provider.test.tsx +118 -0
  458. package/src/providers/theme-provider.tsx +132 -0
  459. package/src/proxy.ts +119 -0
  460. package/src/schema/category.ts +46 -0
  461. package/src/schema/certificate.ts +81 -0
  462. package/src/schema/contact.ts +19 -0
  463. package/src/schema/env.ts +63 -0
  464. package/src/schema/experience.ts +90 -0
  465. package/src/schema/login.ts +10 -0
  466. package/src/schema/message.ts +17 -0
  467. package/src/schema/project.ts +74 -0
  468. package/src/schema/settings.ts +116 -0
  469. package/src/schema/skill.ts +49 -0
  470. package/src/stores/theme-store.test.ts +30 -0
  471. package/src/stores/theme-store.ts +18 -0
  472. package/src/test-fixtures/public-content.ts +29 -0
  473. package/src/test-fixtures/render.tsx +33 -0
  474. package/src/types/api.ts +27 -0
  475. package/src/types/domain.ts +348 -0
  476. package/src/types/world-atlas.d.ts +24 -0
  477. package/src/utils/client-ip.test.ts +43 -0
  478. package/src/utils/client-ip.ts +39 -0
  479. package/src/utils/slug.test.ts +24 -0
  480. package/src/utils/slug.ts +11 -0
  481. package/tsconfig.json +34 -0
  482. package/tsconfig.tsbuildinfo +1 -0
  483. package/vercel.json +5 -0
  484. package/vitest.config.ts +36 -0
  485. package/vitest.integration.config.ts +27 -0
  486. package/vitest.setup.ts +39 -0
package/.dockerignore ADDED
@@ -0,0 +1,10 @@
1
+ # .dockerignore
2
+ node_modules
3
+ .next
4
+ .git
5
+ .gitignore
6
+ docker/
7
+ *.md
8
+ .env
9
+ .env.local
10
+ .DS_Store
package/.gitattributes ADDED
@@ -0,0 +1,21 @@
1
+ # Normalize all text files to LF in the repository and working tree.
2
+ # Required: Docker / nginx / Linux containers break with CRLF.
3
+ * text=auto eol=lf
4
+
5
+ # Explicit binary assets (never normalize)
6
+ *.png binary
7
+ *.jpg binary
8
+ *.jpeg binary
9
+ *.gif binary
10
+ *.ico binary
11
+ *.webp binary
12
+ *.avif binary
13
+ *.woff binary
14
+ *.woff2 binary
15
+ *.ttf binary
16
+ *.eot binary
17
+ *.otf binary
18
+ *.pdf binary
19
+ *.mp4 binary
20
+ *.webm binary
21
+ *.mp3 binary
@@ -0,0 +1 @@
1
+ * @Ridho-arachman
@@ -0,0 +1,80 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Description
9
+ description: A clear and concise summary of the bug.
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: steps
15
+ attributes:
16
+ label: Steps to Reproduce
17
+ description: Minimal steps to trigger the bug.
18
+ placeholder: |
19
+ 1. Go to '...'
20
+ 2. Click on '...'
21
+ 3. See error
22
+ validations:
23
+ required: true
24
+
25
+ - type: textarea
26
+ id: expected
27
+ attributes:
28
+ label: Expected Behavior
29
+ description: What should have happened instead?
30
+ validations:
31
+ required: true
32
+
33
+ - type: textarea
34
+ id: actual
35
+ attributes:
36
+ label: Actual Behavior
37
+ description: What actually happened?
38
+ validations:
39
+ required: true
40
+
41
+ - type: input
42
+ id: route
43
+ attributes:
44
+ label: Affected Route
45
+ description: Which route shows the bug? Include the locale prefix.
46
+ placeholder: e.g. /en/projects, /id/about, /admin/login
47
+ validations:
48
+ required: false
49
+
50
+ - type: input
51
+ id: os
52
+ attributes:
53
+ label: Operating System
54
+ placeholder: e.g. Windows 11, macOS 15, Ubuntu 24.04
55
+ validations:
56
+ required: false
57
+
58
+ - type: input
59
+ id: browser
60
+ attributes:
61
+ label: Browser
62
+ placeholder: e.g. Chrome 130, Firefox 133, Safari 18
63
+ validations:
64
+ required: false
65
+
66
+ - type: input
67
+ id: node
68
+ attributes:
69
+ label: Node.js Version
70
+ placeholder: e.g. 24.0.0
71
+ validations:
72
+ required: false
73
+
74
+ - type: textarea
75
+ id: screenshots
76
+ attributes:
77
+ label: Screenshots
78
+ description: If applicable, add screenshots to help explain the problem.
79
+ validations:
80
+ required: false
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question
4
+ url: https://github.com/Ridho-arachman/portfolio/discussions
5
+ about: Ask questions and discuss ideas
@@ -0,0 +1,35 @@
1
+ name: Feature Request
2
+ description: Suggest a new feature or improvement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem
9
+ description: What problem does this feature solve? Is it related to a frustration?
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: solution
15
+ attributes:
16
+ label: Proposed Solution
17
+ description: How should this feature work?
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: alternatives
23
+ attributes:
24
+ label: Alternatives Considered
25
+ description: Have you considered any other approaches?
26
+ validations:
27
+ required: false
28
+
29
+ - type: textarea
30
+ id: context
31
+ attributes:
32
+ label: Additional Context
33
+ description: Any other context, mockups, or screenshots.
34
+ validations:
35
+ required: false
@@ -0,0 +1,26 @@
1
+ ## Description
2
+
3
+ <!-- Briefly describe what this PR does and why. -->
4
+
5
+ ## Type of Change
6
+
7
+ - [ ] `feat` โ€” New feature
8
+ - [ ] `fix` โ€” Bug fix
9
+ - [ ] `refactor` โ€” Code refactor (no behavior change)
10
+ - [ ] `chore` โ€” Tooling, config, or dependency update
11
+ - [ ] `docs` โ€” Documentation only
12
+
13
+ ## Checklist
14
+
15
+ - [ ] `npm run lint` passes (0 errors)
16
+ - [ ] `npx tsc --noEmit` passes
17
+ - [ ] `npm run build` passes (incl. `[lang]` routes EN/ID)
18
+ - [ ] `npm run test:unit` passes
19
+ - [ ] `npm run test:integration` passes (if API/DB touched)
20
+ - [ ] `npm run test:e2e` passes (if user flow touched)
21
+ - [ ] Commit message follows Conventional Commits (`feat:` / `fix:` / ...)
22
+ - [ ] Self-reviewed the diff
23
+
24
+ ## Screenshots (if UI change)
25
+
26
+ <!-- Before/after screenshots, or "N/A" -->
@@ -0,0 +1,43 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 0.1.x | :white_check_mark: |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ If you discover a security vulnerability, please report it responsibly.
12
+
13
+ **Do NOT open a public GitHub issue.**
14
+
15
+ Instead, please email: **ridho.arachman22@gmail.com**
16
+
17
+ Include:
18
+
19
+ - Description of the vulnerability
20
+ - Steps to reproduce
21
+ - Potential impact
22
+
23
+ You should receive a response within **48 hours**. We will work with you to understand and address the issue before any public disclosure.
24
+
25
+ ## Enforced Controls
26
+
27
+ - Cloudflare Turnstile is fail-closed in production (`TURNSTILE_SECRET_KEY` is required at boot; CI/build uses the official test keys).
28
+ - Test bypasses (`DISABLE_RATE_LIMIT`, empty captcha) are ignored when `NODE_ENV=production`.
29
+ - Admin API requires an `ADMIN` session; destructive actions (purge, settings reset) need explicit confirmation and emit a JSON audit line to stdout.
30
+ - Rate limiting is atomic (DB transaction) and keyed by validated client IP.
31
+ - Public API returns explicit selects only โ€” no internal columns (`deletedAt`, ordering, timestamps).
32
+
33
+ ## Scope
34
+
35
+ This policy applies to vulnerabilities found in:
36
+
37
+ - The portfolio web application
38
+ - API routes and authentication flows
39
+ - Docker and deployment configurations
40
+
41
+ ## Disclosure
42
+
43
+ We follow responsible disclosure. Once a fix is released, we will credit the reporter (unless they prefer to remain anonymous).
@@ -0,0 +1,47 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "npm"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ day: "monday"
8
+ # 0 = Dependabot proposes no version updates. The weekly run kept refilling
9
+ # open-pull-requests-limit slots from a backlog deeper than it looked, so
10
+ # merging never reached an empty queue. To resume updates, change 0 back to
11
+ # a number (5-10) โ€” the ignore/groups rules below stay ready.
12
+ open-pull-requests-limit: 0
13
+ ignore:
14
+ # eslint-plugin-react has no ESLint 10 release (latest peer stops at ^9.7),
15
+ # so `npm run lint` dies on 'react/display-name' (PR #37). Lift when it
16
+ # adds ^10 to its peer range.
17
+ - dependency-name: "eslint"
18
+ versions: [">=10.0.0"]
19
+ groups:
20
+ react:
21
+ patterns:
22
+ - "react"
23
+ - "react-dom"
24
+ # @vitest/coverage-v8 pins an exact peer on vitest; splitting them makes
25
+ # `npm ci` fail with ERESOLVE (PR #34).
26
+ vitest:
27
+ patterns:
28
+ - "vitest"
29
+ - "@vitest/coverage-v8"
30
+ dev-dependencies:
31
+ dependency-type: "development"
32
+ update-types:
33
+ - "minor"
34
+ - "patch"
35
+ labels:
36
+ - "dependencies"
37
+ - "chore"
38
+
39
+ - package-ecosystem: "github-actions"
40
+ directory: "/"
41
+ schedule:
42
+ interval: "weekly"
43
+ day: "monday"
44
+ open-pull-requests-limit: 0
45
+ labels:
46
+ - "dependencies"
47
+ - "ci"
@@ -0,0 +1,171 @@
1
+ name: CI Pipeline
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: ["main", "develop"]
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ ci-test:
16
+ name: Lint, Typecheck, Build, Unit & Docker Test
17
+ runs-on: ubuntu-latest
18
+
19
+ services:
20
+ postgres:
21
+ image: postgres:16-alpine
22
+ env:
23
+ POSTGRES_USER: postgres
24
+ POSTGRES_PASSWORD: postgres
25
+ POSTGRES_DB: portfolio_test
26
+ ports:
27
+ - 5432:5432
28
+ options: >-
29
+ --health-cmd "pg_isready -U postgres -d portfolio_test"
30
+ --health-interval 10s
31
+ --health-timeout 5s
32
+ --health-retries 5
33
+
34
+ steps:
35
+ - name: ๐Ÿ“‚ Checkout repository
36
+ uses: actions/checkout@v7
37
+
38
+ - name: ๐ŸŸข Setup Node.js
39
+ uses: actions/setup-node@v7
40
+ with:
41
+ node-version: 24
42
+ cache: "npm"
43
+
44
+ - name: ๐Ÿ“ฆ Install dependencies
45
+ run: npm ci
46
+
47
+ - name: ๐Ÿ—„๏ธ Generate Prisma Client
48
+ run: npx prisma generate
49
+
50
+ - name: ๐Ÿ” Run Linter
51
+ run: npm run lint
52
+
53
+ - name: ๐Ÿง  Type Checking
54
+ run: npx tsc --noEmit
55
+
56
+ - name: ๐Ÿงช Unit Tests
57
+ run: npm run test:unit
58
+
59
+ - name: ๐Ÿ—๏ธ Build Next.js App
60
+ env:
61
+ DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/portfolio_test"
62
+ BETTER_AUTH_SECRET: "ci-build-secret-1234567890abcdefghijklmnop"
63
+ BETTER_AUTH_URL: "http://localhost:3000"
64
+ NEXT_PUBLIC_SUPABASE_URL: "https://placeholder.supabase.co"
65
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: "placeholder-anon-key"
66
+ SUPABASE_SERVICE_ROLE_KEY: "placeholder-service-key"
67
+ # Wajib sejak validasi env fail-closed prod (env.ts): Cloudflare test keys resmi, selalu lolos.
68
+ NEXT_PUBLIC_TURNSTILE_SITE_KEY: "1x00000000000000000000AA"
69
+ TURNSTILE_SECRET_KEY: "1x0000000000000000000000000000000AA"
70
+ run: |
71
+ npx prisma db push
72
+ npm run build
73
+
74
+ - name: ๐Ÿณ Test Docker Build (PENTING!)
75
+ run: |
76
+ echo "Validasi Dockerfile (deps stage only)..."
77
+ docker build -f docker/Dockerfile.prod -t nextjs-app:ci-test --target deps .
78
+ echo "โœ… Docker build berhasil! File .dockerignore dan Dockerfile aman."
79
+
80
+ test-integration:
81
+ name: Integration Tests
82
+ runs-on: ubuntu-latest
83
+
84
+ services:
85
+ postgres:
86
+ image: postgres:16-alpine
87
+ env:
88
+ POSTGRES_USER: postgres
89
+ POSTGRES_PASSWORD: postgres
90
+ POSTGRES_DB: portfolio_test
91
+ ports:
92
+ - 5432:5432
93
+ options: >-
94
+ --health-cmd "pg_isready -U postgres -d portfolio_test"
95
+ --health-interval 10s
96
+ --health-timeout 5s
97
+ --health-retries 5
98
+
99
+ env:
100
+ DATABASE_URL: postgresql://postgres:postgres@localhost:5432/portfolio_test
101
+ BETTER_AUTH_SECRET: ci-integration-test-secret-1234567890abcdef
102
+ BETTER_AUTH_URL: http://localhost:3000
103
+
104
+ steps:
105
+ - name: ๐Ÿ“‚ Checkout repository
106
+ uses: actions/checkout@v7
107
+
108
+ - name: ๐ŸŸข Setup Node.js
109
+ uses: actions/setup-node@v7
110
+ with:
111
+ node-version: 24
112
+ cache: "npm"
113
+
114
+ - name: ๐Ÿ“ฆ Install dependencies
115
+ run: npm ci
116
+
117
+ - name: ๐Ÿ—„๏ธ Generate Prisma Client
118
+ run: npx prisma generate
119
+
120
+ - name: ๐Ÿ—„๏ธ Push schema to test database
121
+ run: npx prisma db push
122
+
123
+ - name: ๐Ÿงช Integration Tests
124
+ run: npx vitest run --config vitest.integration.config.ts
125
+
126
+ e2e:
127
+ name: End-to-End Tests
128
+ runs-on: ubuntu-latest
129
+
130
+ services:
131
+ postgres:
132
+ image: postgres:16-alpine
133
+ env:
134
+ POSTGRES_USER: postgres
135
+ POSTGRES_PASSWORD: postgres
136
+ POSTGRES_DB: portfolio_test
137
+ ports:
138
+ - 5432:5432
139
+ options: >-
140
+ --health-cmd "pg_isready -U postgres -d portfolio_test"
141
+ --health-interval 10s
142
+ --health-timeout 5s
143
+ --health-retries 5
144
+
145
+ env:
146
+ DATABASE_URL: postgresql://postgres:postgres@localhost:5432/portfolio_test
147
+
148
+ steps:
149
+ - name: ๐Ÿ“‚ Checkout repository
150
+ uses: actions/checkout@v7
151
+
152
+ - name: ๐ŸŸข Setup Node.js
153
+ uses: actions/setup-node@v7
154
+ with:
155
+ node-version: 24
156
+ cache: "npm"
157
+
158
+ - name: ๐Ÿ“ฆ Install dependencies
159
+ run: npm ci
160
+
161
+ - name: ๐Ÿ—„๏ธ Push schema to test database
162
+ run: npx prisma db push
163
+
164
+ - name: ๐Ÿ–ฅ๏ธ Install Playwright browsers
165
+ run: npx playwright install --with-deps chromium
166
+
167
+ - name: ๐Ÿงฌ Generate Prisma Client
168
+ run: npx prisma generate
169
+
170
+ - name: ๐Ÿงช End-to-End Tests
171
+ run: npm run test:e2e
@@ -0,0 +1,68 @@
1
+ name: Publish to npm
2
+
3
+ # Every push to main publishes a new patch version to npm, so the
4
+ # registry copy is always fresh. Requires repo secret NPM_TOKEN
5
+ # (npmjs.com -> Access Tokens -> publish permission).
6
+
7
+ on:
8
+ push:
9
+ branches: ["main"]
10
+ workflow_dispatch:
11
+
12
+ # Serialize publishes; never cancel a publish in flight (avoids
13
+ # duplicate-version races when pushes land close together).
14
+ concurrency:
15
+ group: npm-publish
16
+ cancel-in-progress: false
17
+
18
+ permissions:
19
+ contents: write
20
+
21
+ jobs:
22
+ publish:
23
+ # The version-bump commit this workflow pushes itself must not
24
+ # trigger another publish (infinite loop guard).
25
+ if: "!contains(github.event.head_commit.message, '[skip ci]')"
26
+ name: Bump patch and publish
27
+ runs-on: ubuntu-latest
28
+
29
+ steps:
30
+ - name: ๐Ÿ“‚ Checkout repository
31
+ uses: actions/checkout@v7
32
+
33
+ - name: ๐ŸŸข Setup Node.js with npm registry
34
+ uses: actions/setup-node@v7
35
+ with:
36
+ node-version: 24
37
+ cache: "npm"
38
+ registry-url: "https://registry.npmjs.org"
39
+
40
+ - name: ๐Ÿ”ง Git identity for version commit
41
+ run: |
42
+ git config user.name "github-actions[bot]"
43
+ git config user.email "github-actions[bot]@users.noreply.github.com"
44
+
45
+ - name: ๐Ÿ“ฆ Install dependencies
46
+ run: npm ci
47
+
48
+ - name: ๐Ÿ—„๏ธ Generate Prisma Client (no DB needed)
49
+ run: npx prisma generate
50
+
51
+ - name: ๐Ÿง  Typecheck gate (do not publish broken code)
52
+ run: npx tsc --noEmit
53
+
54
+ - name: ๐Ÿ”ข Bump patch version ([skip ci] avoids re-trigger)
55
+ run: |
56
+ npm version patch --no-git-tag-version
57
+ VERSION=$(node -p "require('./package.json').version")
58
+ git add package.json
59
+ git commit -m "chore(release): $VERSION [skip ci]"
60
+ git tag "v$VERSION"
61
+
62
+ - name: ๐Ÿš€ Publish to npm
63
+ run: npm publish --access public
64
+ env:
65
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
66
+
67
+ - name: ๐Ÿท๏ธ Push version commit and tag
68
+ run: git push --follow-tags
@@ -0,0 +1 @@
1
+ npx --no -- commitlint --edit $1
@@ -0,0 +1 @@
1
+ echo "tunggu!!!"