Compare commits

...

182 Commits

Author SHA1 Message Date
8777c45a44 fix(build): resolve ESLint and type errors causing build failure 2026-04-01 17:44:48 +08:00
b751f031cd fix(auth/swagger): make WA failure non-fatal and include /api prefix in docs 2026-04-01 17:04:25 +08:00
a3940321a7 fix(api): move swagger to /api group to prevent double prefixing 2026-04-01 15:29:26 +08:00
3cd6fcbd81 fix(api): clean up redundant /api prefixes and fix swagger documentation 2026-04-01 15:24:12 +08:00
7d9b7b0c60 feat(apbdes): finalize modernization and update config 2026-04-01 15:15:01 +08:00
0806eb2308 feat(apbdes): modernize ui, charts and refactor (Phase 1, 2, 4) 2026-04-01 15:09:40 +08:00
51ce823b45 Fix: Use window.location.origin for API base URL in browser
treaty from @elysiajs/eden doesn't support relative URLs like '/'
This caused 'ERR_NAME_NOT_RESOLVED' when trying to access 'https://api/fileStorage/create'

Solution:
- Client-side: Use window.location.origin (e.g., https://desa-darmasaba-stg.wibudev.com)
- Server-side dev: Use localhost:3000
- Server-side prod: Use NEXT_PUBLIC_BASE_URL env var

This ensures the API calls use the correct domain in all environments.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-12 14:14:55 +08:00
f6f0e10935 Fix Url API Route 2026-03-12 12:11:10 +08:00
2108f403aa Update .env.example to use relative URL '/' as default for NEXT_PUBLIC_BASE_URL
This ensures the API uses the same protocol and domain as the frontend,
preventing mixed content blocking in staging/production environments.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-12 12:06:16 +08:00
c6c3eebadf Fix: CORS and API base URL for music create in staging
- Update CORS config to allow all origins (wildcard first) for better staging support
- Change API fetch base URL from absolute to relative (/) to prevent mixed content blocking
- Add detailed logging in music create page for better debugging
- Update .env.example with better NEXT_PUBLIC_BASE_URL documentation
- Add MUSIK_CREATE_ANALYSIS.md with comprehensive error analysis

Fixes ERR_BLOCKED_BY_CLIENT error when creating music in staging environment

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-12 11:27:51 +08:00
bipproduction
0dabc204bc Revert standalone output, keep serverExternalPackages fix
- Remove output: standalone to keep migration/seed workflow
- Restore original Dockerfile structure with full node_modules copy
- Keep serverExternalPackages for @elysiajs/static and elysia to fix
  the Html prerender error caused by dynamic import in @elysiajs/static
- Keep NODE_ENV=production before build step

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:53:18 +08:00
bipproduction
e8f8b51686 Fix build: externalize elysia packages, use standalone output, fix NODE_ENV
- Add serverExternalPackages for @elysiajs/static and elysia to prevent
  webpack from bundling dynamic imports that cause Html prerender error
- Use output: standalone for proper Docker deployment
- Comment out NODE_ENV=development in .env.example to avoid conflict
  with next build which requires NODE_ENV=production
- Set NODE_ENV=production before build step in Dockerfile
- Update runtime stage to use standalone output structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:48:05 +08:00
bipproduction
a4db3a149d Fix build error: move ViewTransitions inside body to fix 404 prerendering
ViewTransitions was wrapping the html element, which violates Next.js App
Router requirement that html and body be returned directly from root layout.
This caused prerendering of /404 to fail with Html import error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:29:29 +08:00
bipproduction
fece983ac5 Fix Dockerfile: remove non-existent gen:api script and fix build output paths
- Remove bun run gen:api which does not exist in package.json
- Change dist to .next for correct Next.js build output
- Replace non-existent generated/ with public/ for static assets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:12:33 +08:00
8b7eef5fee New bunlock.b 2026-03-10 11:04:44 +08:00
8b22d01e0d FIx Docker File 2026-03-10 10:56:15 +08:00
dc13e37a02 Add .env.example and fix .gitignore to allow it
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-10 10:50:52 +08:00
2d2cbef29b Tambah File Docker 2026-03-10 10:42:51 +08:00
8c8a96b830 First Stg 2026-03-10 10:07:14 +08:00
dc3eccacbf First Stg 2026-03-10 10:03:33 +08:00
ffe94992e5 StaggingWeb 2026-03-09 16:44:42 +08:00
4fb522f88f Fix Eror Grafik Realisasi-3 2026-03-06 12:03:22 +08:00
85332a8225 Merge pull request 'Fix Eror Grafik Realisasi-2' (#78) from nico/6-mar-26/fix-container-portainer-1 into staggingweb
Reviewed-on: #78
2026-03-06 11:24:46 +08:00
3fe2a5ccab Fix Eror Grafik Realisasi-2 2026-03-06 11:19:45 +08:00
363bfa65fb Merge pull request 'Fix Eror Grafik Realisasi' (#77) from nico/6-mar-26/fix-container-portainer-1 into staggingweb
Reviewed-on: #77
2026-03-06 10:53:19 +08:00
dccf590cbf Fix Eror Grafik Realisasi 2026-03-06 10:52:10 +08:00
f076b81d14 Merge pull request 'Fix Prisma 1' (#76) from nico/6-mar-26/fix-container-portainer-1 into staggingweb
Reviewed-on: #76
2026-03-06 10:35:54 +08:00
b5ea3216e0 Fix Prisma 1 2026-03-06 10:31:19 +08:00
64b116588b Merge pull request 'nico/5-mar-26/fix-musik-fix-apbdes' (#75) from nico/5-mar-26/fix-musik-fix-apbdes into staggingweb
Reviewed-on: #75
2026-03-05 16:38:07 +08:00
63161e1a39 Fix tombolreplay, posisi tombol, posisi icon music. Fix create & edit apbdes upload image dan file optional 2026-03-05 16:36:12 +08:00
8b8c65dd1e fix(apbdes-edit): clear imageId/fileId when user removes preview
Problem:
- Saat user klik X button untuk hapus preview image/file
- Form state masih menyimpan imageId/fileId lama
- Saat submit, data lama tetap terkirim
- User tidak bisa benar-benar menghapus image/file

Solution:
- Clear apbdesState.edit.form.imageId saat hapus preview gambar
- Clear apbdesState.edit.form.fileId saat hapus preview dokumen
- Now user can truly make image/file empty

Files changed:
- src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 16:26:34 +08:00
159fb3cec6 feat(apbdes): make image and file optional for edit page too
Changes:

Backend (updt.ts, index.ts):
- Update FormUpdateBody: imageId?: string | null
- Update Elysia schema: t.Optional(t.String())
- Handle null/undefined values when updating

UI (edit/page.tsx):
- Remove mandatory validation for imageId and fileId
- Update labels to show '(Opsional)'
- Simplify handleSubmit logic (no validation check)
- Keep existing file IDs if no new upload

User Flow:
Before: Edit required imageId and fileId to be present
After: Can update APBDes without files, preserve existing or set to null

Files changed:
- src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts
- src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts
- src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 15:53:26 +08:00
4821934224 fix(music-player): fix floating icon position shift on hover
Problem:
- Icon bergeser ke bawah saat hover
- transform: 'scale(1.1)' mengganti transform: 'translateY(-80%)'
- CSS transform property di-replace, bukan di-mix

Solution:
- Gabungkan kedua transform dalam satu string
- Hover: 'translateY(-80%) scale(1.1)' - maintain posisi + scale
- Leave: 'translateY(-80%)' - kembali ke posisi semula

Changes:
- onMouseEnter: transform = 'translateY(-80%) scale(1.1)'
- onMouseLeave: transform = 'translateY(-80%)'
- Added 'ease' timing function for smoother transition

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 14:53:38 +08:00
ee39b88b00 feat(music-player): add minimize feature with floating icon and centered controls
Layout Changes:
- Center all control buttons (shuffle, prev, play/pause, next, repeat)
- Center progress bar alongside controls
- Keep volume control + close button on the right
- Song info remains on the left

New Feature - Minimize Player:
- Add isMinimized state to track player visibility
- Replace close button with minimize functionality
- Show floating music icon when minimized (bottom-right corner)
- Click floating icon to restore player bar
- Floating icon has hover scale animation for better UX

UI/UX Improvements:
- Better visual hierarchy with centered controls
- Floating icon uses blue bg with white music icon
- Smooth transitions between states
- Icon scales on hover for interactive feedback
- Persistent player state (song continues playing when minimized)

Files changed:
- src/app/darmasaba/_com/FixedPlayerBar.tsx: Complete redesign

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 14:14:46 +08:00
ce46d3b5f7 fix(music-player): fix repeat button not working due to stale closure
Problem:
- Tombol repeat tidak berfungsi saat lagu selesai
- Event listener 'ended' menggunakan variabel state 'isRepeat' dari closure yang lama
- Meskipun state sudah di-toggle, event listener masih menggunakan nilai lama

Solution:
- Tambahkan isRepeatRef untuk menyimpan nilai terbaru dari isRepeat
- Sync ref dengan state menggunakan useEffect
- Gunakan isRepeatRef.current di event listener 'ended'
- Remove isRepeat dari dependency array useEffect

Files changed:
- src/app/context/MusicContext.tsx: Add isRepeatRef and sync with state

This ensures the repeat functionality works correctly when the song ends.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 13:54:15 +08:00
144ac37e12 fix(public-apbdes): fix realisasi display on public APBDes page
- Fix types.ts transformAPBDesData to map totalRealisasi → realisasi
  - Backend returns totalRealisasi, frontend expects realisasi
  - Add fallback to use item.realisasi if totalRealisasi not available

- Fix grafikRealisasi.tsx to use realisasi field
  - Update Summary component to use i.realisasi || i.totalRealisasi
  - Update total calculation to use realisasi field

- Fix apbDesaTable.tsx to use realisasi field
  - Update total calculation to use item.realisasi

- Fix apbDesaProgress.tsx to use realisasi field
  - Update calcTotal to use item.realisasi with fallback

Root cause: Backend Prisma schema uses 'totalRealisasi' field, but public
page components were expecting 'realisasi' field.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 11:27:28 +08:00
f90477ed63 fix(apbdes-edit): preserve realisasi data when editing APBDes
- Fix backend updt.ts to preserve realisasiItems from old items
  - Load existing items with realisasiItems before delete
  - Re-create realisasiItems for new items based on kode match
  - Recalculate totalRealisasi, selisih, persentase after restore

- Update frontend state to handle realisasi fields
  - Add realisasi, selisih, persentase to ApbdesItemSchema
  - Fix edit.load() to map totalRealisasi → realisasi
  - Fix edit.update() to omit calculated fields when sending to backend

- Update edit page.tsx to display realisasi data
  - Fix load data to use item.totalRealisasi (not item.realisasi)
  - Add Realisasi, Selisih, % columns to items table
  - Update handleAddItem and handleReset to preserve realisasi fields

Root cause: Backend was resetting totalRealisasi=0 for all items on update,
and frontend was accessing wrong field name (realisasi vs totalRealisasi)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-05 11:20:45 +08:00
4a7811e06f Merge pull request 'Fix Tabel Apbdes, & fix muciplayer in background' (#74) from nico/4-mar-26/fix-musik-play-bg into staggingweb
Reviewed-on: #74
2026-03-04 16:41:25 +08:00
f63aaf916d Fix Tabel Apbdes, & fix muciplayer in background 2026-03-04 16:28:06 +08:00
3803c79c95 Merge pull request 'nico/4-mar-26/realiasasi-apbdes' (#73) from nico/4-mar-26/realiasasi-apbdes into staggingweb
Reviewed-on: #73
2026-03-04 12:03:46 +08:00
2d901912ea fix(realisasi): add kode field to RealisasiItem and simplify table display
- Add kode field to RealisasiItem model in Prisma schema
- Update API endpoints (create, update) to accept kode parameter
- Update state management with proper type definitions
- Add kode input field in RealisasiManager component
- Simplify realisasiTable to show flat list (Kode, Uraian, Realisasi, %)
- Remove section grouping and expandable details
- Fix race condition in findUnique.load() with loading guard
- Fix linting errors across multiple files

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-04 11:51:58 +08:00
a791efe76c fix(grafik): sync grafikRealisasi with totalRealisasi field
Fix:
- Change i.realisasi to i.totalRealisasi in Summary component
- Change i.realisasi to i.totalRealisasi in total calculation
- Add fragment wrapper <> to fix Box children type error
- Reorder Total Keseluruhan section to top (before category breakdown)

Now grafik shows correct data from multiple realisasi items.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 16:47:26 +08:00
e9f7bc2043 feat(ui landing): add expandable realisasi detail in RealisasiTable
Features:
- Add expandable rows for each APBDes item
- Show detailed realisasi breakdown per item
- Each realisasi shows:
  * Keterangan/Uraian
  * Jumlah (formatted in Rupiah)
  * Tanggal (formatted date)
- Chevron icon indicator (right/down)
- Click row to expand/collapse
- Hover effect on clickable rows
- Info text: "Klik pada item untuk melihat detail realisasi"

UI Components:
- RealisasiDetail: Component to display list of realisasi
- ItemRow: Expandable row with click handler
- Updated Section: Manage expanded state per item

Styling:
- Gray background for detail section
- Blue color for amount
- Dimmed color for date
- Responsive layout with wrap="nowrap"
- Proper spacing between items

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 16:38:15 +08:00
6712da9ac2 fix(ui): replace Title with Text in Modal title to avoid h5 in h2 nesting
Fix:
- Change Modal title from <Title order={5}> to <Text fz='lg' fw={600}>
- Avoids invalid HTML nesting (<h5> cannot be child of <h2>)
- Maintains same visual appearance

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 16:21:27 +08:00
ac11a9367c fix(api): correct selisih calculation formula
Bug Fix:
- Change selisih formula from: totalRealisasi - anggaran
- To: anggaran - totalRealisasi

Reason:
- Selisih positif = Sisa anggaran (belum digunakan)
- Selisih negatif = Over budget (melebihi anggaran)

Example:
- Anggaran: Rp 30.000.000
- Realisasi: Rp 5.000.000
- Selisih (OLD): 5jt - 30jt = -25jt  Wrong
- Selisih (NEW): 30jt - 5jt = 25jt  Correct (sisa anggaran)

Files Updated:
- create.ts: Fix initial item creation
- updt.ts: Fix item update
- realisasi/create.ts: Fix after adding realisasi
- realisasi/update.ts: Fix after updating realisasi
- realisasi/delete.ts: Fix after deleting realisasi

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 16:16:38 +08:00
67e5ceb254 feat(ui): add Realisasi Manager component for multiple realisasi CRUD
New Component - RealisasiManager:
- Add modal form for create/edit realisasi
- Input fields: Jumlah (Rp), Tanggal, Keterangan/Uraian
- Display list of existing realisasi with edit/delete actions
- Summary cards showing: Anggaran, Total Realisasi, Sisa Anggaran, Persentase
- Color-coded percentage badges (teal ≥100%, blue ≥80%, yellow ≥60%, red <60%)
- Auto-reload data after create/update/delete operations

Features:
- Multiple realisasi per APBDes item
- Each realisasi has its own description (uraian)
- Date picker for realisasi tanggal
- Format currency in IDR (Rupiah)
- Responsive table layout
- Empty state when no realisasi exists

Integration:
- Integrated with existing state.realisasi CRUD functions
- Auto-calculate totalRealisasi and persentase (handled by backend)
- Display realisasi items from API response
- Works with existing APBDes detail page

UI/UX:
- Clean modal design with form validation
- Summary cards with color-coded backgrounds
- Icon indicators for date and currency
- Confirmation dialog before delete
- Loading states during async operations

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 15:41:43 +08:00
65942ac9d2 refactor(create): remove realisasiAwal, simplify to anggaran-only input
Refactoring:
- Remove realisasiAwal field from ItemForm type
- Remove NumberInput for realisasi awal from UI
- Remove realisasiAwal column from preview table
- Simplify state management (no realisasiAwal mapping)
- API create: Create items with totalRealisasi=0 (no auto-create realisasi)

Rationale:
- Cleaner separation: Anggaran dan Realisasi adalah entitas terpisah
- User create item untuk ANGGARAN dulu
- Setelah item dibuat, user bisa add MULTIPLE REALISASI dengan:
  * Uraian yang jelas untuk setiap realisasi
  * Tanggal yang spesifik
  * Keterangan detail
  * Bukti file attachment
- Follows the original schema design more closely

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 15:30:33 +08:00
e0436cc384 feat(create): add realisasi awal input di create page
Features:
- Add realisasiAwal field to ItemForm type
- Add NumberInput for realisasi awal (optional)
- Update table preview to show realisasi awal
- Update state to send realisasiAwal to API
- Update API create to handle realisasiAwal:
  * Create APBDesItem with totalRealisasi = realisasiAwal
  * Auto-create first RealisasiItem if realisasiAwal > 0
  * Auto-calculate selisih and persentase

UX Improvements:
- User can input initial realization during create
- Optional field with clear label and description
- Auto-calculation of percentages on backend
- Single transaction for item + first realisasi

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 15:13:58 +08:00
63682e47b6 feat(state): update APBDes state management for multiple realisasi
State Changes:
- Update ApbdesItemSchema: Remove realisasi, selisih, persentase fields
- Add RealisasiItemSchema for realisasi CRUD operations
- Update normalizeItem: Remove manual calculations (backend handles it)
- Update edit.load: Map items without realisasi fields
- Add realisasi state: create, update, delete functions

UI Changes:
- Update create/page.tsx: Remove realisasi input field and column
- Update edit/page.tsx: Remove realisasi input field and column
- Update ItemForm type: Remove realisasi property
- Simplify forms to only input anggaran, realisasi added separately

Features:
- Support for multiple realisasi per item
- Realisasi CRUD via dedicated state functions
- Auto-reload findUnique after realisasi operations
- Backend auto-calculates totalRealisasi, selisih, persentase

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 14:55:06 +08:00
f4705690a9 feat(api): implement multiple realisasi for APBDes
Schema Changes:
- Add RealisasiItem model for multiple realizations per APBDesItem
- Replace realisasi field with totalRealisasi (auto-calculated sum)
- Add selisih and persentase as auto-calculated fields
- Cascade delete realisasi when item is deleted

API Changes:
- Update index.ts: Add realisasi CRUD endpoints
  - POST /:itemId/realisasi - Create realisasi
  - PUT /realisasi/:realisasiId - Update realisasi
  - DELETE /realisasi/:realisasiId - Delete realisasi
- Update create.ts: Auto-calculate totalRealisasi=0, selisih, persentase
- Update updt.ts: Reset calculations when items updated
- Update findUnique.ts: Include realisasiItems in response
- Update findMany.ts: Include realisasiItems in response
- Remove realisasi field from ApbdesItemSchema

New Files:
- realisasi/create.ts - Create realisasi with auto-calculation
- realisasi/update.ts - Update realisasi with recalculation
- realisasi/delete.ts - Soft delete with recalculation

Features:
- Auto-calculate totalRealisasi from sum of all realisasiItems
- Auto-calculate selisih = totalRealisasi - anggaran
- Auto-calculate persentase = (totalRealisasi / anggaran) * 100
- Support for bukti file attachment
- Support for keterangan (notes) per realisasi
- Soft delete support for audit trail

UI Updates:
- Update admin detail page to use totalRealisasi instead of realisasi
- Update landing page realisasiTable to use totalRealisasi

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 14:45:21 +08:00
239771a714 fix(apbdes): improve UI components and styling
- Update Apbdes component with better conditional rendering
- Enhance grafikRealisasi with improved percentage display
- Refine color coding and feedback messages
- Optimize layout and spacing for better UX

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 14:15:27 +08:00
03451195c8 feat(apbdes) grafik: add detailed percentage comparison
- Display percentage value prominently next to each category title
- Add formatted currency (Rupiah) for better readability
- Color-coded progress bars based on achievement level:
  * Teal: ≥100% (target tercapai)
  * Blue: ≥80% (baik)
  * Yellow: ≥60% (cukup)
  * Red: <60% (perlu perhatian)
- Add contextual feedback messages based on percentage:
  * ✓ Achievement message for 100%
  *  Positive message for 80-99%
  * ⚠️ Warning messages for <80%
- Add TOTAL KESELURUHAN summary section at the top
- Add emoji icons for better visual distinction (💰 💸 📊)
- Animated progress bars for <100% achievement

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 13:58:52 +08:00
597af7e716 fix(apbdes) landing page: fix APBDes component not displaying on darmasaba page
- Restore Apbdes component with full functionality (fetch data, year selector, tables, charts)
- Fix realisasiTable.tsx: add missing items variable
- Fix grafikRealisasi.tsx: dynamic year title instead of hardcoded 2026
- Add eslint-disable comments for TypeScript any types
- Remove unused imports in paguTable.tsx
- Integrate PaguTable, RealisasiTable, GrafikRealisasi into main Apbdes component
- Component now fetches data from Valtio state and displays 3 tables + charts

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 12:51:53 +08:00
0a8a026b94 fix(apbdes): integrate new APBDes API with admin UI
- Update API schema to support name, deskripsi, and jumlah fields
- Enhance state management with additional form fields
- Add input fields for name, description, and total amount in create/edit pages
- Display description and total amount in detail page
- Fix APBDes component order in landing page
- Update TypeScript types and Prisma schema integration

API Changes:
- POST /api/landingpage/apbdes/create: Added optional fields (name, deskripsi, jumlah)
- PUT /api/landingpage/apbdes/🆔 Added optional fields (name, deskripsi, jumlah)

Admin UI Changes:
- create/page.tsx: Add TextInput for name, deskripsi, and jumlah
- edit/page.tsx: Add TextInput for name, deskripsi, and jumlah; improve reset functionality
- [id]/page.tsx: Display deskripsi and jumlah if available
- page.tsx: Minor formatting fix
- _state/apbdes.ts: Update Zod schema and default form with new fields

Landing Page:
- Move Apbdes component to top of stack for better visibility

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-03 10:56:30 +08:00
a5bd91b580 feat(berita): add multiple images gallery and YouTube video support
- Update schema: add images relation list and linkVideo field
- API: support multiple image upload and YouTube link in create/update
- Admin create page: add gallery upload (max 10) and YouTube embed preview
- Admin edit page: manage existing/new gallery images and YouTube link
- Admin detail page: display gallery grid and YouTube video embed
- Public detail page: show gallery images and YouTube video with responsive layout
- State: add imageIds[] and linkVideo fields with proper type handling
- Music player: fix seek functionality and ESLint warnings

Breaking changes:
- Prisma schema updated - requires migration
- API create/update endpoints now expect imageIds array and linkVideo string

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 16:06:53 +08:00
ae3187804e Notes slider musik belum berfungsi 2026-03-02 14:28:20 +08:00
91e32f3f1c fix(musik): fix seek slider reset ke 0 - root cause: useEffect dependency
ROOT CAUSE:
- filteredMusik di-calculate ulang setiap render (.filter() tanpa memoization)
- currentSong = filteredMusik[currentSongIndex] → object reference baru setiap render
- useEffect dependency [currentSong, currentSongIndex] trigger setiap render
- useEffect reset setCurrentTime(0) → slider kembali ke awal

FIX:
1. useMemo untuk filteredMusik - mencegah re-calculate setiap render
2. useEffect dependency [currentSong?.id, currentSongIndex] - hanya trigger saat lagu benar-benar berubah
3. Hapus semua debug console.log yang tidak diperlukan
4. Simplifikasi seekTo function

File Changed:
- src/app/darmasaba/(pages)/musik/musik-desa/page.tsx
- src/app/darmasaba/(pages)/musik/lib/seek.ts

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 12:03:26 +08:00
4d03908f23 feat(musik): tambahkan extensive debug logging untuk tracking seek issue
- Tambah key stabil pada audio element untuk mencegah remount
- Log di seekTo: before/after currentTime
- Log di onTimeUpdate: currentTime, rounded, isSeeking
- Log di onChangeEnd slider: value, seekTime
- Log di useEffect song change: currentSong, currentSongIndex
- Log di skipBack/skipForward: index perubahan lagu

Purpose: Track urutan eksekusi dan identifikasi race condition atau re-render yang tidak diinginkan

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 11:58:40 +08:00
0563f9664f fix(musik): perbaiki timing dan rounding pada seek slider
- Gunakan durasi dari database sebagai acuan utama (bukan dari audio metadata)
- Ganti Math.floor dengan Math.round untuk smoothing currentTime
- Tambahkan validasi seek time: Math.min(Math.max(0, v), duration)
- Tambahkan debug logging untuk tracking seek behavior
- Hapus override duration di onLoadedMetadata untuk menghindari konflik

Root cause:
- Duration dari database (string 'MM:SS' → seconds) berbeda dengan audio.duration (float)
- Math.floor menyebabkan lompatan kasar dan kehilangan presisi
- onLoadedMetadata override duration dengan audio.duration yang tidak exact

Fix:
- Database duration = source of truth
- Math.round untuk smoothing tanpa kehilangan presisi
- Validasi bounds untuk mencegah seek negatif atau melebihi durasi

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 11:53:36 +08:00
961cc32057 fix(musik): slider seek sekarang berfungsi dengan benar
- Fix slider seek reset ke detik awal saat digeser
- Tambahkan isSeeking state untuk mencegah onTimeUpdate mereset posisi slider
- Implementasi pattern preview/commit untuk seek:
  - onChange: update UI state saja (preview)
  - onChangeEnd: commit ke audio player (commit)
- Update seekTo function untuk support optional setCurrentTime callback
- Terapkan fix ke kedua slider (Sedang Diputar dan bottom player)

Bug: Slider seek langsung kembali ke posisi awal saat digeser karena:
1. onTimeUpdate terus menerus update currentTime state
2. seekTo tidak update React state setelah set audio.currentTime
3. Tidak ada isSeeking flag untuk block onTimeUpdate saat user sedang seek

Fix:
1. Set isSeeking=true saat onChange, false saat onChangeEnd
2. onTimeUpdate check isSeeking sebelum update state
3. seekTo sekarang juga update state via callback optional

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 11:47:05 +08:00
fe7672e09f refactor(musik): integrate music player library functions and fix build errors
- Integrate togglePlayPause, getNextIndex, getPrevIndex, handleRepeatOrNext, seekTo, toggleShuffle, setAudioVolume, toggleMute library functions
- Fix ESLint warnings: remove unused eslint-disable, add missing useEffect dependencies
- Fix ESLint error in useMusicPlayer.ts togglePlayPause function
- Add force-dynamic export to root layout to prevent prerendering errors
- Improve seek slider with preview/commit functionality
- Add isSeeking state to prevent UI flickering during seek

Fixes: Build PageNotFoundError for admin/darmasaba pages

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-02 11:41:14 +08:00
341ff5779f Fix Durasi Musik Di Tampilan User 2026-02-27 11:52:18 +08:00
69f7b4c162 feat: integrate musik desa page with API and improve audio player
- Fetch musik data from /api/desa/musik/find-many endpoint
- Filter only active musik (isActive: true)
- Add search functionality by title, artist, and genre
- Implement real audio playback with HTML5 audio element
- Add play/pause, next/previous, shuffle, repeat controls
- Add progress bar with seek functionality
- Add volume control with mute toggle
- Auto-play next song when current song ends
- Add loading and empty states
- Use cover image and audio file from database
- Fix skip back/forward button handlers

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-26 22:24:25 +08:00
409ad4f1a2 Fix Login KodeOtp WA 2026-02-26 22:10:28 +08:00
55ea3c473a add menu musik 2026-02-26 21:32:33 +08:00
0160fa636d Merge pull request 'Fix Login KodeOtp WA' (#72) from nico/26-feb-26/fix-auth-wa-login into staggingweb
Reviewed-on: #72
2026-02-26 14:14:29 +08:00
a152eaf984 Fix Login KodeOtp WA 2026-02-26 14:12:54 +08:00
3684e83187 Merge pull request 'Fix CORS config for staging environment' (#71) from nico/25-feb-26 into staggingweb
Reviewed-on: #71
2026-02-25 23:15:18 +08:00
223b85a714 Fix CORS config for staging environment
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-25 22:55:36 +08:00
77c54b5c8a Merge pull request 'nico/25-feb-26' (#70) from nico/25-feb-26 into staggingweb
Reviewed-on: #70
2026-02-25 21:34:28 +08:00
f1729151b3 Fix themeTokens light mode status colors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-25 21:24:39 +08:00
8e8c133eea Fix eror build 2026-02-25 21:19:56 +08:00
1e7acac193 Fix eror build 2026-02-25 21:18:26 +08:00
bb80b0ecc1 Merge pull request 'fix/admin/menu-desa/berita' (#69) from fix/admin/menu-desa/berita into staggingweb
Reviewed-on: #69
2026-02-25 16:27:35 +08:00
42dcbcfb22 fix-admin-menu-desa-berita 2026-02-25 16:25:59 +08:00
22de1aa1f3 fix-admin-menu-desa-potensi 2026-02-25 15:41:01 +08:00
b1d28a8322 fix-admin-menu-desa-profile 2026-02-25 15:25:51 +08:00
b86a3a85c3 fix: force default light mode for public pages and admin
- Set defaultColorScheme='light' in root MantineProvider
- Change darkModeStore default from system preference to false (light)
- Add MantineProvider with light theme to darmasaba/layout.tsx
- Remove dark mode dependency from ModuleView component
- Prevent system color scheme from affecting initial page load

This ensures consistent light mode on first visit for both
public pages and admin panel, regardless of OS settings.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-25 10:45:27 +08:00
fd63bb0fd4 feat: implement dark mode support & fix Prisma schema validation
- Add dark mode toggle component in admin header
- Integrate dark mode store across admin layout and components
- Add unified typography and surface components for consistent theming
- Implement smooth transitions for dark/light mode switching
- Fix Prisma schema: remove @default(null) from DateTime? fields
- Update form validation for inovasi, lingkungan, and pendidikan modules
- Add form validation and improve UX across multiple admin pages

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-25 10:41:48 +08:00
f2c9a922a6 fix(profil-module): QC improvements based on QC-PROFIL-MODULE.md
- Fix fetch method inconsistency (convert to ApiFetch)
  - programInovasi: findUnique, delete, update methods
  - mediaSosial: findUnique, delete, update methods
- Add loading state to findUnique operations
- Fix iconUrl validation (make optional instead of required)
- Add DOMPurify for HTML sanitization (XSS protection)
  - program-inovasi page.tsx (list & detail)
- Remove console.log in production (use dev-only logging)
- Install dompurify and @types/dompurify

Security: Prevent XSS attacks by sanitizing HTML content
Consistency: Use ApiFetch for all API operations
UX: Proper loading states for better user feedback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-23 15:11:00 +08:00
92b24440fe fix: Quality Control improvements & bug fixes
- APBDes: Fix edit form original data tracking (imageId, fileId)
- APBDes: Update formula consistency in state
- PPID modules: Various UI improvements and bug fixes
- PPID Profil: Preview and edit page improvements
- PPID Dasar Hukum: Page structure improvements
- PPID Visi Misi: Page structure improvements
- PPID Struktur: Posisi organisasi page improvements
- PPID Daftar Informasi: Edit page improvements
- Auth login: Route improvements
- Update dependencies (package.json, bun.lockb)
- Update seed data
- Update .gitignore

QC Reports added:
- QC-APBDES-MODULE.md
- QC-PROFIL-MODULE.md
- QC-SDGS-DESA.md
- QC-DESA-ANTI-KORUPSI.md
- QC-PRESTASI-DESA-MODULE.md
- QC-PPID-PROFIL-MODULE.md
- QC-STRUKTUR-PPID-MODULE.md
- QC-VISI-MISI-PPID-MODULE.md
- QC-DASAR-HUKUM-PPID-MODULE.md
- QC-PERMOHONAN-INFORMASI-PUBLIK-MODULE.md
- QC-PERMOHONAN-KEBERATAN-INFORMASI-MODULE.md
- QC-DAFTAR-INFORMASI-PUBLIK-MODULE.md
- QC-IKM-MODULE.md

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-23 14:38:28 +08:00
f0558aa0d0 feat: implement dark mode support for admin layout and components
- Add dark mode toggle component in admin header
- Integrate dark mode store across admin layout and child components
- Update header, judulList, and judulListTab components with theme tokens
- Add unified typography components for consistent theming
- Implement smooth transitions for dark/light mode switching
- Add mounted state to prevent hydration mismatches
- Style navbar with dark mode aware colors and hover states
- Update button styles with gradient effects for both themes

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-23 10:48:00 +08:00
8132609ccb feat: add form validation for inovasi, lingkungan, and pendidikan modules
- Added isFormValid() and isHtmlEmpty() helper functions for form validation
- Disabled submit buttons when required fields are empty across multiple admin and public pages
- Applied consistent validation pattern for creating and editing records
- Commented out WhatsApp OTP sending in login route for debugging/testing
- Fixed path in NavbarMainMenu tooltip action
2026-02-20 15:08:41 +08:00
1ddc1d7eac feat: add form validation for ekonomi module admin pages
- Added isFormValid() and isHtmlEmpty() helper functions
- Disabled submit buttons when required fields are empty
- Applied consistent validation pattern across all create/edit pages
- Validated fields: nama, deskripsi, tahun, jumlah, value, icon, statistik, and more
- Edit pages allow existing data, create pages require all fields

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-18 16:13:20 +08:00
aa354992e7 feat: add form validation for keamanan module admin pages
- Added isFormValid() and isHtmlEmpty() helper functions
- Disabled submit buttons when required fields are empty
- Applied consistent validation pattern across all create/edit pages
- Validated fields: judul, deskripsi, lokasi, tanggal, status, kronologi, penanganan, link video, and image uploads
- Edit pages allow existing images, create pages require new uploads

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-18 11:22:30 +08:00
d43b07c2ef feat: add form validation for kesehatan module admin pages
- Added isFormValid() and isHtmlEmpty() helper functions
- Disabled submit buttons when required fields are empty
- Applied consistent validation pattern across all create/edit pages
- Validated fields: name, address, dates, descriptions, and image uploads
- Edit pages allow existing images, create pages require new uploads

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-18 10:51:10 +08:00
9678e6979b feat: implement form validation for empty fields across multiple admin pages
- Added validation to disable submit buttons when required fields are empty
- Implemented consistent validation patterns across various admin pages
- Applied validation to create and edit forms for berita, gallery, layanan, penghargaan, pengumuman, potensi, profil-desa, and ppid sections
- Used helper functions to check for empty HTML content in editor fields
- Ensured submit buttons are disabled until all required fields are filled

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-14 14:17:17 +08:00
b35874b120 feat: add form validation and disable submit buttons when fields are empty
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-11 17:04:55 +08:00
1b59d6bf09 Merge pull request 'Fix Coba lagi image stagging' (#66) from nico/5-feb-26-2 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/66
2026-02-05 14:31:53 +08:00
b69df2454e Fix Coba lagi image stagging 2026-02-05 14:29:44 +08:00
eb1ad54db6 Merge pull request 'Seed create' (#65) from nico/5-feb-26-1 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/65
2026-02-05 14:04:09 +08:00
df198c320a Seed create 2026-02-05 14:03:40 +08:00
21ec3ad1c1 Merge pull request 'nico / 5-feb-26 (3)' (#64) from nico/5-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/64
2026-02-05 12:35:21 +08:00
f550e29a75 Fix ke 3 Env dan seafile 2026-02-05 12:34:31 +08:00
3a115908c4 Merge pull request 'nico / 5-feb-26(2)' (#63) from nico/5-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/63
2026-02-05 12:07:17 +08:00
bb7384f1e5 Fix Seed Profile PPID
Fix Seed Visi Misi Desa Profile Desa
2026-02-05 12:06:20 +08:00
5ff791642c Merge pull request 'nico / 5-feb-26' (#62) from nico/5-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/62
2026-02-05 11:14:42 +08:00
df154806f7 Fix image di seafile sudah tidak pakai token tapi by folder di seafile
Kasih console di page profil ppid & visi misi di Profile Desa
2026-02-05 11:10:30 +08:00
b803c7a90c Merge pull request 'nico / 4-feb-26' (#61) from nico/4-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/61
2026-02-04 17:10:27 +08:00
25000d0b0f PPID > Profile PPID
Desa >  Profile Visi Misi Desa
Keamanan >  Pencegahan Kriminalitas  Grid Kiri  Datanya  Mepet
Keamanan >  Laporan  Publik
Ekonomi  >  Sektor Unggulan Desa Coba tampilin 3  Aja
2026-02-04 16:59:49 +08:00
fb2fe67c23 Merge pull request 'Nico / 4-Feb-2026' (#60) from nico/4-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/60
2026-02-04 11:49:22 +08:00
bbd52fb6f5 Fix Jam Operasional Kantor Desa
Fix Agar Token Seafile ga expired cuma 1 hari
2026-02-04 11:47:56 +08:00
51460558d4 Merge pull request 'Seeder Menu Lingkungan dan Pendidikan' (#59) from nico/3-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/59
2026-02-03 17:12:03 +08:00
358ff14efe Seeder Menu Lingkungan dan Pendidikan
Fix Jam Operasional Kantor Desa Darmasaba
2026-02-03 16:53:15 +08:00
d105ceeb6b Merge pull request 'nico/2-feb-26' (#58) from nico/2-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/58
2026-02-02 17:32:10 +08:00
6c36a15290 Seed Menu Ekonomi
Seed MEnu Inovasi
Sisa 2 Menu
2026-02-02 17:31:27 +08:00
da585dde99 seed kesheatan
seed keamanan
2026-02-02 15:05:53 +08:00
c865aee766 Merge pull request 'Fix Eror Code get_images.ts (1)' (#57) from nico/30-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/57
2026-01-30 17:16:42 +08:00
8afbaabd91 Fix Eror Code get_images.ts (1) 2026-01-30 17:15:39 +08:00
273dfdfd09 Merge pull request 'Fix Seeder Image, Menu Landing Page - Desa' (#56) from nico/30-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/56
2026-01-30 15:57:16 +08:00
f0425cfc47 Fix Seeder Image, Menu Landing Page - Desa 2026-01-30 15:55:05 +08:00
1d1d8e50dc Merge pull request 'Fix Seed Image 27 Jan' (#55) from nico/27-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/55
2026-01-27 10:51:22 +08:00
c2ad515366 Fix Seed Image 27 Jan 2026-01-27 10:50:33 +08:00
092afe67d2 Merge pull request 'Seed Pendidikan' (#54) from nico/23-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/54
2026-01-23 16:52:25 +08:00
d9ce4aac6d Seed Pendidikan 2026-01-23 16:51:35 +08:00
2d9170705d Merge pull request 'Fix seeder statistik kemiskinan' (#53) from nico/21-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/53
2026-01-21 14:27:32 +08:00
3fcfec22fb Fix seeder statistik kemiskinan 2026-01-21 14:25:20 +08:00
fdf9a951a4 Merge pull request 'Fix uploads -1' (#52) from nico/21-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/52
2026-01-21 14:10:42 +08:00
6ca1e032a6 Fix uploads -1 2026-01-21 14:09:27 +08:00
ca74029688 Merge pull request 'nico/21-jan-26' (#51) from nico/21-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/51
2026-01-21 12:10:18 +08:00
78c55a8a71 Seed data menu ekonomi - lingkungan
fix iconmap
2026-01-21 12:07:52 +08:00
1a8fc1a670 Merge pull request 'nico/17-jan-26' (#49) from nico/17-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/49
> Add Layanan Polsek submenu polsek terdekat
> Seeder menu keamanan -> menu ekonomi submenu : demografi pekerjaan, junlah pengangguran, lowongan kerja lokal, pasar desa, program kemiskinan, sektor unggulan, struktur organisasi
2026-01-17 10:36:11 +08:00
17b20e0d40 Add Layanan Polsek submenu polsek terdekat
Seeder menu keamanan -> menu ekonomi submenu : demografi pekerjaan, junlah pengangguran, lowongan kerja lokal, pasar desa, program kemiskinan, sektor unggulan, struktur organisasi
2026-01-17 10:32:48 +08:00
184854d273 Fix Table Admin Preview Desktop
Seeder Menu Kesehatan
2026-01-13 11:45:55 +08:00
903dc74cca Seeder data Landing Page - Desa 2026-01-12 14:03:44 +08:00
503da91ce6 Tambah seeder di bagian landing page 2026-01-06 17:54:21 +08:00
19235f0791 Merge pull request 'Fix All Search Admin' (#48) from nico/5-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/48
2026-01-05 17:12:29 +08:00
daaed8089b Fix All Search Admin 2026-01-05 17:11:30 +08:00
61de7d8d33 Merge pull request 'Fix QC Kak Inno Mobile Done' (#47) from nico/1-jan-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/47
2026-01-02 16:42:08 +08:00
f436aa2ef0 Fix QC Kak Inno Mobile Done
FIx QC Kak Ayu Mobile Admin Done
Fix Tampilan Admin Mobile Device All Menu Done
2026-01-02 16:33:15 +08:00
8fb85ce56c Merge pull request 'Fix QC Kak Inno 23 Des' (#46) from nico/24-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/46
2025-12-24 14:38:12 +08:00
50bc54ceca Fix QC Kak Inno 22 Des
Fix QC Kak Ayu 22 Des
Fix Tampilan Admin Menu Inovasi
2025-12-24 14:36:51 +08:00
1f98b6993d Merge pull request 'nico/23-des-25' (#45) from nico/23-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/45
2025-12-23 17:19:57 +08:00
f0f201c853 Fix QC Kak Inno 22 Des
Fix QC Kak Ayu 22 Des
Fix Tampilan Admin Mobile Device Menu Ekonomi
Fix Search -> useDebounced Menu Ekonomi
2025-12-23 17:18:36 +08:00
29065cb3e2 Fix QC Kak Inno 19 Des
Fix QC Kak Ayu 19 Des
Fix Tampilan Admin Mobile Menu Keamanan
Fix Search Debounce Menu Keamanan
2025-12-22 15:10:25 +08:00
f3a10d63d1 Merge pull request 'nico/19-des-25' (#44) from nico/19-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/44
2025-12-19 15:44:53 +08:00
bf20cd55e8 Fix QC Kak Inno 18 Des
Fix UI Admin Menu Kesehatan
Fix Search : Sudah diberi useDebounced menu Kesehatan
2025-12-19 15:43:55 +08:00
af60bcd6fc Fix QC Kak Inno Tgl 17
Fix QC Kak Ayu Tgl 17
Fix UI Admin Mobile Menu PPID
Search Admin Menu Landing Page & Menu PPID
2025-12-18 17:25:22 +08:00
7a42bec63b Merge pull request 'nico/17-des-25' (#43) from nico/17-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/43
2025-12-17 17:39:29 +08:00
dc8793e3ae Fix QC Kak Inno 16 Des
Fix QC Kak Ayu 16 Des
FIx UI Admin Mobile Menu PPID
Fix Search Admin Menu Landing Page & Menu PPID
2025-12-17 17:37:58 +08:00
44c421129e Merge pull request 'nico/16-des-25' (#42) from nico/16-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/42
2025-12-16 16:38:42 +08:00
c8484357cb Fix QC Kak Ayu 15 Des
Fix QC Kak Inno 15 Des
Fix UI User Font Size, Font Weight, Line Height
Fix UI Admin Font Size, Font Weight, Line Height & UI Mobile
2025-12-16 16:37:17 +08:00
342e9bbc65 Fix QC Kak Ayu Tgl 12
Fix QC Kak Ino Tgl 12
Fix UI Mobile Menu Keamanan
Fix UI Mobile Admin Menu Landing Page
2025-12-16 10:19:15 +08:00
ddff427926 Merge pull request 'nico/12-des-25' (#41) from nico/12-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/41
2025-12-12 17:07:31 +08:00
f6f77d9e35 Fix QC Kak Inno Tgl 11 Des
Fix QC Kak Ayu Tgl 11 Des
Fix font style {font size, color, line height} menu kesehatan
2025-12-12 17:06:33 +08:00
a00481152c Fix Konsisten teks di tampilan mobile dan desktop
Fix QC Kak Inno tgl 10 Des
Fix QC Kak Ayu tgl 10 Des
2025-12-11 17:58:03 +08:00
00c8caade4 Merge pull request 'nico/10-des-25' (#40) from nico/10-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/40
2025-12-10 17:45:16 +08:00
242ea86f77 Fix konsisten font, menu landing page & PPID 2025-12-10 17:44:31 +08:00
99c2c9c6d7 Fix semua tulisan profile jadi profil, mulai dari navbar, dan route 2025-12-10 14:16:15 +08:00
0209f49449 Merge pull request 'nico/9-des-25' (#39) from nico/9-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/39
2025-12-09 17:40:16 +08:00
ac2fc1a705 Fix QC Kak Inno 8 Des
Fix QC Kak Ayu 8 Des
Fix QC Pak Jun 8 Des
2025-12-09 17:27:23 +08:00
9dbe172165 Fix QC Kak Inno Tgl 4 & 5 Desember
Fix QC Kak Ayu Tgl 4 & 5 Desember
Fix QC Pak Jun Tgl 5 Desember
2025-12-09 12:00:27 +08:00
cc318d4d54 Fix QC Kak Inno Tgl 4 & 5 Desember
Fix QC Kak Ayu Tgl 4 & 5 Desember
Fix QC Pak Jun Tgl 5 Desember
2025-12-09 10:28:17 +08:00
dcb8017594 Fix undefined ke detail berita terbaru 2025-12-05 17:42:04 +08:00
344c6ada6d Merge pull request 'nico/5-des-25' (#38) from nico/5-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/38
2025-12-05 14:32:12 +08:00
ec3ad12531 Fix Notifikasi saat ada berita atau pengumuman baru, notifikasi baru muncul. Ga setiap masuk landing page ada notifikasi 2025-12-05 14:30:53 +08:00
dad44c0537 Fix Menu Gallery : Gallery Foto
Fix detail berita
2025-12-05 10:56:03 +08:00
11acd04419 Merge pull request 'Fix Error Build Staging' (#37) from nico/3-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/37
2025-12-04 11:59:43 +08:00
867dce42f0 Fix Error Build Staging 2025-12-04 11:58:47 +08:00
8d49213b68 Merge pull request 'Menambahkan menu dokter dan tenaga medis, admin bisa create, edit, delet dokter' (#36) from nico/3-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/36
2025-12-03 17:57:33 +08:00
7bb17ddf22 Menambahkan menu dokter dan tenaga medis, admin bisa create, edit, delet dokter
Menambahkan menu tarif dan layanan, admin bisa create, edit, delete tarif dan layanan
Dibagian fasilitas kesehatan admin bisa multiselect bagian dokter dan tarif layanan
Di tampilan user juga sudah disesuaikan dengan datanya bisa muncul lebih dari 1 dokter dan 1 tarif layanan
2025-12-03 17:24:03 +08:00
96911e3cf1 Merge pull request 'Fix UI Sosial Media Landing Page in User' (#35) from nico/2-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/35
2025-12-02 16:46:49 +08:00
a4069d3cba Fix UI Sosial Media Landing Page in User 2025-12-02 16:45:55 +08:00
9950c28b9b Merge pull request 'Fix menu admin landing page, submenu sosial media' (#34) from nico/2-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/34
2025-12-02 16:09:19 +08:00
ffe5e6dd9f Fix menu admin landing page, submenu sosial media 2025-12-02 16:06:14 +08:00
fa0f3538d1 Merge pull request 'Tambahan filter data sesuai tahun, di landing page apbdes' (#33) from nico/1-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/33
2025-12-01 17:12:34 +08:00
2778f53aff Merge pull request 'Tambah Term of Service di Registrasi' (#32) from nico/1-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/32
2025-12-01 14:02:11 +08:00
37ac91d4f4 Push Conflict 2025-12-01 13:58:27 +08:00
217f4a9a3b Tambah Term of Service di Registrasi 2025-12-01 13:53:39 +08:00
5d6a7437ed Merge branch 'nico/1-des-25' into staggingweb 2025-12-01 13:52:11 +08:00
752a6cabee Merge pull request 'Meta-data' (#29) from nico/1-des-25-1 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/29
2025-12-01 10:22:10 +08:00
134ddc6154 Meta-data 2025-12-01 10:21:00 +08:00
28979c6b49 Merge pull request 'Test Google Insight' (#28) from nico/28-nov-25-1 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/28
2025-11-28 19:24:18 +08:00
b2066caa13 Test Google Insight 2025-11-28 17:54:18 +08:00
023c77d636 Merge pull request 'Add <meta charSet=utf-8 />' (#27) from nico/28-nov-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/27
2025-11-28 17:05:14 +08:00
9bf3ec72cf Add <meta charSet=utf-8 /> 2025-11-28 17:04:35 +08:00
f359f5b1ce Merge pull request 'nico/28-nov-25' (#26) from nico/28-nov-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/26
2025-11-28 15:39:08 +08:00
1c1e8fb190 fix ganti role, user menu access ikut ke create fix 2025-11-28 15:38:07 +08:00
54f83da3b8 fix ganti role, user menu access ikut ke create 2025-11-28 15:35:21 +08:00
f8985c550f Merge branch 'nico/28-nov-25' of https://wibugit.wibudev.com/wibu/desa-darmasaba into nico/28-nov-25 2025-11-28 15:32:19 +08:00
e3d909e760 fix ganti role, user menu access ikut ke create 2025-11-28 15:31:10 +08:00
16a8df50c1 Merge pull request 'staggingweb' (#25) from staggingweb into nico/28-nov-25
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/25
2025-11-28 15:04:30 +08:00
978 changed files with 58365 additions and 18284 deletions

19
.env Normal file
View File

@@ -0,0 +1,19 @@
DATABASE_URL="postgresql://bip:Production_123@localhost:5433/desa-darmasaba-v0.0.1?schema=public"
# Seafile
SEAFILE_TOKEN=20a19f4a04032215d50ce53292e6abdd38b9f806
SEAFILE_REPO_ID=f0e9ee4a-fd13-49a2-81c0-f253951d063a
SEAFILE_URL=https://cld-dkr-makuro-seafile.wibudev.com
SEAFILE_PUBLIC_SHARE_TOKEN=3a9a9ecb5e244f4da8ae
# Upload
WIBU_UPLOAD_DIR=uploads
WIBU_DOWNLOAD_DIR="./download"
NEXT_PUBLIC_BASE_URL="http://localhost:3000"
EMAIL_USER=nicoarya20@gmail.com
EMAIL_PASS=hymmfpcaqzqkfgbh
BASE_SESSION_KEY=kp9sGx91as0Kj2Ls81nAsl2Kdj13KsxP
BASE_TOKEN_KEY=Qm82JsA92lMnKw0291mxKaaP02KjslaA
# BOT-TELE
BOT_TOKEN=8479423145:AAE9ArrOgTD3DyVxYSVs3IXN40u_sL6c9sw
CHAT_ID=-1003368982298

41
.env.example Normal file
View File

@@ -0,0 +1,41 @@
# Database Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/desa-darmasaba?schema=public"
# Seafile Configuration (File Storage)
SEAFILE_TOKEN=your_seafile_token
SEAFILE_REPO_ID=your_seafile_repo_id
SEAFILE_URL=https://your-seafile-instance.com
SEAFILE_PUBLIC_SHARE_TOKEN=your_seafile_public_share_token
# Upload Configuration
WIBU_UPLOAD_DIR=uploads
WIBU_DOWNLOAD_DIR=./download
# Application Configuration
# IMPORTANT: For staging/production, set this to your actual domain
# Local development: NEXT_PUBLIC_BASE_URL=http://localhost:3000
# Staging: NEXT_PUBLIC_BASE_URL=https://desa-darmasaba-stg.wibudev.com
# Production: NEXT_PUBLIC_BASE_URL=https://your-production-domain.com
# Or use relative URL '/' for automatic protocol/domain detection (recommended)
NEXT_PUBLIC_BASE_URL=/
# Email Configuration (for notifications/subscriptions)
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_email_app_password
# Session Configuration
BASE_SESSION_KEY=your_session_key_generate_secure_random_string
BASE_TOKEN_KEY=your_jwt_secret_key_generate_secure_random_string
# Telegram Bot Configuration (for notifications)
BOT_TOKEN=your_telegram_bot_token
CHAT_ID=your_telegram_chat_id
# Session Password (for iron-session)
SESSION_PASSWORD="your_session_password_min_32_characters_long_secure"
# ElevenLabs API Key (for TTS features - optional)
ELEVENLABS_API_KEY=your_elevenlabs_api_key
# Environment (optional, defaults to development)
# NODE_ENV=development

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env bun
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
// Function to manually load .env from project root if process.env is missing keys
function loadEnv() {
const envPath = join(process.cwd(), ".env");
if (existsSync(envPath)) {
const envContent = readFileSync(envPath, "utf-8");
const lines = envContent.split("\n");
for (const line of lines) {
if (line && !line.startsWith("#")) {
const [key, ...valueParts] = line.split("=");
if (key && valueParts.length > 0) {
const value = valueParts.join("=").trim().replace(/^["']|["']$/g, "");
process.env[key.trim()] = value;
}
}
}
}
}
async function run() {
try {
// Ensure environment variables are loaded
loadEnv();
const inputRaw = readFileSync(0, "utf-8");
if (!inputRaw) return;
let finalText = "";
let sessionId = "web-desa-darmasaba";
try {
// Try parsing as JSON first
const input = JSON.parse(inputRaw);
sessionId = input.session_id || "web-desa-darmasaba";
finalText = typeof input === "string" ? input : (input.response || input.text || JSON.stringify(input));
} catch {
// If not JSON, use raw text
finalText = inputRaw;
}
const BOT_TOKEN = process.env.BOT_TOKEN;
const CHAT_ID = process.env.CHAT_ID;
if (!BOT_TOKEN || !CHAT_ID) {
console.error("Missing BOT_TOKEN or CHAT_ID in environment variables");
return;
}
const message =
`✅ *Gemini Task Selesai*\n\n` +
`🆔 Session: \`${sessionId}\` \n\n` +
`🧠 Output:\n${finalText.substring(0, 3500)}`;
const res = await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chat_id: CHAT_ID,
text: message,
parse_mode: "Markdown",
}),
});
if (!res.ok) {
const errorData = await res.json();
console.error("Telegram API Error:", errorData);
} else {
console.log("Notification sent successfully!");
}
process.stdout.write(JSON.stringify({ status: "continue" }));
} catch (err) {
console.error("Hook Error:", err);
process.stdout.write(JSON.stringify({ status: "continue" }));
}
}
run();

17
.gemini/settings.json Normal file
View File

@@ -0,0 +1,17 @@
{
"hooks": {
"AfterAgent": [
{
"matcher": "*",
"hooks": [
{
"name": "telegram-notify",
"type": "command",
"command": "bun $GEMINI_PROJECT_DIR/.gemini/hooks/telegram-notify.ts",
"timeout": 10000
}
]
}
]
}
}

12
.gitignore vendored
View File

@@ -29,7 +29,15 @@ yarn-error.log*
.pnpm-debug.log*
# env
.env*
# env local files (keep .env.example)
.env.local
.env*.local
.env.production
.env.development
!.env.example
# QC
QC
# vercel
.vercel
@@ -49,7 +57,5 @@ next-env.d.ts
.github/
.env.*
*.tar.gz

3
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"recommendations": []
}

167
AGENTS.md Normal file
View File

@@ -0,0 +1,167 @@
# AGENTS.md
This file contains essential information for agentic coding agents working in the desa-darmasaba repository.
## Project Overview
Desa Darmasaba is a Next.js 15 application for village management services in Badung, Bali. It uses:
- **Framework**: Next.js 15 with App Router
- **Language**: TypeScript with strict mode
- **Styling**: Mantine UI components with custom CSS
- **Backend**: Elysia.js API server integrated with Next.js
- **Database**: PostgreSQL with Prisma ORM
- **State Management**: Jotai for global state
- **Authentication**: JWT with iron-session
## Build Commands
```bash
# Development
npm run dev
# Production build
npm run build
# Start production server
npm start
# Database seeding
bun run prisma/seed.ts
# Linting (ESLint)
npx eslint .
# Type checking
npx tsc --noEmit
# Prisma operations
npx prisma generate
npx prisma db push
npx prisma studio
```
## Running Tests
Currently no test framework is configured. When adding tests:
- Set up test scripts in package.json
- Consider Jest or Vitest for unit testing
- Use Playwright for E2E testing
- Update this section with specific test commands
## Code Style Guidelines
### Imports
- Use absolute imports with `@/` alias (configured in tsconfig.json)
- Group imports: external libraries first, then internal modules
- Keep import statements organized and remove unused imports
```typescript
// External libraries
import { useState } from 'react'
import { Button, Stack } from '@mantine/core'
// Internal modules
import ApiFetch from '@/lib/api-fetch'
import { MyComponent } from '@/components/my-component'
```
### TypeScript Configuration
- Strict mode enabled (`"strict": true`)
- Target: ES2017
- Module resolution: bundler
- Path alias: `@/*` maps to `./src/*`
### Naming Conventions
- **Components**: PascalCase (e.g., `UploadImage.tsx`)
- **Files**: kebab-case for utilities (e.g., `api-fetch.ts`)
- **Variables/Functions**: camelCase
- **Constants**: UPPER_SNAKE_CASE
- **Database Models**: PascalCase (Prisma convention)
### Error Handling
- Use try-catch blocks for async operations
- Implement proper error boundaries in React components
- Log errors appropriately without exposing sensitive data
- Use Zod for runtime validation and type safety
### API Structure
- Backend uses Elysia.js with TypeScript
- API routes are in `src/app/api/[[...slugs]]/` directory
- Use treaty client for type-safe API calls
- Follow RESTful conventions for endpoints
- Include proper HTTP status codes and error responses
### Database Operations
- Use Prisma client from `@/lib/prisma.ts`
- Database connection includes graceful shutdown handling
- Use transactions for complex operations
- Implement proper error handling for database queries
### Component Guidelines
- Use functional components with hooks
- Implement proper prop types with TypeScript interfaces
- Use Mantine components for UI consistency
- Follow atomic design principles when possible
- Add loading states and error states for async operations
### State Management
- Use Jotai atoms for global state
- Keep local state in components when possible
- Use React Query (SWR) for server state caching
- Implement optimistic updates for better UX
### Styling
- Primary: Mantine UI components
- Use Mantine theme system for customization
- Custom CSS should be minimal and scoped
- Follow responsive design principles
- Use semantic HTML5 elements
### Environment Variables
- Use `.env.local` for development
- Prefix public variables with `NEXT_PUBLIC_`
- Never commit environment files to version control
- Use proper typing for environment variables
### File Organization
```
src/
├── app/ # Next.js app router pages
├── components/ # Reusable React components
├── lib/ # Utility functions and configurations
├── state/ # Jotai atoms and state management
├── types/ # TypeScript type definitions
└── con/ # Constants and static data
```
### Security Practices
- Validate all user inputs with Zod schemas
- Use JWT tokens for authentication
- Implement proper CORS configuration
- Never expose database credentials or API keys
- Use HTTPS in production
- Implement rate limiting for sensitive endpoints
### Performance Considerations
- Use Next.js Image optimization
- Implement proper caching strategies
- Use React.memo for expensive components
- Optimize bundle size with dynamic imports
- Use Prisma query optimization
## Development Workflow
1. Always run type checking before committing: `npx tsc --noEmit`
2. Run linting to catch style issues: `npx eslint .`
3. Test database changes with `npx prisma db push`
4. Use the integrated Swagger docs at `/api/docs` for API testing
5. Check environment variables are properly configured
6. Verify responsive design on different screen sizes
## Important Notes
- The application uses a custom Elysia.js server integrated with Next.js API routes
- Image uploads are handled through `/api/upl-img-single` endpoint
- Database seeding is done with Bun runtime
- The app supports Indonesian locale (id_ID) for SEO and content
- CORS is configured to allow cross-origin requests during development

73
AUDIT_REPORT.md Normal file
View File

@@ -0,0 +1,73 @@
# Engineering Audit Report: Desa Darmasaba
**Status:** Production Readiness Review (Critical)
**Auditor:** Staff Technical Architect
---
## 📊 Executive Summary & Scores
| Category | Score | Status |
| :--- | :---: | :--- |
| **Project Architecture** | 3/10 | 🔴 Critical Failure |
| **Code Quality** | 4/10 | 🟠 Poor |
| **Performance** | 5/10 | 🟡 Mediocre |
| **Security** | 5/10 | 🟠 Risk Detected |
| **Production Readiness** | 2/10 | 🔴 Not Ready |
---
## 🏗️ 1. Project Architecture
The project suffers from a **"Frankenstein Architecture"**. It attempts to run a full Elysia.js instance inside a Next.js Catch-All route.
- **Fractured Backend:** Logic is split between standard Next.js routes (`/api/auth`) and embedded Elysia modules.
- **Stateful Dependency:** Reliance on local filesystem (`WIBU_UPLOAD_DIR`) makes the application impossible to deploy on modern serverless platforms like Vercel.
- **Polluted Namespace:** Routing tree contains "test/coba" folders (`src/app/coba`, `src/app/percobaan`) that would be accessible in production.
## ⚛️ 2. Frontend Engineering (React / Next.js)
- **State Management Chaos:** Simultaneous use of `Valtio`, `Jotai`, `React Context`, and `localStorage`.
- **Tight Coupling:** Public pages (`/darmasaba`) import state directly from Admin internal states (`/admin/(dashboard)/_state`).
- **Heavy Client-Side Logic:** Logic that belongs in Server Actions or Hooks is embedded in presentational components (e.g., `Footer.tsx`).
## 📡 3. Backend / API Design
- **Framework Overhead:** Running Elysia inside Next.js adds unnecessary cold-boot overhead and complexity.
- **Weak Validation:** Widespread use of `as Type` casting in API handlers instead of runtime validation (Zod/Schema).
- **Service Integration:** OTP codes are sent via external `GET` requests with sensitive data in the query string—a major logging risk.
## 🗄️ 4. Database & Data Modeling (Prisma)
- **Schema Over-Normalization:** ~2000 lines of schema. Every minor content type (e.g., `LambangDesa`) is a separate table instead of a unified CMS model.
- **Polymorphic Monolith:** `FileStorage` is a "god table" with optional relations to ~40 other tables, creating a massive bottleneck and data integrity risk.
- **Connection Mismanagement:** Manual `prisma.$disconnect()` in API routes kills connection pooling performance.
## 🚀 5. Performance Engineering
- **Bypassing Optimization:** Custom `/api/utils/img` endpoint bypasses `next/image` optimization, serving uncompressed assets.
- **Aggressive Polling:** Client-side 30s polling for notifications is battery-draining and inefficient compared to SSE or SWR.
## 🔒 6. Security Audit
- **Insecure OTP Delivery:** Credentials passed as URL parameters to the WhatsApp service.
- **File Upload Risks:** Potential for Arbitrary File Upload due to direct local filesystem writes without rigorous sanitization.
## 🧹 7. Code Quality
- **Inconsistency:** Mixed English/Indonesian naming (e.g., `nomor` vs `createdAt`).
- **Artifacts:** Root directory is littered with scratch files: `xcoba.ts`, `xx.ts`, `test.txt`.
---
## 🚩 Top 10 Critical Problems
1. **Architectural Fracture:** Embedding Elysia inside Next.js creates a "split-brain" system.
2. **Serverless Incompatibility:** Dependency on local disk storage for uploads.
3. **Database Bloat:** Over-complicated schema with a fragile `FileStorage` monolith.
4. **State Fragmentation:** Mixed usage of Jotai and Valtio without a clear standard.
5. **Credential Leakage:** OTP codes sent via GET query parameters.
6. **Poor Cleanup:** Trial/Test folders and files committed to the production source.
7. **Asset Performance:** Bypassing Next.js image optimization.
8. **Coupling:** High dependency between public UI and internal Admin state.
9. **Type Safety:** Manual casting in APIs instead of runtime validation.
10. **Connection Pooling:** Inefficient Prisma connection management.
---
## 🛠️ Tech Lead Refactoring Priorities
1. **Unify the API:** Decommission the Elysia wrapper. Port all logic to standard Next.js Route Handlers with Zod validation.
2. **Stateless Storage:** Implement an S3-compatible adapter for all file uploads. Remove `fs` usage.
3. **Schema Consolidation:** Refactor the schema to use generic content models where possible.
4. **Standardize State:** Choose one global state manager and migrate all components.
5. **Project Sanitization:** Delete all `coba`, `percobaan`, and scratch files (`xcoba.ts`, etc.).

60
Dockerfile Normal file
View File

@@ -0,0 +1,60 @@
# Stage 1: Build
FROM oven/bun:1.3 AS build
# Install build dependencies for native modules
RUN apt-get update && apt-get install -y \
python3 \
make \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Copy package files
COPY package.json bun.lock* ./
# Install dependencies
RUN bun install --frozen-lockfile
# Copy the rest of the application code
COPY . .
# Use .env.example as default env for build
RUN cp .env.example .env
# Generate Prisma client
RUN bun x prisma generate
# Build the application frontend
ENV NODE_ENV=production
RUN bun run build
# Stage 2: Runtime
FROM oven/bun:1.3-slim AS runtime
# Set environment variables
ENV NODE_ENV=production
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Copy necessary files from build stage
COPY --from=build /app/package.json ./
COPY --from=build /app/tsconfig.json ./
COPY --from=build /app/.next ./.next
COPY --from=build /app/public ./public
COPY --from=build /app/src ./src
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/prisma ./prisma
# Expose the port
EXPOSE 3000
# Start the application
CMD ["bun", "start"]

62
GEMINI.md Normal file
View File

@@ -0,0 +1,62 @@
# Project: Desa Darmasaba
## Project Overview
The `desa-darmasaba` project is a Next.js (version 15+) application developed with TypeScript. It serves as an official platform for Desa Darmasaba (a village in Badung, Bali), offering various public services, news, and detailed village profiles.
**Key Technologies:**
* **Frontend Framework:** Next.js (v15+) with React (v19+)
* **Language:** TypeScript
* **UI Library:** Mantine UI
* **Database ORM:** Prisma (v6+)
* **Database:** PostgreSQL (as configured in `prisma/schema.prisma`)
* **API Framework:** Elysia (used for API routes, as seen in dependencies)
* **State Management:** Potentially Jotai and Valtio (listed in dependencies)
* **Image Processing:** Sharp
* **Package Manager:** Likely Bun, given `bun.lockb` and the `prisma:seed` script.
The application architecture follows the Next.js App Router structure, with comprehensive data models defined in `prisma/schema.prisma` covering various domains like public information, health, security, economy, innovation, environment, and education. It also includes configurations for image handling and caching.
## Building and Running
This project uses `bun` as the package manager. Ensure Bun is installed to run these commands.
* **Install Dependencies:**
```bash
bun install
```
* **Development Server:**
Runs the Next.js development server.
```bash
bun run dev
```
* **Build for Production:**
Builds the Next.js application for production deployment.
```bash
bun run build
```
* **Start Production Server:**
Starts the Next.js application in production mode.
```bash
bun run start
```
* **Database Seeding:**
Executes the Prisma seeding script to populate the database.
```bash
bun run prisma:seed
```
## Development Conventions
* **Coding Language:** TypeScript is strictly enforced.
* **Frontend Framework:** Next.js App Router for page and component structuring.
* **UI/UX:** Adherence to Mantine UI component library for consistent styling and user experience.
* **Database Interaction:** Prisma ORM is used for all database operations, with a PostgreSQL database.
* **Linting:** ESLint is configured with `next/core-web-vitals` and `next/typescript` to maintain code quality and adherence to Next.js and TypeScript best practices.
* **Styling:** PostCSS is used, with `postcss-preset-mantine` and `postcss-simple-vars` defining Mantine-specific breakpoints and other CSS variables.
* **Imports:** Absolute imports are configured using `@/*` which resolves to the `src/` directory.

173
MUSIK_CREATE_ANALYSIS.md Normal file
View File

@@ -0,0 +1,173 @@
# Musik Desa - Create Feature Analysis
## Error Summary
**Error**: `ERR_BLOCKED_BY_CLIENT` saat create musik di staging environment
## Root Cause Analysis
### 1. **CORS Configuration Issue** (Primary)
File: `src/app/api/[[...slugs]]/route.ts`
The CORS configuration has specific origins listed:
```typescript
const corsConfig = {
origin: [
"http://localhost:3000",
"http://localhost:3001",
"https://cld-dkr-desa-darmasaba-stg.wibudev.com",
"https://cld-dkr-staging-desa-darmasaba.wibudev.com",
"*",
],
// ...
}
```
**Problem**: The wildcard `*` is at the end, but some browsers don't respect it when `credentials: true` is set.
### 2. **API Fetch Base URL** (Secondary)
File: `src/lib/api-fetch.ts`
```typescript
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'
```
**Problem**:
- In staging, this might still default to `http://localhost:3000`
- Mixed content (HTTPS frontend → HTTP API) gets blocked by browsers
- The `NEXT_PUBLIC_BASE_URL` environment variable might not be set in staging
### 3. **File Storage Upload Path** (Tertiary)
File: `src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts`
```typescript
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
```
**Problem**: If `WIBU_UPLOAD_DIR` is not set or points to a non-writable location, uploads will fail silently.
## Solution
### Fix 1: Update CORS Configuration
**File**: `src/app/api/[[...slugs]]/route.ts`
```typescript
// Move wildcard to first position and ensure it works with credentials
const corsConfig = {
origin: [
"*", // Allow all origins (for staging flexibility)
"http://localhost:3000",
"http://localhost:3001",
"https://cld-dkr-desa-darmasaba-stg.wibudev.com",
"https://cld-dkr-staging-desa-darmasaba.wibudev.com",
"https://desa-darmasaba-stg.wibudev.com"
],
methods: ["GET", "POST", "PATCH", "DELETE", "PUT", "OPTIONS"] as HTTPMethod[],
allowedHeaders: ["Content-Type", "Authorization", "Accept"],
exposedHeaders: ["Content-Range", "X-Content-Range"],
maxAge: 86400, // 24 hours
credentials: true,
};
```
### Fix 2: Add Environment Variable Validation
**File**: `.env.example` (update)
```bash
# Application Configuration
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# For staging/production, set this to your actual domain
# NEXT_PUBLIC_BASE_URL=https://cld-dkr-desa-darmasaba-stg.wibudev.com
```
### Fix 3: Update API Fetch to Handle Relative URLs
**File**: `src/lib/api-fetch.ts`
```typescript
import { AppServer } from '@/app/api/[[...slugs]]/route'
import { treaty } from '@elysiajs/eden'
// Use relative URL for better deployment flexibility
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '/'
const ApiFetch = treaty<AppServer>(BASE_URL)
export default ApiFetch
```
### Fix 4: Add Error Handling in Create Page
**File**: `src/app/admin/(dashboard)/musik/create/page.tsx`
Add better error logging to diagnose issues:
```typescript
const handleSubmit = async () => {
// ... validation ...
try {
setIsSubmitting(true);
// Upload cover image
const coverRes = await ApiFetch.api.fileStorage.create.post({
file: coverFile,
name: coverFile.name,
});
if (!coverRes.data?.data?.id) {
console.error('Cover upload failed:', coverRes);
return toast.error('Gagal mengunggah cover, silakan coba lagi');
}
// ... rest of the code ...
} catch (error) {
console.error('Error creating musik:', {
error,
message: error instanceof Error ? error.message : 'Unknown error',
stack: error instanceof Error ? error.stack : undefined,
});
toast.error('Terjadi kesalahan saat membuat musik');
} finally {
setIsSubmitting(false);
}
};
```
## Testing Checklist
### Local Development
- [ ] Test create musik with cover image and audio file
- [ ] Verify CORS headers in browser DevTools Network tab
- [ ] Check that file uploads are saved to correct directory
### Staging Environment
- [ ] Set `NEXT_PUBLIC_BASE_URL` to staging domain
- [ ] Verify HTTPS is used for all API calls
- [ ] Check browser console for mixed content warnings
- [ ] Verify `WIBU_UPLOAD_DIR` is set and writable
- [ ] Test create musik end-to-end
## Additional Notes
### ERR_BLOCKED_BY_CLIENT Common Causes:
1. **CORS policy blocking** - Most likely cause
2. **Ad blockers** - Can block certain API endpoints
3. **Mixed content** - HTTPS page making HTTP requests
4. **Content Security Policy (CSP)** - Restrictive CSP headers
5. **Browser extensions** - Privacy/security extensions blocking requests
### Debugging Steps:
1. Open browser DevTools → Network tab
2. Try to create musik
3. Look for failed requests (red status)
4. Check the "Headers" tab for:
- Request URL (should be correct domain)
- Response headers (should have `Access-Control-Allow-Origin`)
- Status code (4xx/5xx indicates server-side issue)
5. Check browser console for CORS errors
## Recommended Next Steps
1. **Immediate**: Update CORS configuration to allow staging domain
2. **Short-term**: Add proper environment variable validation
3. **Long-term**: Implement proper error boundaries and logging

232
QWEN.md Normal file
View File

@@ -0,0 +1,232 @@
# Desa Darmasaba - Village Management System
## Project Overview
Desa Darmasaba is a comprehensive Next.js 15 application designed for village management services in Darmasaba, Badung, Bali. The application serves as a digital platform for government services, public information, and community engagement. It features multiple sections including PPID (Public Information Disclosure), health services, security, education, environment, economy, innovation, and more.
### Key Technologies
- **Framework**: Next.js 15 with App Router
- **Language**: TypeScript with strict mode
- **Styling**: Mantine UI components with custom CSS
- **Backend**: Elysia.js API server integrated with Next.js
- **Database**: PostgreSQL with Prisma ORM
- **State Management**: Valtio for global state
- **Authentication**: JWT with iron-session
### Architecture
The application follows a modular architecture with:
- A main frontend built with Next.js and Mantine UI
- An integrated Elysia.js API server for backend operations
- Prisma ORM for database interactions
- File storage integration with Seafile
- Multiple domain-specific modules (PPID, health, security, education, etc.)
## Building and Running
### Prerequisites
- Node.js (with Bun runtime)
- PostgreSQL database
- Seafile server for file storage
### Setup Instructions
1. Install dependencies:
```bash
bun install
```
2. Set up environment variables in `.env.local`:
```
DATABASE_URL=your_postgresql_connection_string
SEAFILE_TOKEN=your_seafile_token
SEAFILE_REPO_ID=your_seafile_repo_id
SEAFILE_BASE_URL=your_seafile_base_url
SEAFILE_PUBLIC_SHARE_TOKEN=your_seafile_public_share_token
SEAFILE_URL=your_seafile_api_url
WIBU_UPLOAD_DIR=your_upload_directory
```
3. Generate Prisma client:
```bash
bunx prisma generate
```
4. Push database schema:
```bash
bunx prisma db push
```
5. Seed the database:
```bash
bun run prisma/seed.ts
```
6. Run the development server:
```bash
bun run dev
```
### Available Scripts
- `bun run dev` - Start development server
- `bun run build` - Build for production
- `bun run start` - Start production server
- `bun run prisma/seed.ts` - Run database seeding
- `bunx prisma generate` - Generate Prisma client
- `bunx prisma db push` - Push schema changes to database
- `bunx prisma studio` - Open Prisma Studio GUI
## Development Conventions
### Code Structure
```
src/
├── app/ # Next.js app router pages
│ ├── admin/ # Admin dashboard pages
│ ├── api/ # API routes with Elysia.js
│ ├── darmasaba/ # Public-facing village pages
│ └── ...
├── con/ # Constants and configuration
├── hooks/ # React hooks
├── lib/ # Utility functions and configurations
├── middlewares/ # Next.js middleware
├── state/ # Global state management
├── store/ # Additional state management
├── types/ # TypeScript type definitions
└── utils/ # Utility functions
```
### Import Conventions
- Use absolute imports with `@/` alias (configured in tsconfig.json)
- Group imports: external libraries first, then internal modules
- Keep import statements organized and remove unused imports
```typescript
// External libraries
import { useState } from 'react'
import { Button, Stack } from '@mantine/core'
// Internal modules
import ApiFetch from '@/lib/api-fetch'
import { MyComponent } from '@/components/my-component'
```
### TypeScript Configuration
- Strict mode enabled (`"strict": true`)
- Target: ES2017
- Module resolution: bundler
- Path alias: `@/*` maps to `./src/*`
### Naming Conventions
- **Components**: PascalCase (e.g., `UploadImage.tsx`)
- **Files**: kebab-case for utilities (e.g., `api-fetch.ts`)
- **Variables/Functions**: camelCase
- **Constants**: UPPER_SNAKE_CASE
- **Database Models**: PascalCase (Prisma convention)
### Error Handling
- Use try-catch blocks for async operations
- Implement proper error boundaries in React components
- Log errors appropriately without exposing sensitive data
- Use Zod for runtime validation and type safety
### API Structure
- Backend uses Elysia.js with TypeScript
- API routes are in `src/app/api/[[...slugs]]/` directory
- Use treaty client for type-safe API calls
- Follow RESTful conventions for endpoints
- Include proper HTTP status codes and error responses
### Database Operations
- Use Prisma client from `@/lib/prisma.ts`
- Database connection includes graceful shutdown handling
- Use transactions for complex operations
- Implement proper error handling for database queries
### Component Guidelines
- Use functional components with hooks
- Implement proper prop types with TypeScript interfaces
- Use Mantine components for UI consistency
- Follow atomic design principles when possible
- Add loading states and error states for async operations
### State Management
- Use Valtio proxies for global state
- Keep local state in components when possible
- Use SWR for server state caching
- Implement optimistic updates for better UX
### Styling
- Primary: Mantine UI components
- Use Mantine theme system for customization
- Custom CSS should be minimal and scoped
- Follow responsive design principles
- Use semantic HTML5 elements
### Security Practices
- Validate all user inputs with Zod schemas
- Use JWT tokens for authentication
- Implement proper CORS configuration
- Never expose database credentials or API keys
- Use HTTPS in production
- Implement rate limiting for sensitive endpoints
### Performance Considerations
- Use Next.js Image optimization
- Implement proper caching strategies
- Use React.memo for expensive components
- Optimize bundle size with dynamic imports
- Use Prisma query optimization
## Domain Modules
The application is organized into several domain modules:
1. **PPID (Public Information Disclosure)**: Profile, structure, information requests, legal basis
2. **Health**: Health facilities, programs, emergency response, disease information
3. **Security**: Community security, emergency contacts, crime prevention
4. **Education**: Schools, scholarships, educational programs
5. **Economy**: Local markets, BUMDes, employment data
6. **Environment**: Environmental data, conservation, waste management
7. **Innovation**: Digital services, innovation programs
8. **Culture**: Village traditions, music, cultural preservation
Each module has its own section in both the admin panel and public-facing areas.
## File Storage Integration
The application integrates with Seafile for file storage, with specific handling for:
- Images and documents
- Public sharing capabilities
- CDN URL generation
- Batch processing of assets
## Testing
Currently no formal test framework is configured. When adding tests:
- Consider Jest or Vitest for unit testing
- Use Playwright for E2E testing
- Update this section with specific test commands
## Deployment
The application includes deployment scripts in the `NOTE.md` file that outline:
- Automated deployment with GitHub API integration
- Environment-specific configurations
- PM2 process management
- Release management with versioning
## Troubleshooting
Common issues and solutions:
- **API endpoints returning 404**: Check that environment variables are properly configured
- **Database connection errors**: Verify DATABASE_URL in environment variables
- **File upload issues**: Ensure Seafile integration is properly configured
- **Build failures**: Run `bunx prisma generate` before building
## Development Workflow
1. Always run type checking before committing: `bunx tsc --noEmit`
2. Run linting to catch style issues: `bun run eslint .`
3. Test database changes with `bunx prisma db push`
4. Use the integrated Swagger docs at `/api/docs` for API testing
5. Check environment variables are properly configured
6. Verify responsive design on different screen sizes

View File

@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import ApiFetch from '@/lib/api-fetch';
describe('FileStorage API', () => {
it('should fetch a list of files from /api/fileStorage/findMany', async () => {
const response = await ApiFetch.api.fileStorage.findMany.get();
expect(response.status).toBe(200);
const responseBody = response.data as any;
expect(responseBody.data).toBeInstanceOf(Array);
expect(responseBody.data.length).toBe(2);
expect(responseBody.data[0].name).toBe('file1.jpg');
});
it('should create a file using /api/fileStorage/create', async () => {
const mockFile = new File(['hello'], 'hello.png', { type: 'image/png' });
const response = await ApiFetch.api.fileStorage.create.post({
file: mockFile,
name: 'hello.png',
});
expect(response.status).toBe(200);
const responseBody = response.data as any;
expect(responseBody.data.realName).toBe('hello.png');
expect(responseBody.data.id).toBe('3');
});
});

View File

@@ -0,0 +1,11 @@
import { test, expect } from '@playwright/test';
test('homepage has correct title and content', async ({ page }) => {
await page.goto('/');
// Wait for the redirect to /darmasaba
await page.waitForURL('/darmasaba');
// Check for the main heading
await expect(page.getByText('DARMASABA', { exact: true })).toBeVisible();
});

View File

@@ -0,0 +1,43 @@
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('http://localhost:3000/api/fileStorage/findMany', () => {
return HttpResponse.json({
data: [
{ id: '1', name: 'file1.jpg', url: '/uploads/file1.jpg' },
{ id: '2', name: 'file2.png', url: '/uploads/file2.png' },
],
meta: {
page: 1,
limit: 10,
total: 2,
totalPages: 1,
},
});
}),
http.post('http://localhost:3000/api/fileStorage/create', async ({ request }) => {
const data = await request.formData();
const file = data.get('file') as File;
const name = data.get('name') as string;
if (!file) {
return new HttpResponse(null, { status: 400 });
}
return HttpResponse.json({
data: {
id: '3',
name: 'generated-nanoid',
path: `/uploads/generated-nanoid`,
link: `/uploads/generated-nanoid`,
realName: name,
mimeType: file.type,
category: "uncategorized",
isActive: true,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
}
});
}),
];

View File

@@ -0,0 +1,4 @@
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);

7
__tests__/setup.ts Normal file
View File

@@ -0,0 +1,7 @@
import '@testing-library/jest-dom';
import { server } from './mocks/server';
import { beforeAll, afterEach, afterAll } from 'vitest';
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

BIN
bun.lockb

Binary file not shown.

169
darkMode.md Normal file
View File

@@ -0,0 +1,169 @@
# 🌙 Dark Mode Design Specification
## Admin Darmasaba Dashboard & CMS
Dokumen ini mendefinisikan standar **Dark Mode UI** agar:
- nyaman di mata
- konsisten
- tidak flat
- tetap profesional untuk aplikasi pemerintahan
---
## 🎨 Color Palette (Dark Mode)
### Background Layers
| Layer | Token | Warna | Fungsi |
|------|------|------|------|
| Base | `--bg-base` | `#0B1220` | Background utama aplikasi |
| App | `--bg-app` | `#0F172A` | Area kerja utama |
| Card | `--bg-card` | `#162235` | Card / container |
| Surface | `--bg-surface` | `#1E2A3D` | Table header, tab, input |
---
### Border & Divider
| Token | Warna | Catatan |
|-----|------|--------|
| `--border-default` | `#2A3A52` | Border utama |
| `--border-soft` | `#22314A` | Divider halus |
> ❗ Hindari border terlalu tipis (`opacity < 20%`)
---
### Text Colors
| Jenis | Token | Warna |
|-----|------|------|
| Primary | `--text-primary` | `#E5E7EB` |
| Secondary | `--text-secondary` | `#9CA3AF` |
| Muted | `--text-muted` | `#6B7280` |
| Inverse | `--text-inverse` | `#020617` |
---
### Accent & Action
| Fungsi | Warna |
|------|------|
| Primary Action | `#3B82F6` |
| Hover | `#2563EB` |
| Active | `#1D4ED8` |
| Link | `#60A5FA` |
---
### Status Colors
| Status | Warna |
|------|------|
| Success | `#22C55E` |
| Warning | `#FACC15` |
| Error | `#EF4444` |
| Info | `#38BDF8` |
---
## 🧱 Layout Rules
### Sidebar
- Background: `--bg-app`
- Active menu:
- Background: `rgba(59,130,246,0.15)`
- Text: Primary
- Indicator: kiri (23px accent bar)
- Hover:
- Background: `rgba(255,255,255,0.04)`
---
### Header / Topbar
- Background: `linear-gradient(#0F172A → #0B1220)`
- Border bawah wajib (`--border-soft`)
- Icon:
- Default: muted
- Hover: primary
---
## 📦 Card & Section
### Card
- Background: `--bg-card`
- Border: `--border-default`
- Radius: 1216px
- Jangan pakai shadow hitam
### Section Header
- Font weight lebih besar
- Text: primary
- Spacing jelas dari konten
---
## 📊 Table (Dark Mode Friendly)
### Table Header
- Background: `--bg-surface`
- Text: secondary
- Font weight: medium
### Table Row
- Default: transparent
- Hover:
- Background: `rgba(255,255,255,0.03)`
- Divider antar row wajib terlihat
### Link di Table
- Warna link **lebih terang dari text**
- Hover underline
---
## 🔘 Button Rules
### Primary Button
- Background: Primary Action
- Text: Inverse
- Hover: darker shade
### Secondary Button
- Background: transparent
- Border: `--border-default`
- Text: primary
### Icon Button
- Default: muted
- Hover: primary + bg soft
---
## 🧭 Tab Navigation
- Inactive:
- Text: muted
- Active:
- Background: `rgba(59,130,246,0.15)`
- Text: primary
- Icon ikut berubah
---
## 🌗 Dark vs Light Mode Rule
- Layout, spacing, typography **HARUS SAMA**
- Yang boleh beda:
- warna
- border intensity
- background layer
> ❌ Jangan ganti struktur UI antara dark & light
---
## ✅ Dark Mode Checklist
- [ ] Kontras teks terbaca
- [ ] Active state jelas
- [ ] Hover terasa hidup
- [ ] Tidak flat
- [ ] Tidak silau
---
Dokumen ini adalah **single source of truth** untuk Dark Mode.

99
gambar.ttx Normal file
View File

@@ -0,0 +1,99 @@
type DirItem = {
type: "file" | "dir";
name: string;
path: string;
size?: number;
};
// type FileDownloadResponse = {
// url: string;
// };
// const TOKEN = "20a19f4a04032215d50ce53292e6abdd38b9f806";
// const REPO_ID = "8814bfe1-30d5-4e77-ab36-3122fa59a022";
// const DIR_TARGET = "image";
// const BASE_URL = "https://cld-dkr-makuro-seafile.wibudev.com/api2";
const TOKEN = process.env.SEAFILE_TOKEN!;
const REPO_ID = process.env.SEAFILE_REPO_ID!;
// ⛔ PENTING: RELATIVE PATH (tanpa slash depan)
const DIR_TARGET = "asset-web";
const BASE_URL = "https://cld-dkr-makuro-seafile.wibudev.com/api2";
const headers = {
Authorization: `Token ${TOKEN}`,
};
/**
* Ambil list file di directory
*/
async function getDirItems(): Promise<DirItem[]> {
const res = await fetch(
`${BASE_URL}/repos/${REPO_ID}/dir/?p=${DIR_TARGET}`,
{ headers }
);
if (!res.ok) {
throw new Error(`Failed get dir items: ${res.statusText}`);
}
return res.json();
}
/**
* Ambil download URL file
*/
async function getDownloadUrl(filePath: string): Promise<string> {
const res = await fetch(
`${BASE_URL}/repos/${REPO_ID}/file/?p=${encodeURIComponent(filePath)}`,
{ headers }
);
if (!res.ok) {
throw new Error(`Failed get file url: ${res.statusText}`);
}
const data = await res.json();
return data;
}
/**
* Ambil semua download URL dari target dir
*/
async function getAllDownloadUrls() {
const items = await getDirItems();
const files = items.filter((item) => item.type === "file");
const results = await Promise.all(
files.map(async (file) => {
const filePath = `${DIR_TARGET}/${file.name}`;
const url = await getDownloadUrl(filePath);
return {
name: file.name,
path: filePath,
downloadUrl: url,
};
})
);
return results;
}
// contoh eksekusi
(async () => {
try {
console.log("ambil gambar")
const urls = await getAllDownloadUrls();
await Bun.write("list_image2.json", JSON.stringify(urls))
console.log("selesai !")
} catch (err) {
console.error(err);
}
})();

View File

@@ -1,6 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
serverExternalPackages: ['@elysiajs/static', 'elysia'],
experimental: {},
allowedDevOrigins: [
"http://192.168.1.82:3000", // buat akses dari HP/device lain
@@ -19,7 +20,6 @@ const nextConfig: NextConfig = {
},
];
},
};
export default nextConfig;

View File

@@ -5,7 +5,10 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
"start": "next start",
"test:api": "vitest run",
"test:e2e": "playwright test",
"test": "bun run test:api && bun run test:e2e"
},
"prisma": {
"seed": "bun run prisma/seed.ts"
@@ -30,7 +33,7 @@
"@mantine/modals": "^8.3.6",
"@mantine/tiptap": "^7.17.4",
"@paljs/types": "^8.1.0",
"@prisma/client": "^6.3.1",
"@prisma/client": "6.3.1",
"@tabler/icons-react": "^3.30.0",
"@tiptap/extension-highlight": "^2.11.7",
"@tiptap/extension-link": "^2.11.7",
@@ -45,17 +48,21 @@
"@types/bun": "^1.2.2",
"@types/leaflet": "^1.9.20",
"@types/lodash": "^4.17.16",
"@types/mime-types": "^3.0.1",
"@types/nodemailer": "^7.0.2",
"add": "^2.0.6",
"adm-zip": "^0.5.16",
"animate.css": "^4.1.1",
"async-mutex": "^0.5.0",
"bcryptjs": "^3.0.2",
"bun": "^1.2.2",
"chart.js": "^4.4.8",
"classnames": "^2.5.1",
"cli-progress": "^3.12.0",
"colors": "^1.4.0",
"date-fns": "^4.1.0",
"dayjs": "^1.11.13",
"dompurify": "^3.3.1",
"dotenv": "^17.2.3",
"elysia": "^1.3.5",
"embla-carousel": "^8.6.0",
@@ -63,7 +70,7 @@
"embla-carousel-react": "^8.6.0",
"extract-zip": "^2.0.1",
"form-data": "^4.0.2",
"framer-motion": "^12.23.5",
"framer-motion": "^12.38.0",
"get-port": "^7.1.0",
"iron-session": "^8.0.4",
"jose": "^6.1.0",
@@ -72,6 +79,7 @@
"leaflet": "^1.9.4",
"list": "^2.0.19",
"lodash": "^4.17.21",
"mime-types": "^3.0.2",
"motion": "^12.4.1",
"nanoid": "^5.1.5",
"next": "^15.5.2",
@@ -81,7 +89,7 @@
"p-limit": "^6.2.0",
"primeicons": "^7.0.0",
"primereact": "^10.9.6",
"prisma": "^6.3.1",
"prisma": "6.3.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-exif-orientation-img": "^0.1.5",
@@ -92,7 +100,7 @@
"react-transition-group": "^4.4.5",
"react-zoom-pan-pinch": "^3.7.0",
"readdirp": "^4.1.1",
"recharts": "^2.15.3",
"recharts": "^3.8.0",
"sharp": "^0.34.3",
"swr": "^2.3.2",
"uuid": "^11.1.0",
@@ -102,16 +110,24 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@playwright/test": "^1.58.2",
"@testing-library/jest-dom": "^6.9.1",
"@types/cli-progress": "^3.11.6",
"@types/dompurify": "^3.2.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitest/ui": "^4.0.18",
"eslint": "^9",
"eslint-config-next": "15.1.6",
"jsdom": "^28.0.0",
"msw": "^2.12.9",
"parcel": "^2.6.2",
"postcss": "^8.5.1",
"postcss-preset-mantine": "^1.17.0",
"postcss-simple-vars": "^7.0.1",
"typescript": "^5"
"typescript": "^5",
"vitest": "^4.0.18"
}
}

View File

@@ -0,0 +1,208 @@
# Page snapshot
```yaml
- generic [active] [ref=e1]:
- generic [ref=e2]:
- generic [ref=e7]:
- button "Darmasaba Logo" [ref=e8] [cursor=pointer]:
- img "Darmasaba Logo" [ref=e10]
- button "PPID" [ref=e11] [cursor=pointer]:
- generic [ref=e13]: PPID
- button "Desa" [ref=e14] [cursor=pointer]:
- generic [ref=e16]: Desa
- button "Kesehatan" [ref=e17] [cursor=pointer]:
- generic [ref=e19]: Kesehatan
- button "Keamanan" [ref=e20] [cursor=pointer]:
- generic [ref=e22]: Keamanan
- button "Ekonomi" [ref=e23] [cursor=pointer]:
- generic [ref=e25]: Ekonomi
- button "Inovasi" [ref=e26] [cursor=pointer]:
- generic [ref=e28]: Inovasi
- button "Lingkungan" [ref=e29] [cursor=pointer]:
- generic [ref=e31]: Lingkungan
- button "Pendidikan" [ref=e32] [cursor=pointer]:
- generic [ref=e34]: Pendidikan
- button "Musik" [ref=e35] [cursor=pointer]:
- generic [ref=e37]: Musik
- button [ref=e38] [cursor=pointer]:
- img [ref=e40]
- generic [ref=e46]:
- generic [ref=e51]:
- generic [ref=e52]:
- generic [ref=e53]:
- img "Logo Darmasaba" [ref=e55]
- img "Logo Pudak" [ref=e57]
- generic [ref=e63]:
- generic [ref=e65]:
- generic [ref=e66]:
- img [ref=e67]
- paragraph [ref=e71]: Jam Operasional
- generic [ref=e72]:
- generic [ref=e74]: Buka
- paragraph [ref=e75]: 07:30 - 15:30
- generic [ref=e77]:
- generic [ref=e78]:
- img [ref=e79]
- paragraph [ref=e82]: Hari Ini
- generic [ref=e83]:
- paragraph [ref=e84]: Status Kantor
- paragraph [ref=e85]: Sedang Beroperasi
- paragraph [ref=e95]: Bagikan ide, kritik, atau saran Anda untuk mendukung pembangunan desa. Semua lebih mudah dengan fitur interaktif yang kami sediakan.
- generic [ref=e102]:
- generic [ref=e103]: Browser Anda tidak mendukung video.
- generic [ref=e106]:
- heading "Penghargaan Desa" [level=2] [ref=e107]
- paragraph [ref=e110]: Sedang memuat data penghargaan...
- button "Lihat semua penghargaan" [ref=e111] [cursor=pointer]:
- generic [ref=e112]:
- paragraph [ref=e114]: Lihat Semua Penghargaan
- img [ref=e116]
- generic [ref=e119]:
- generic [ref=e121]:
- heading "Layanan" [level=1] [ref=e122]
- paragraph [ref=e123]: Layanan adalah fitur yang membantu warga desa mengakses berbagai kebutuhan administrasi, informasi, dan bantuan secara cepat, mudah, dan transparan. Dengan fitur ini, semua layanan desa ada dalam genggaman Anda!
- link "Detail" [ref=e125] [cursor=pointer]:
- /url: /darmasaba/desa/layanan
- generic [ref=e127]: Detail
- separator [ref=e129]
- generic [ref=e130]:
- generic [ref=e131]:
- paragraph [ref=e132]: Potensi Desa
- paragraph [ref=e133]: Jelajahi berbagai potensi dan peluang yang dimiliki desa. Fitur ini membantu warga maupun pemerintah desa dalam merencanakan dan mengembangkan program berbasis kekuatan lokal.
- paragraph [ref=e136]: Sedang memuat potensi desa...
- button "Lihat Semua Potensi" [ref=e139] [cursor=pointer]:
- generic [ref=e140]:
- generic [ref=e141]: Lihat Semua Potensi
- img [ref=e143]
- separator [ref=e146]
- generic [ref=e147]:
- generic [ref=e148]:
- paragraph [ref=e150]: Desa Anti Korupsi
- paragraph [ref=e151]: Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola secara terbuka dengan melibatkan warga dalam pengawasan anggaran, sehingga digunakan tepat sasaran dan sesuai kebutuhan masyarakat.
- link "Selengkapnya" [ref=e153] [cursor=pointer]:
- /url: /darmasaba/desa-anti-korupsi/detail
- generic [ref=e155]: Selengkapnya
- paragraph [ref=e158]: Memuat Data...
- generic [ref=e166]:
- heading "SDGs Desa" [level=1] [ref=e168]
- paragraph [ref=e169]: SDGs Desa adalah upaya desa untuk menciptakan pembangunan yang maju, inklusif, dan berkelanjutan melalui 17 tujuan mulai dari pengentasan kemiskinan, pendidikan, kesehatan, hingga pelestarian lingkungan.
- generic [ref=e170]:
- generic [ref=e171]:
- img [ref=e172]
- paragraph [ref=e175]: Data SDGs Desa belum tersedia
- link "Jelajahi Semua Tujuan SDGs Desa" [ref=e177] [cursor=pointer]:
- /url: /darmasaba/sdgs-desa
- paragraph [ref=e180]: Jelajahi Semua Tujuan SDGs Desa
- generic [ref=e181]:
- generic [ref=e183]:
- heading "APBDes" [level=1] [ref=e184]
- paragraph [ref=e185]: Transparansi APBDes Darmasaba adalah langkah nyata menuju tata kelola desa yang bersih, terbuka, dan bertanggung jawab.
- link "Lihat Semua Data" [ref=e187] [cursor=pointer]:
- /url: /darmasaba/apbdes
- generic [ref=e189]: Lihat Semua Data
- generic [ref=e191]:
- paragraph [ref=e193]: Pilih Tahun APBDes
- generic [ref=e194]:
- textbox "Pilih Tahun APBDes" [ref=e195]:
- /placeholder: Pilih tahun
- generic:
- img
- paragraph [ref=e197]: Tidak ada data APBDes untuk tahun yang dipilih.
- generic [ref=e202]:
- heading "Prestasi Desa" [level=1] [ref=e203]
- paragraph [ref=e204]: Kami bangga dengan pencapaian desa hingga saat ini. Semoga prestasi ini menjadi inspirasi untuk terus berkarya dan berinovasi demi kemajuan bersama.
- link "Lihat Semua Prestasi" [ref=e205] [cursor=pointer]:
- /url: /darmasaba/prestasi-desa
- generic [ref=e207]: Lihat Semua Prestasi
- button [ref=e211] [cursor=pointer]:
- img [ref=e214]
- button [ref=e219] [cursor=pointer]:
- img [ref=e221]
- generic [ref=e225]:
- contentinfo [ref=e228]:
- generic [ref=e230]:
- generic [ref=e231]:
- heading "Komitmen Layanan Kami" [level=2] [ref=e232]
- generic [ref=e233]:
- generic [ref=e234]:
- paragraph [ref=e235]: "1. Transparansi:"
- paragraph [ref=e236]: Pengelolaan dana desa dilakukan secara terbuka agar masyarakat dapat memahami dan memantau penggunaan anggaran.
- generic [ref=e237]:
- paragraph [ref=e238]: "2. Profesionalisme:"
- paragraph [ref=e239]: Layanan desa diberikan secara cepat, adil, dan profesional demi kepuasan masyarakat.
- generic [ref=e240]:
- paragraph [ref=e241]: "3. Partisipasi:"
- paragraph [ref=e242]: Masyarakat dilibatkan aktif dalam pengambilan keputusan demi pembangunan desa yang berhasil.
- generic [ref=e243]:
- paragraph [ref=e244]: "4. Inovasi:"
- paragraph [ref=e245]: Kami terus berinovasi, termasuk melalui teknologi, agar layanan semakin mudah diakses.
- generic [ref=e246]:
- paragraph [ref=e247]: "5. Keadilan:"
- paragraph [ref=e248]: Kebijakan dan program disusun untuk memberi manfaat yang merata bagi seluruh warga.
- generic [ref=e249]:
- paragraph [ref=e250]: "6. Pemberdayaan:"
- paragraph [ref=e251]: Masyarakat didukung melalui pelatihan, pendampingan, dan pengembangan usaha lokal.
- generic [ref=e252]:
- paragraph [ref=e253]: "7. Ramah Lingkungan:"
- paragraph [ref=e254]: Seluruh kegiatan pembangunan memperhatikan keberlanjutan demi menjaga alam dan kesehatan warga.
- separator [ref=e255]
- generic [ref=e256]:
- heading "Visi Kami" [level=2] [ref=e257]
- paragraph [ref=e258]: Dengan visi ini, kami berkomitmen menjadikan desa sebagai tempat yang aman, sejahtera, dan nyaman bagi seluruh warga.
- paragraph [ref=e259]: Kami percaya kemajuan dimulai dari kerja sama antara pemerintah desa dan masyarakat, didukung tata kelola yang baik demi kepentingan bersama. Saran maupun keluhan dapat disampaikan melalui kontak di bawah ini.
- generic [ref=e260]:
- paragraph [ref=e261]: "\"Desa Kuat, Warga Sejahtera!\""
- button "Logo Desa" [ref=e262] [cursor=pointer]:
- generic [ref=e263]:
- img "Logo Desa"
- generic [ref=e265]:
- generic [ref=e267]:
- paragraph [ref=e268]: Tentang Darmasaba
- paragraph [ref=e269]: Darmasaba adalah desa budaya yang kaya akan tradisi dan nilai-nilai warisan Bali.
- generic [ref=e270]:
- link [ref=e271] [cursor=pointer]:
- /url: https://www.facebook.com/DarmasabaDesaku
- img [ref=e273]
- link [ref=e275] [cursor=pointer]:
- /url: https://www.instagram.com/ddarmasaba/
- img [ref=e277]
- link [ref=e280] [cursor=pointer]:
- /url: https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg
- img [ref=e282]
- link [ref=e285] [cursor=pointer]:
- /url: https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc
- img [ref=e287]
- generic [ref=e290]:
- paragraph [ref=e291]: Layanan Desa
- link "Administrasi Kependudukan" [ref=e292] [cursor=pointer]:
- /url: /darmasaba/desa/layanan/
- link "Layanan Sosial" [ref=e293] [cursor=pointer]:
- /url: /darmasaba/ekonomi/program-kemiskinan
- link "Pengaduan Masyarakat" [ref=e294] [cursor=pointer]:
- /url: /darmasaba/keamanan/laporan-publik
- link "Informasi Publik" [ref=e295] [cursor=pointer]:
- /url: /darmasaba/ppid/daftar-informasi-publik-desa-darmasaba
- generic [ref=e297]:
- paragraph [ref=e298]: Tautan Penting
- link "Portal Badung" [ref=e299] [cursor=pointer]:
- /url: /darmasaba/desa/berita/semua
- link "E-Government" [ref=e300] [cursor=pointer]:
- /url: /darmasaba/inovasi/desa-digital-smart-village
- link "Transparansi" [ref=e301] [cursor=pointer]:
- /url: /darmasaba/ppid/daftar-informasi-publik-desa-darmasaba
- generic [ref=e303]:
- paragraph [ref=e304]: Berlangganan Info
- paragraph [ref=e305]: Dapatkan kabar terbaru tentang program dan kegiatan desa langsung ke email Anda.
- generic [ref=e306]:
- generic [ref=e308]:
- textbox "Masukkan email Anda" [ref=e309]
- img [ref=e311]
- button "Daftar" [ref=e314] [cursor=pointer]:
- generic [ref=e316]: Daftar
- separator [ref=e317]
- paragraph [ref=e318]: © 2025 Desa Darmasaba. Hak cipta dilindungi.
- region "Notifications Alt+T"
- button "Open Next.js Dev Tools" [ref=e324] [cursor=pointer]:
- img [ref=e325]
- alert [ref=e328]
```

File diff suppressed because one or more lines are too long

25
playwright.config.ts Normal file
View File

@@ -0,0 +1,25 @@
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './__tests__/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'bun run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});

View File

@@ -1,14 +1,15 @@
module.exports = {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
/* Mobile first */
'mantine-breakpoint-xs': '30em', // 480px → mobile kecilnormal
'mantine-breakpoint-sm': '48em', // 768px → tablet / mobile landscape
'mantine-breakpoint-md': '64em', // 1024px → laptop & desktop kecil
'mantine-breakpoint-lg': '80em', // 1280px → desktop standar
'mantine-breakpoint-xl': '90em', // 1440px+ → desktop besar
},
},
};
},
};

View File

@@ -0,0 +1,94 @@
import prisma from "@/lib/prisma";
import kategoriBerita from "../../../data/desa/berita/kategori-berita.json";
import beritaJson from "../../../data/desa/berita/berita.json";
export async function seedBerita() {
// ================== SUBMENU BERITA ========================
console.log("🔄 Seeding Kategori Berita...");
for (const k of kategoriBerita) {
await prisma.kategoriBerita.upsert({
where: {
name: k.name, // ✅ cocok dengan @unique
},
update: {
name: k.name,
isActive: true,
},
create: {
id: k.id, // ✅ id tetap bisa disimpan
name: k.name,
isActive: true,
},
});
}
console.log("kategori berita success ...");
console.log("🔄 Seeding Berita...");
// Build a map of valid kategori IDs
const validKategoriIds = new Set<string>();
const kategoriList = await prisma.kategoriBerita.findMany({
select: { id: true, name: true },
});
kategoriList.forEach((k) => validKategoriIds.add(k.id));
console.log(`📋 Found ${validKategoriIds.size} valid kategori IDs in database`);
for (const b of beritaJson) {
// Validate kategoriBeritaId exists
if (!b.kategoriBeritaId || !validKategoriIds.has(b.kategoriBeritaId)) {
console.warn(
`⚠️ Skipping berita "${b.judul}": Invalid kategoriBeritaId "${b.kategoriBeritaId}"`,
);
continue;
}
let imageId: string | null = null;
if (b.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: b.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for berita "${b.judul}": ${b.imageName}`,
);
} else {
imageId = image.id;
}
}
try {
await prisma.berita.upsert({
where: { id: b.id },
update: {
judul: b.judul,
deskripsi: b.deskripsi,
content: b.content,
kategoriBeritaId: b.kategoriBeritaId,
imageId,
},
create: {
id: b.id,
judul: b.judul,
deskripsi: b.deskripsi,
content: b.content,
kategoriBeritaId: b.kategoriBeritaId,
imageId,
},
});
console.log(`✅ Berita seeded: ${b.judul}`);
} catch (error: any) {
console.error(
`❌ Failed to seed berita "${b.judul}": ${error.message}`,
);
}
}
console.log("🎉 Berita seed selesai");
}

View File

@@ -0,0 +1,40 @@
import prisma from "@/lib/prisma";
import foto from "../../../../data/desa/gallery/foto/foto.json";
export async function seedFoto() {
console.log("🔄 Seeding Foto...");
for (const f of foto) {
let imagesId: string | null = null;
if (f.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: f.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for foto "${f.name}": ${f.imageName}`,
);
} else {
imagesId = image.id;
}
}
await prisma.galleryFoto.upsert({
where: { id: f.id },
update: {
name: f.name,
deskripsi: f.deskripsi,
imagesId,
},
create: {
id: f.id,
name: f.name,
deskripsi: f.deskripsi,
imagesId,
},
});
}
console.log("✅ Foto seeding completed");
}

View File

@@ -0,0 +1,25 @@
import prisma from "@/lib/prisma";
import galleryVideo from "../../../../data/desa/gallery/video/video.json";
export async function seedVideo() {
console.log("🔄 Seeding Gallery Video...");
for (const v of galleryVideo) {
await prisma.galleryVideo.upsert({
where: {
id: v.id,
},
update: {
name: v.judul,
deskripsi: v.deskripsi,
linkVideo: v.linkVideo,
},
create: {
name: v.judul,
deskripsi: v.deskripsi,
linkVideo: v.linkVideo,
},
});
}
console.log("gallery video success ...");
}

View File

@@ -0,0 +1,128 @@
import prisma from "@/lib/prisma";
import pelayananSuratKeterangan from "../../../data/desa/layanan/pelayananSuratKeterangan.json";
import pelayananTelunjukSaktiDesa from "../../../data/desa/layanan/pelayananTelunjukSaktiDesa.json";
import pelayananPerizinanBerusaha from "../../../data/desa/layanan/pelayananPerizinanBerusaha.json";
import pelayananPendudukNonPermanen from "../../../data/desa/layanan/pelayananPendudukNonPermanen.json";
export async function seedLayanan() {
console.log("🔄 Seeding Pelayanan Surat Keterangan...");
for (const p of pelayananSuratKeterangan) {
const existing = await prisma.pelayananSuratKeterangan.findUnique({
where: { id: p.id },
select: { imageId: true, image2Id: true }, // 📌 tambahkan image2Id
});
// 1⃣ Handle imageId
let imageId = existing?.imageId ?? null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for pelayanan surat keterangan 1 "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
// 2⃣ Handle image2Id
let image2Id = existing?.image2Id ?? null;
if (p.image2Name) {
const image2 = await prisma.fileStorage.findUnique({
where: { name: p.image2Name },
select: { id: true },
});
if (!image2) {
console.warn(
`⚠️ Image not found for pelayanan surat keterangan 2 "${p.name}": ${p.image2Name}`,
);
} else {
image2Id = image2.id;
}
}
// 3⃣ Upsert dengan kedua image
await prisma.pelayananSuratKeterangan.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
imageId,
image2Id, // 📌 tambahkan ini
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
imageId,
image2Id, // 📌 tambahkan ini
},
});
}
console.log("✅ Pelayanan Surat Keterangan success...");
for (const p of pelayananTelunjukSaktiDesa) {
await prisma.pelayananTelunjukSaktiDesa.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
link: p.link,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
link: p.link,
},
});
}
console.log("pelayanan telunjuk sakti desa success ...");
for (const l of pelayananPerizinanBerusaha) {
await prisma.pelayananPerizinanBerusaha.upsert({
where: {
id: l.id,
},
update: {
name: l.name,
deskripsi: l.deskripsi,
link: l.link,
},
create: {
id: l.id,
name: l.name,
deskripsi: l.deskripsi,
link: l.link,
},
});
}
console.log("pelayanan perizinan berusaha success ...");
for (const l of pelayananPendudukNonPermanen) {
await prisma.pelayananPendudukNonPermanen.upsert({
where: {
id: l.id,
},
update: {
name: l.name,
deskripsi: l.deskripsi,
},
create: {
id: l.id,
name: l.name,
deskripsi: l.deskripsi,
},
});
}
console.log("pelayanan penduduk non permanen success ...");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import penghargaan from "../../../data/desa/penghargaan/penghargaan.json"
export async function seedPenghargaan() {
console.log("🔄 Seeding Penghargaan...");
for (const m of penghargaan) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for penghargaan "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.penghargaan.upsert({
where: { id: m.id },
update: {
name: m.name,
juara: m.juara,
deskripsi: m.deskripsi,
imageId,
},
create: {
id: m.id,
name: m.name,
juara: m.juara,
deskripsi: m.deskripsi,
imageId,
},
});
}
console.log("penghargaan success ...");
}

View File

@@ -0,0 +1,43 @@
import prisma from "@/lib/prisma";
import { safeSeedUnique } from "../../../safeseedUnique";
import kategoriPengumuman from "../../../data/desa/pengumuman/kategori-pengumuman.json";
import pengumuman from "../../../data/desa/pengumuman/pengumuman.json";
export async function seedPengumuman() {
console.log("🔄 Seeding Kategori Pengumuman...");
for (const c of kategoriPengumuman) {
await safeSeedUnique(
"categoryPengumuman",
{ name: c.name }, // ✅ where clause
{
id: c.id,
name: c.name,
},
);
}
console.log("kategori pengumuman success ...");
console.log("🔄 Seeding Pengumuman...");
for (const p of pengumuman) {
await prisma.pengumuman.upsert({
where: {
id: p.id,
},
update: {
judul: p.judul,
deskripsi: p.deskripsi,
content: p.content,
categoryPengumumanId: p.categoryPengumumanId,
},
create: {
judul: p.judul,
deskripsi: p.deskripsi,
content: p.content,
categoryPengumumanId: p.categoryPengumumanId,
},
});
}
console.log("pengumuman success ...");
}

View File

@@ -0,0 +1,64 @@
import prisma from "@/lib/prisma";
import kategoriPotensi from "../../../data/desa/potensi/kategori-potensi.json";
import potensiDesa from "../../../data/desa/potensi/potensi-desa.json";
export async function seedPotensi() {
console.log("🔄Seeding Kategori Potensi Desa ...");
for (const c of kategoriPotensi) {
await prisma.kategoriPotensi.upsert({
where: {
id: c.id,
},
update: {
nama: c.nama,
},
create: {
id: c.id,
nama: c.nama,
},
});
}
console.log("kategori Potensi success ...");
console.log("🔄 Seeding Potensi Desa...");
for (const m of potensiDesa) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for potensi desa "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.potensiDesa.upsert({
where: { id: m.id },
update: {
name: m.name,
deskripsi: m.deskripsi,
content: m.content,
kategoriId: m.kategoriId,
imageId,
},
create: {
id: m.id,
name: m.name,
deskripsi: m.deskripsi,
content: m.content,
kategoriId: m.kategoriId,
imageId,
},
});
}
console.log("potensi desa success ...");
}

View File

@@ -0,0 +1,168 @@
import prisma from "@/lib/prisma";
import lambangDesa from "../../../data/desa/profile/lambang_desa.json";
import maskotDesa from "../../../data/desa/profile/maskot_desa.json";
import profilePerbekel from "../../../data/desa/profile/profil_perbekel.json";
import profileDesaImage from "../../../data/desa/profile/profileDesaImage.json";
import sejarahDesa from "../../../data/desa/profile/sejarah_desa.json";
import visiMisiDesa from "../../../data/desa/profile/visi_misi_desa.json";
export async function seedProfileDesa() {
// =========== SEJARAH DESA ===========
for (const l of sejarahDesa) {
await prisma.sejarahDesa.upsert({
where: {
id: l.id,
},
update: {
judul: l.judul,
deskripsi: l.deskripsi,
},
create: {
id: l.id,
judul: l.judul,
deskripsi: l.deskripsi,
},
});
}
console.log("sejarah desa success ...");
// =========== VISI MISI DESA ===========
for (const l of visiMisiDesa) {
await prisma.visiMisiDesa.upsert({
where: {
id: l.id,
},
update: {
visi: l.visi,
misi: l.misi,
},
create: {
id: l.id,
visi: l.visi,
misi: l.misi,
},
});
}
console.log("visi misi desa success ...");
// =========== MASKOT DESA ===========
for (const l of maskotDesa) {
await prisma.maskotDesa.upsert({
where: {
id: l.id,
},
update: {
judul: l.judul,
deskripsi: l.deskripsi,
},
create: {
id: l.id,
judul: l.judul,
deskripsi: l.deskripsi,
},
});
}
console.log("maskot desa success ...");
console.log("🔄 Seeding Profile Desa Image...");
for (const m of profileDesaImage) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for profile desa image "${m.label}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.profileDesaImage.upsert({
where: { id: m.id },
update: {
label: m.label,
maskotDesaId: m.maskotDesaId,
imageId,
},
create: {
id: m.id,
label: m.label,
maskotDesaId: m.maskotDesaId,
imageId,
},
});
}
console.log("profile desa image success ...");
// =========== LAMBANG DESA ===========
for (const l of lambangDesa) {
await prisma.lambangDesa.upsert({
where: {
id: l.id,
},
update: {
judul: l.judul,
deskripsi: l.deskripsi,
},
create: {
id: l.id,
judul: l.judul,
deskripsi: l.deskripsi,
},
});
}
console.log("lambang desa success ...");
// =========== PROFILE PERBEKEL PROFILE DESA ===========
console.log("🔄 Seeding Profile Perbekel...");
for (const m of profilePerbekel) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for profile perbekel "${m.biodata}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.profilPerbekel.upsert({
where: { id: m.id },
update: {
biodata: m.biodata,
pengalaman: m.pengalaman,
pengalamanOrganisasi: m.pengalamanOrganisasi,
programUnggulan: m.programUnggulan,
imageId,
},
create: {
id: m.id,
biodata: m.biodata,
pengalaman: m.pengalaman,
pengalamanOrganisasi: m.pengalamanOrganisasi,
programUnggulan: m.programUnggulan,
imageId,
},
});
}
console.log("profile perbekel desa success ...");
}

View File

@@ -0,0 +1,42 @@
import prisma from "@/lib/prisma";
import perbekelDariMasaKeMasa from "../../../data/desa/profile/profile-perbekel-lalu.json";
export async function seedProfilePerbekel() {
console.log("🔄 Seeding Perbekel Dari Masa Ke Masa...");
for (const p of perbekelDariMasaKeMasa) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for Perbekel Dari Masa Ke Masa "${p.nama}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.perbekelDariMasaKeMasa.upsert({
where: { id: p.id },
update: {
nama: p.nama,
periode: p.periode,
daerah: p.daerah,
imageId,
},
create: {
id: p.id,
nama: p.nama,
periode: p.periode,
daerah: p.daerah,
imageId,
},
});
}
console.log("✅ Pejabat Desa seeding completed");
}

View File

@@ -0,0 +1,25 @@
import prisma from "@/lib/prisma";
import demografiPekerjaan from "../../data/ekonomi/demografi-pekerjaan/demografi-pekerjaan.json";
export async function seedDemografiPekerjaan() {
console.log("🔄 Seeding Demografi Pekerjaan...");
for (const k of demografiPekerjaan) {
await prisma.dataDemografiPekerjaan.upsert({
where: {
id: k.id,
},
update: {
pekerjaan: k.pekerjaan,
lakiLaki: k.lakiLaki,
perempuan: k.perempuan,
},
create: {
id: k.id,
pekerjaan: k.pekerjaan,
lakiLaki: k.lakiLaki,
perempuan: k.perempuan,
},
});
}
console.log("✅ Demografi Pekerjaan seeded successfully");
}

View File

@@ -0,0 +1,23 @@
import prisma from "@/lib/prisma";
import jumlahPendudukMiskin from "../../data/ekonomi/jumlah-penduduk-miskin/jumlah-penduduk-miskin.json";
export async function seedJumlahPendudukMiskin() {
console.log("🔄 Seeding Jumlah Penduduk Miskin...");
for (const k of jumlahPendudukMiskin) {
await prisma.grafikJumlahPendudukMiskin.upsert({
where: {
id: k.id,
},
update: {
year: k.year,
totalPoorPopulation: k.totalPoorPopulation,
},
create: {
id: k.id,
year: k.year,
totalPoorPopulation: k.totalPoorPopulation,
},
});
}
console.log("✅ Jumlah Penduduk Miskin seeded successfully");
}

View File

@@ -0,0 +1,27 @@
import prisma from "@/lib/prisma";
import jumlahPengangguran from "../../data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
export async function seedJumlahPengangguran() {
for (const d of jumlahPengangguran) {
await prisma.detailDataPengangguran.upsert({
where: {
month_year: { month: d.month, year: d.year },
},
update: {
totalUnemployment: d.totalUnemployment,
educatedUnemployment: d.educatedUnemployment,
uneducatedUnemployment: d.uneducatedUnemployment,
percentageChange: d.percentageChange,
},
create: {
month: d.month,
year: d.year,
totalUnemployment: d.totalUnemployment,
educatedUnemployment: d.educatedUnemployment,
uneducatedUnemployment: d.uneducatedUnemployment,
percentageChange: d.percentageChange,
},
});
}
console.log("📊 detailDataPengangguran success ...");
}

View File

@@ -0,0 +1,35 @@
import prisma from "@/lib/prisma";
import lowonganKerjaLokal from "../../data/ekonomi/lowongan-kerja-lokal/lowongan-kerja-lokal.json";
export async function seedLowonganKerjaLokal() {
console.log("🔄 Seeding Lowongan Kerja Lokal...");
for (const k of lowonganKerjaLokal) {
await prisma.lowonganPekerjaan.upsert({
where: {
id: k.id,
},
update: {
posisi: k.posisi,
namaPerusahaan: k.namaPerusahaan,
lokasi: k.lokasi,
tipePekerjaan: k.tipePekerjaan,
gaji: k.gaji,
deskripsi: k.deskripsi,
kualifikasi: k.kualifikasi,
notelp: k.notelp,
},
create: {
id: k.id,
posisi: k.posisi,
namaPerusahaan: k.namaPerusahaan,
lokasi: k.lokasi,
tipePekerjaan: k.tipePekerjaan,
gaji: k.gaji,
deskripsi: k.deskripsi,
kualifikasi: k.kualifikasi,
notelp: k.notelp,
},
});
}
console.log("✅ Lowongan Kerja Lokal seeded successfully");
}

View File

@@ -0,0 +1,91 @@
import prisma from "@/lib/prisma";
import kategoriProduk from "../../data/ekonomi/pasar-desa/kategori-produk.json";
import pasarDesa from "../../data/ekonomi/pasar-desa/pasar-desa.json";
import kategoriToPasar from "../../data/ekonomi/pasar-desa/kategori-to-pasar.json";
export async function seedPasarDesa() {
console.log("🔄 Seeding Kategori Produk...");
for (const k of kategoriProduk) {
await prisma.kategoriProduk.upsert({
where: {
id: k.id,
},
update: {
nama: k.nama,
},
create: {
id: k.id,
nama: k.nama,
},
});
}
console.log("✅ Kategori Produk seeded successfully");
console.log("🔄 Seeding Pasar Desa...");
for (const p of pasarDesa) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for pasar desa "${p.nama}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.pasarDesa.upsert({
where: { id: p.id },
update: {
nama: p.nama,
deskripsi: p.deskripsi,
harga: p.harga,
rating: p.rating,
alamatUsaha: p.alamatUsaha,
kontak: p.kontak,
imageId,
kategoriProdukId: p.kategoriProdukId,
},
create: {
id: p.id,
nama: p.nama,
deskripsi: p.deskripsi,
harga: p.harga,
rating: p.rating,
alamatUsaha: p.alamatUsaha,
kontak: p.kontak,
imageId,
kategoriProdukId: p.kategoriProdukId,
},
});
console.log(`✅ Pasar desa seeded: ${p.nama}`);
}
console.log("🎉 Pasar desa seed selesai");
console.log("🔄 Seeding Kategori To Pasar...");
for (const p of kategoriToPasar) {
await prisma.kategoriToPasar.upsert({
where: {
id: p.id,
},
update: {
kategoriId: p.kategoriId,
pasarDesaId: p.pasarDesaId,
},
create: {
id: p.id,
kategoriId: p.kategoriId,
pasarDesaId: p.pasarDesaId,
},
});
}
}

View File

@@ -0,0 +1,81 @@
import prisma from "@/lib/prisma";
import apbdes from "../../data/ekonomi/pendapatan-asli-desa/apbDesa.json";
import pendapatan from "../../data/ekonomi/pendapatan-asli-desa/pendapatanDesa.json";
import belanja from "../../data/ekonomi/pendapatan-asli-desa/belanjaDesa.json";
import pembiayaan from "../../data/ekonomi/pendapatan-asli-desa/pembiayaanDesa.json";
export async function seedPendapatanAsli() {
console.log("🔄 Seeding Pendapatan Asli...");
for (const d of apbdes) {
await prisma.apbDesa.upsert({
where: {
id: d.id,
},
update: {
tahun: d.tahun,
},
create: {
id: d.id,
tahun: d.tahun,
},
});
}
console.log("✅ Pendapatan Asli seeded successfully");
console.log("🔄 Seeding Pendapatan...");
for (const d of pendapatan) {
await prisma.pendapatan.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
value: d.nilai
},
create: {
id: d.id,
name: d.name,
value: d.nilai
},
});
}
console.log("✅ Pendapatan seeded successfully");
console.log("🔄 Seeding Belanja...");
for (const d of belanja) {
await prisma.belanja.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
value: d.nilai
},
create: {
id: d.id,
name: d.name,
value: d.nilai
},
});
}
console.log("✅ Belanja seeded successfully");
console.log("🔄 Seeding Pembiayaan...");
for (const d of pembiayaan) {
await prisma.pembiayaan.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
value: d.nilai
},
create: {
id: d.id,
name: d.name,
value: d.nilai
},
});
}
console.log("✅ Pembiayaan seeded successfully");
}

View File

@@ -0,0 +1,50 @@
import prisma from "@/lib/prisma";
import grafikMenganggurBerdasarkanUsia from "../../data/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran-berdasarkan-usia.json";
import grafikMenganggurBerdasarkanPendidikan from "../../data/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran-berdasarkan-pendidikan.json";
export async function seedPendudukUsiaKerjaYangMenganggur() {
for (const p of grafikMenganggurBerdasarkanUsia) {
await prisma.grafikMenganggurBerdasarkanUsia.upsert({
where: {
id: p.id,
},
update: {
usia18_25: p.usia18_25,
usia26_35: p.usia26_35,
usia36_45: p.usia36_45,
usia46_keatas: p.usia46_keatas,
},
create: {
id: p.id,
usia18_25: p.usia18_25,
usia26_35: p.usia26_35,
usia36_45: p.usia36_45,
usia46_keatas: p.usia46_keatas,
},
});
}
console.log("📊 grafikMenganggurBerdasarkanUsia success ...");
for (const p of grafikMenganggurBerdasarkanPendidikan) {
await prisma.grafikMenganggurBerdasarkanPendidikan.upsert({
where: {
id: p.id,
},
update: {
SD: p.SD,
SMP: p.SMP,
SMA: p.SMA,
D3: p.D3,
S1: p.S1,
},
create: {
id: p.id,
SD: p.SD,
SMP: p.SMP,
SMA: p.SMA,
D3: p.D3,
S1: p.S1,
},
});
}
console.log("📊 grafikMenganggurBerdasarkanUsia success ...");
}

View File

@@ -0,0 +1,50 @@
import prisma from "@/lib/prisma";
import programKemiskinan from "../../data/ekonomi/program-kemiskinan/program-kemiskinan.json";
import statistikKemiskinan from "../../data/ekonomi/program-kemiskinan/statistik-kemiskinan.json";
export async function seedProgramKemiskinan() {
for (const s of statistikKemiskinan) {
await prisma.statistikKemiskinan.upsert({
where: { tahun: s.tahun }, // ✅ FIX
update: {
jumlah: s.jumlah,
},
create: {
id: s.id, // id boleh tetap
tahun: s.tahun,
jumlah: s.jumlah,
},
});
}
console.log("📊 Statistik Kemiskinan seeded successfully");
console.log("🔄 Seeding Program Kemiskinan...");
for (const k of programKemiskinan) {
await prisma.programKemiskinan.upsert({
where: { id: k.id },
update: {
nama: k.nama,
deskripsi: k.deskripsi,
icon: k.icon,
statistik: {
connect: {
tahun: k.tahun, // 👈 BUKAN ID
},
},
},
create: {
id: k.id,
nama: k.nama,
deskripsi: k.deskripsi,
icon: k.icon,
statistik: {
connect: {
tahun: k.tahun,
},
},
},
});
}
console.log("✅ Program Kemiskinan seeded successfully");
}

View File

@@ -0,0 +1,25 @@
import prisma from "@/lib/prisma";
import sektorUnggulanDesa from "../../data/ekonomi/sektor-unggulan/sektor-unggulan.json";
export async function seedSektorUnggulanDesa() {
console.log("🔄 Seeding Sektor Unggulan Desa...");
for (const k of sektorUnggulanDesa) {
await prisma.sektorUnggulanDesa.upsert({
where: {
id: k.id,
},
update: {
name: k.name,
description: k.description,
value: k.value,
},
create: {
id: k.id,
name: k.name,
description: k.description,
value: k.value,
},
});
}
console.log("✅ Sektor Unggulan Desa seeded successfully");
}

View File

@@ -0,0 +1,58 @@
import prisma from "@/lib/prisma";
import posisiOrganisasiBumDes from "../../data/ekonomi/struktur-organisasi/posisi-organisasi-bumdes.json";
import pegawai from "../../data/ekonomi/struktur-organisasi/pegawai-bumdes.json";
export async function seedStrukturBumdes() {
const flattenedPosisi = posisiOrganisasiBumDes.flat();
// ✅ Urutkan berdasarkan hierarki
const sortedPosisi = flattenedPosisi.sort((a, b) => a.hierarki - b.hierarki);
for (const p of sortedPosisi) {
console.log(`Seeding: ${p.nama} (id: ${p.id}, parent: ${p.parentId})`);
if (p.parentId) {
const parentExists = flattenedPosisi.some((pos) => pos.id === p.parentId);
if (!parentExists) {
console.warn(
`⚠️ Parent tidak ditemukan: ${p.parentId} untuk ${p.nama}`,
);
continue;
}
}
await prisma.posisiOrganisasiBumDes.upsert({
where: { id: p.id },
update: p,
create: p,
});
}
console.log("posisi organisasi berhasil");
for (const p of pegawai) {
await prisma.pegawaiBumDes.upsert({
where: {
id: p.id,
},
update: {
namaLengkap: p.namaLengkap,
gelarAkademik: p.gelarAkademik,
tanggalMasuk: new Date(p.tanggalMasuk),
email: p.email,
telepon: p.telepon,
alamat: p.alamat,
posisiId: p.posisiId,
isActive: p.isActive,
},
create: {
id: p.id,
namaLengkap: p.namaLengkap,
gelarAkademik: p.gelarAkademik,
tanggalMasuk: new Date(p.tanggalMasuk),
email: p.email,
telepon: p.telepon,
alamat: p.alamat,
posisiId: p.posisiId,
isActive: p.isActive,
},
});
}
console.log("pegawai success ...");
}

View File

@@ -0,0 +1,31 @@
import prisma from "@/lib/prisma";
import ajukanIde from "../../data/inovasi/ajukan-ide/ajukan-ide.json";
export async function seedAjukan() {
console.log("🔄 Seeding Ajukan Ide Inovatif...");
for (const d of ajukanIde) {
await prisma.ajukanIdeInovatif.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
alamat: d.alamat,
namaIde: d.namaIde,
deskripsi: d.deskripsi,
masalah: d.masalah,
benefit: d.benefit,
},
create: {
id: d.id,
name: d.name,
alamat: d.alamat,
namaIde: d.namaIde,
deskripsi: d.deskripsi,
masalah: d.masalah,
benefit: d.benefit,
},
});
}
console.log("✅ Ajukan Ide Inovatif seeded successfully");
}

View File

@@ -0,0 +1,42 @@
import prisma from "@/lib/prisma";
import desaDigital from "../../data/inovasi/desa-digital/desa-digital.json";
export async function seedDesaDigital() {
console.log("🔄 Seeding Desa Digital...");
for (const d of desaDigital) {
let imageId: string | null = null;
if (d.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: d.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for desa digital "${d.name}": ${d.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.desaDigital.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
deskripsi: d.deskripsi,
imageId: imageId,
},
create: {
id: d.id,
name: d.name,
deskripsi: d.deskripsi,
imageId: imageId,
},
});
}
console.log("✅ Desa Digital seeded successfully");
}

View File

@@ -0,0 +1,42 @@
import prisma from "@/lib/prisma";
import infoTeknologi from "../../data/inovasi/info-teknologi/info-teknologi.json";
export async function seedInfoTeknologi() {
console.log("🔄 Seeding Info Teknologi...");
for (const p of infoTeknologi) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for berita "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.infoTekno.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
deskripsi: p.deskripsi,
imageId: imageId,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
imageId: imageId,
},
});
}
console.log("✅ Info Teknologi seeded successfully");
}

View File

@@ -0,0 +1,66 @@
import prisma from "@/lib/prisma";
import kolaborasiInovasi from "../../data/inovasi/kolaborasi-inovasi/kolaborasi-inovasi.json";
import mitraKolaborasi from "../../data/inovasi/kolaborasi-inovasi/mitra-kolaborasi.json";
export async function seedKolaborasiInovasi() {
console.log("🔄 Seeding Kolaborasi Inovasi...");
for (const p of kolaborasiInovasi) {
await prisma.kolaborasiInovasi.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
tahun: p.tahun,
slug: p.slug,
deskripsi: p.deskripsi,
kolaborator: p.kolaborator,
},
create: {
id: p.id,
name: p.name,
tahun: p.tahun,
slug: p.slug,
deskripsi: p.deskripsi,
kolaborator: p.kolaborator,
},
});
}
console.log("✅ Kolaborasi Inovasi seeded successfully");
console.log("🔄 Seeding Mitra Kolaborasi...");
for (const p of mitraKolaborasi) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for mitra kolaborasi "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.mitraKolaborasi.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
imageId: imageId,
},
create: {
id: p.id,
name: p.name,
imageId: imageId,
},
});
}
console.log("✅ Mitra Kolaborasi seeded successfully");
}

View File

@@ -0,0 +1,113 @@
import prisma from "@/lib/prisma";
import jenisLayanan from "../../data/inovasi/layanan-online-desa/jenis-layanan.json";
import administrasiOnline from "../../data/inovasi/layanan-online-desa/administrasi-online.json";
import jenisPengaduan from "../../data/inovasi/layanan-online-desa/jenis-pengaduan.json";
import pengaduanMasyarakat from "../../data/inovasi/layanan-online-desa/pengaduan-masyarakat.json";
export async function seedLayananOnlineDesa() {
console.log("🔄 Seeding Jenis Layanan...");
for (const j of jenisLayanan) {
await prisma.jenisLayanan.upsert({
where: {
id: j.id,
},
update: {
nama: j.nama,
deskripsi: j.deskripsi,
},
create: {
id: j.id,
nama: j.nama,
deskripsi: j.deskripsi,
},
});
}
console.log("✅ Jenis Layanan seeded successfully");
console.log("🔄 Seeding Administrasi Online...");
for (const d of administrasiOnline) {
await prisma.administrasiOnline.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
alamat: d.alamat,
nomorTelepon: d.nomorTelepon,
jenisLayananId: d.jenisLayananId,
},
create: {
id: d.id,
name: d.name,
alamat: d.alamat,
nomorTelepon: d.nomorTelepon,
jenisLayananId: d.jenisLayananId,
},
});
}
console.log("✅ Administrasi Online seeded successfully");
console.log("🔄 Seeding Jenis Pengaduan Masyarakat...");
for (const d of jenisPengaduan) {
await prisma.jenisPengaduan.upsert({
where: {
id: d.id,
},
update: {
nama: d.nama,
},
create: {
id: d.id,
nama: d.nama,
},
});
}
console.log("✅ Jenis Pengaduan Masyarakat seeded successfully");
console.log("🔄 Seeding Pengaduan Masyarakat...");
for (const d of pengaduanMasyarakat) {
let imageId: string | null = null;
if (d.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: d.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for pengaduan masyarakat "${d.name}": ${d.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.pengaduanMasyarakat.upsert({
where: {
id: d.id,
},
update: {
name: d.name,
email: d.email,
nik: d.nik,
nomorTelepon: d.nomorTelepon,
judulPengaduan: d.judulPengaduan,
lokasiKejadian: d.lokasiKejadian,
imageId: imageId,
deskripsiPengaduan: d.deskripsiPengaduan,
jenisPengaduanId: d.jenisPengaduanId,
},
create: {
id: d.id,
name: d.name,
email: d.email,
nik: d.nik,
nomorTelepon: d.nomorTelepon,
judulPengaduan: d.judulPengaduan,
lokasiKejadian: d.lokasiKejadian,
imageId: imageId,
deskripsiPengaduan: d.deskripsiPengaduan,
jenisPengaduanId: d.jenisPengaduanId,
},
});
}
console.log("✅ Pengaduan Masyarakat seeded successfully");
}

View File

@@ -0,0 +1,27 @@
import prisma from "@/lib/prisma";
import programKreatif from "../../data/inovasi/program-kreatif-desa/program-kreatif-desa.json";
export async function seedProgramKreatifDesa() {
console.log("🔄 Seeding Program Kreatif...");
for (const p of programKreatif) {
await prisma.programKreatif.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
deskripsi: p.deskripsi,
icon: p.icon,
slug: p.slug,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
icon: p.icon,
slug: p.slug,
},
});
}
console.log("✅ Program Kreatif seeded successfully");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import keamananLingkunganJson from "../../data/keamanan/keamanan-lingkungan/keamanan-lingkungan.json";
export async function seedKeamananLingkungan() {
console.log("🔄 Seeding Keamanan Lingkungan...");
for (const p of keamananLingkunganJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for keamanan lingkungan "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.keamananLingkungan.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
imageId,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
imageId,
},
});
console.log(`✅ Keamanan lingkungan seeded: ${p.name}`);
}
console.log("🎉 Keamanan lingkungan seed selesai");
}

View File

@@ -0,0 +1,87 @@
import prisma from "@/lib/prisma";
import kontakDaruratKeamanan from "../../data/keamanan/kontak-darurat-keamanan/kontak-darurat-keamanan.json";
import kontakItem from "../../data/keamanan/kontak-darurat-keamanan/kontakItem.json";
import kontakDaruratToItem from "../../data/keamanan/kontak-darurat-keamanan/kontakDaruratToItem.json";
export async function seedKontakDaruratKeamanan() {
console.log("🔄 Seeding Kontak Item...");
for (const e of kontakItem) {
await prisma.kontakItem.upsert({
where: {
id: e.id,
},
update: {
nama: e.nama,
icon: e.icon,
nomorTelepon: e.nomorTelepon,
},
create: {
id: e.id, // ✅ WAJIB
nama: e.nama,
icon: e.icon,
nomorTelepon: e.nomorTelepon,
},
});
}
console.log("✅ Kontak Item seeded successfully");
console.log("🔄 Seeding Kontak Darurat Keamanan...");
for (const d of kontakDaruratKeamanan) {
await prisma.kontakDaruratKeamanan.upsert({
where: {
id: d.id,
},
update: {
nama: d.nama,
icon: d.icon,
kategoriId: d.kategoriId,
},
create: {
id: d.id,
nama: d.nama,
icon: d.icon,
kategoriId: d.kategoriId,
},
});
}
console.log("✅ Kontak Darurat Keamanan seeded successfully");
console.log("🔄 Seeding Kontak Darurat To Item...");
for (const f of kontakDaruratToItem) {
// ✅ Validasi foreign keys
const kontakDaruratExists = await prisma.kontakDaruratKeamanan.findUnique({
where: { id: f.kontakDaruratId },
});
const kontakItemExists = await prisma.kontakItem.findUnique({
where: { id: f.kontakItemId },
});
if (!kontakDaruratExists) {
console.warn(
`⚠️ KontakDarurat ${f.kontakDaruratId} not found, skipping...`,
);
continue;
}
if (!kontakItemExists) {
console.warn(`⚠️ KontakItem ${f.kontakItemId} not found, skipping...`);
continue;
}
await prisma.kontakDaruratToItem.upsert({
where: { id: f.id },
update: {
kontakDaruratId: f.kontakDaruratId,
kontakItemId: f.kontakItemId,
},
create: {
id: f.id,
kontakDaruratId: f.kontakDaruratId,
kontakItemId: f.kontakItemId,
},
});
}
console.log("✅ Kontak Darurat To Item seeded successfully");
}

View File

@@ -0,0 +1,49 @@
import prisma from "@/lib/prisma";
import laporanPublik from "../../data/keamanan/laporan-publik/laporan-publik.json";
import penangananLaporan from "../../data/keamanan/laporan-publik/penanganan-laporan.json";
export async function seedLaporanPublik() {
console.log("🔄 Seeding Laporan Publik...");
for (const l of laporanPublik) {
await prisma.laporanPublik.upsert({
where: {
id: l.id,
},
update: {
judul: l.judul,
lokasi: l.lokasi,
tanggalWaktu: l.tanggalWaktu,
kronologi: l.kronologi,
},
create: {
id: l.id,
judul: l.judul,
lokasi: l.lokasi,
tanggalWaktu: l.tanggalWaktu,
kronologi: l.kronologi,
},
});
}
console.log("laporan publik success ...");
console.log("🔄 Seeding Penanganan Laporan...");
for (const l of penangananLaporan) {
await prisma.penangananLaporanPublik.upsert({
where: {
id: l.id,
},
update: {
deskripsi: l.deskripsi,
laporanId: l.laporanId,
},
create: {
id: l.id,
deskripsi: l.deskripsi,
laporanId: l.laporanId,
},
});
}
console.log("penanganan laporan success ...");
}

View File

@@ -0,0 +1,28 @@
import prisma from "@/lib/prisma";
import pencegahanKriminalitas from "../../data/keamanan/pencegahan-kriminalitas/pencegahan-kriminalitas.json";
export async function seedPencegahanKriminalitas() {
console.log("🔄 Seeding Pencegahan Kriminalitas...");
for (const d of pencegahanKriminalitas) {
await prisma.pencegahanKriminalitas.upsert({
where: {
id: d.id,
},
update: {
judul: d.judul,
deskripsi: d.deskripsi,
deskripsiSingkat: d.deskripsiSingkat,
linkVideo: d.linkVideo,
},
create: {
id: d.id,
judul: d.judul,
deskripsi: d.deskripsi,
deskripsiSingkat: d.deskripsiSingkat,
linkVideo: d.linkVideo,
},
});
}
console.log("✅ Pencegahan Kriminalitas seeded successfully");
}

View File

@@ -0,0 +1,80 @@
import prisma from "@/lib/prisma";
import layananPolsek from "../../data/keamanan/polsek-terdekat/layanan-polsek.json";
import polsekTerdekat from "../../data/keamanan/polsek-terdekat/polsek-terdekat.json";
import layananToPolsek from "../../data/keamanan/polsek-terdekat/layanan-to-polsek.json";
export async function seedPolsekTerdekat() {
console.log("🔄 Seeding Layanan Polsek...");
for (const k of layananPolsek) {
await prisma.layananPolsek.upsert({
where: {
id: k.id,
},
update: {
nama: k.nama,
},
create: {
id: k.id,
nama: k.nama,
},
});
}
console.log("layanan polsek success ...");
console.log("🔄 Seeding Polsek Terdekat...");
for (const k of polsekTerdekat) {
await prisma.polsekTerdekat.upsert({
where: {
id: k.id,
},
update: {
nama: k.nama,
jarakKeDesa: k.jarakKeDesa,
alamat: k.alamat,
nomorTelepon: k.nomorTelepon,
jamOperasional: k.jamOperasional,
embedMapUrl: k.embedMapUrl,
namaTempatMaps: k.namaTempatMaps,
alamatMaps: k.alamatMaps,
linkPetunjukArah: k.linkPetunjukArah,
layananPolsekId: k.layananPolsekId,
},
create: {
id: k.id,
nama: k.nama,
jarakKeDesa: k.jarakKeDesa,
alamat: k.alamat,
nomorTelepon: k.nomorTelepon,
jamOperasional: k.jamOperasional,
embedMapUrl: k.embedMapUrl,
namaTempatMaps: k.namaTempatMaps,
alamatMaps: k.alamatMaps,
linkPetunjukArah: k.linkPetunjukArah,
layananPolsekId: k.layananPolsekId,
},
});
}
console.log("polsek terdekat success ...");
console.log("🔄 Seeding Layanan To Polsek...");
for (const k of layananToPolsek) {
await prisma.layananToPolsek.upsert({
where: {
id: k.id,
},
update: {
layananId: k.layananId,
polsekTerdekatId: k.polsekTerdekatId,
},
create: {
id: k.id,
layananId: k.layananId,
polsekTerdekatId: k.polsekTerdekatId,
},
});
}
console.log("layanan to polsek success ...");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import tipsKeamananJson from "../../data/keamanan/tips-keamanan/tips-keamanan.json";
export async function seedTipsKeamanan() {
console.log("🔄 Seeding Tips Keamanan...");
for (const p of tipsKeamananJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for tips keamanan "${p.judul}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.menuTipsKeamanan.upsert({
where: { id: p.id },
update: {
judul: p.judul,
deskripsi: p.deskripsi,
imageId,
},
create: {
id: p.id,
judul: p.judul,
deskripsi: p.deskripsi,
imageId,
},
});
console.log(`✅ Tips Keamanan seeded: ${p.judul}`);
}
console.log("🎉 Tips Keamanan seed selesai");
}

View File

@@ -0,0 +1,46 @@
import prisma from "@/lib/prisma";
import infoWabahPenyakitJson from "../../../data/kesehatan/infowabahpenyakit/infowabahpenyakit.json";
export async function seedInfoWabahPenyakit() {
console.log("🔄 Seeding Info Wabah Penyakit...");
for (const p of infoWabahPenyakitJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for info wabah penyakit "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.infoWabahPenyakit.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsiSingkat: p.deskripsiSingkat,
deskripsiLengkap: p.deskripsiLengkap,
imageId,
},
create: {
id: p.id,
name: p.name,
deskripsiSingkat: p.deskripsiSingkat,
deskripsiLengkap: p.deskripsiLengkap,
imageId,
},
});
console.log(`✅ Info wabah penyakit seeded: ${p.name}`);
}
console.log("🎉 Info wabah penyakit seed selesai");
}

View File

@@ -0,0 +1,46 @@
import kontakDaruratJson from "../../../data/kesehatan/kontak-darurat/kontak-darurat.json";
import prisma from "@/lib/prisma";
export async function seedKontakDarurat() {
console.log("🔄 Seeding Kontak Darurat...");
for (const p of kontakDaruratJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for kontak darurat "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.kontakDarurat.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
imageId,
whatsapp: p.whatsapp,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
imageId,
whatsapp: p.whatsapp,
},
});
console.log(`✅ Kontak darurat seeded: ${p.name}`);
}
console.log("🎉 Kontak darurat seed selesai");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import penangananDaruratJson from "../../../data/kesehatan/penanganan-darurat/penganan-darurat.json";
export async function seedPenangananDarurat() {
console.log("🔄 Seeding Penanganan Darurat...");
for (const p of penangananDaruratJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for penanganan darurat "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.penangananDarurat.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
imageId,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
imageId,
},
});
console.log(`✅ Penanganan darurat seeded: ${p.name}`);
}
console.log("🎉 Penanganan darurat seed selesai");
}

View File

@@ -0,0 +1,48 @@
import prisma from "@/lib/prisma";
import posyanduJson from "../../../data/kesehatan/posyandu/posyandu.json";
export async function seedPosyandu() {
console.log("🔄 Seeding Posyandu...");
for (const p of posyanduJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for posyandu "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.posyandu.upsert({
where: { id: p.id },
update: {
name: p.name,
nomor: p.nomor,
deskripsi: p.deskripsi,
jadwalPelayanan: p.jadwalPelayanan,
imageId,
},
create: {
id: p.id,
name: p.name,
nomor: p.nomor,
deskripsi: p.deskripsi,
jadwalPelayanan: p.jadwalPelayanan,
imageId,
},
});
console.log(`✅ Posyandu seeded: ${p.name}`);
}
console.log("🎉 Posyandu seed selesai");
}

View File

@@ -0,0 +1,42 @@
import prisma from "@/lib/prisma";
import programKesehatanJson from "../../../data/kesehatan/program-kesehatan/program-kesehatan.json";
export async function seedProgramKesehatan() {
for (const p of programKesehatanJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for program kesehatan "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.programKesehatan.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsiSingkat: p.deskripsiSingkat,
deskripsi: p.deskripsi,
imageId,
},
create: {
id: p.id,
name: p.name,
deskripsiSingkat: p.deskripsiSingkat,
deskripsi: p.deskripsi,
imageId,
},
});
console.log(`✅ Program kesehatan seeded: ${p.name}`);
}
}

View File

@@ -0,0 +1,95 @@
import prisma from "@/lib/prisma";
import puskesmasJson from "../../../data/kesehatan/puskesmas/puskesmas.json";
import kontakPuskesmasJson from "../../../data/kesehatan/puskesmas/kontak-puskesmas/kontak.json";
import jamPuskesmasJson from "../../../data/kesehatan/puskesmas/jam-puskesmas/jam.json";
export async function seedPuskesmas() {
console.log("🔄 Seeding Kontak Puskesmas...");
for (const k of kontakPuskesmasJson) {
await prisma.kontakPuskesmas.upsert({
where: {
id: k.id,
},
update: {
kontakPuskesmas: k.kontakPuskesmas,
email: k.email,
facebook: k.facebook,
kontakUGD: k.kontakUGD,
},
create: {
id: k.id,
kontakPuskesmas: k.kontakPuskesmas,
email: k.email,
facebook: k.facebook,
kontakUGD: k.kontakUGD,
},
});
}
console.log("kontak puskesmas success ...");
console.log("🔄 Seeding Jam Puskesmas...");
for (const k of jamPuskesmasJson) {
await prisma.jamOperasional.upsert({
where: {
id: k.id,
},
update: {
workDays: k.workDays,
weekDays: k.weekDays,
holiday: k.holiday,
},
create: {
id: k.id,
workDays: k.workDays,
weekDays: k.weekDays,
holiday: k.holiday,
},
});
}
console.log("jam puskesmas success ...");
console.log("🔄 Seeding Puskesmas...");
for (const p of puskesmasJson) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for puskesmas "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.puskesmas.upsert({
where: { id: p.id },
update: {
name: p.name,
alamat: p.alamat,
jamId: p.jamId,
kontakId: p.kontakId,
imageId,
},
create: {
id: p.id,
name: p.name,
alamat: p.alamat,
jamId: p.jamId,
kontakId: p.kontakId,
imageId,
},
});
console.log(`✅ Puskesmas seeded: ${p.name}`);
}
console.log("🎉 Puskesmas seed selesai");
}

View File

@@ -0,0 +1,38 @@
import prisma from "@/lib/prisma";
import kategoriDesaAntiKorupsi from "../../../data/landing-page/desa-anti-korupsi/kategoriDesaAntiKorupsi.json"
import desaAntiKorupsi from "../../../data/landing-page/desa-anti-korupsi/desaantiKorpusi.json"
export async function seedDesaAntiKorupsi() {
for (const k of kategoriDesaAntiKorupsi) {
await prisma.kategoriDesaAntiKorupsi.upsert({
where: { id: k.id },
update: {
name: k.name,
},
create: {
id: k.id,
name: k.name,
},
});
}
console.log("kategori desa anti korupsi success ...");
// =========== DESA ANTI KORUPSI ===========
for (const p of desaAntiKorupsi) {
await prisma.desaAntiKorupsi.upsert({
where: { id: p.id },
update: {
name: p.name,
deskripsi: p.deskripsi,
kategoriId: p.kategoriId,
},
create: {
id: p.id,
name: p.name,
deskripsi: p.deskripsi,
kategoriId: p.kategoriId,
},
});
}
console.log("desa anti korupsi success ...");
}

View File

@@ -0,0 +1,61 @@
import prisma from "@/lib/prisma";
import prestasiDesa from "../../../data/landing-page/prestasi-desa/prestasi-desa.json"
import kategoriPrestasiDesa from "../../../data/landing-page/prestasi-desa/kategori-prestasi.json"
export async function seedPrestasiDesa() {
console.log("🔄 Seeding Kategori Prestasi Desa...");
for (const c of kategoriPrestasiDesa) {
await prisma.kategoriPrestasiDesa.upsert({
where: { id: c.id },
update: {
name: c.name,
},
create: {
id: c.id,
name: c.name,
},
});
}
console.log("kategori prestasi desa success ...");
console.log("🔄 Seeding Prestasi Desa...");
for (const m of prestasiDesa) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for prestasi desa "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.prestasiDesa.upsert({
where: { id: m.id },
update: {
name: m.name,
deskripsi: m.deskripsi,
kategoriId: m.kategoriId,
imageId,
},
create: {
id: m.id,
name: m.name,
deskripsi: m.deskripsi,
kategoriId: m.kategoriId,
imageId,
},
});
}
console.log("prestasi desa success ...");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import mediaSosial from "../../../data/landing-page/profile/mediaSosial.json"
export async function seedMediaSosial() {
console.log("🔄 Seeding Media Sosial...");
for (const m of mediaSosial) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for berita "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.mediaSosial.upsert({
where: { id: m.id },
update: {
name: m.name,
iconUrl: m.iconUrl,
imageId,
},
create: {
id: m.id,
name: m.name,
iconUrl: m.iconUrl,
imageId,
},
});
}
console.log("media sosial success ...");
}

View File

@@ -0,0 +1,40 @@
import prisma from "@/lib/prisma";
import profilePejabatDesa from "../../../data/landing-page/profile/profile.json";
export async function seedProfileLP() {
console.log("🔄 Seeding Pejabat Desa...");
for (const p of profilePejabatDesa) {
let imageId: string | null = null;
if (p.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: p.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for profile "${p.name}": ${p.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.pejabatDesa.upsert({
where: { id: p.id },
update: {
name: p.name,
position: p.position,
imageId,
},
create: {
id: p.id,
name: p.name,
position: p.position,
imageId,
},
});
}
console.log("✅ Pejabat Desa seeding completed");
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma";
import programInovasi from "../../../data/landing-page/profile/programInovasi.json";
export async function seedProgramInovasi() {
console.log("🔄 Seeding Program Inovasi...");
for (const b of programInovasi) {
let imageId: string | null = null;
if (b.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: b.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for program inovasi "${b.name}": ${b.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.programInovasi.upsert({
where: { id: b.id },
update: {
name: b.name,
description: b.description,
link: b.link,
imageId,
},
create: {
id: b.id,
name: b.name,
description: b.description,
link: b.link,
imageId,
},
});
console.log(`✅ Program Inovasi seeded: ${b.name}`);
}
}

View File

@@ -0,0 +1,41 @@
import prisma from "@/lib/prisma";
import sdgsDesa from "../../../data/landing-page/sdgs-desa/sdgs-desa.json";
export async function seedSDGSDesa() {
console.log("🔄 Seeding SDGS Desa...");
for (const m of sdgsDesa) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for sdgs desa "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.sdgsDesa.upsert({
where: { id: m.id },
update: {
name: m.name,
jumlah: m.jumlah,
imageId,
},
create: {
id: m.id,
name: m.name,
jumlah: m.jumlah,
imageId,
},
});
}
console.log("sdgs desa success ...");
}

View File

@@ -0,0 +1,71 @@
import prisma from "@/lib/prisma";
import kategoriGotongRoyong from "../../data/lingkungan/gotong-royong/kategori-gotong-royong.json";
import gotongRoyong from "../../data/lingkungan/gotong-royong/gotong-royong.json";
export async function seedDataGotongRoyong() {
console.log("🔄 Seeding Kategori Gotong Royong...");
for (const k of kategoriGotongRoyong) {
await prisma.kategoriKegiatan.upsert({
where: {
id: k.id,
},
update: {
nama: k.nama,
},
create: {
id: k.id,
nama: k.nama,
},
});
}
console.log("✅ Kategori Gotong Royong seeded successfully");
console.log("🔄 Seeding Gotong Royong...");
for (const k of gotongRoyong) {
let imageId: string | null = null;
if (k.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: k.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for gotong royong "${k.judul}": ${k.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.kegiatanDesa.upsert({
where: {
id: k.id,
},
update: {
judul: k.judul,
deskripsiSingkat: k.deskripsiSingkat,
deskripsiLengkap: k.deskripsiLengkap,
tanggal: k.tanggal,
lokasi: k.lokasi,
partisipan: k.partisipan,
imageId: imageId,
kategoriKegiatanId: k.kategoriKegiatanId,
},
create: {
id: k.id,
judul: k.judul,
deskripsiSingkat: k.deskripsiSingkat,
deskripsiLengkap: k.deskripsiLengkap,
tanggal: k.tanggal,
lokasi: k.lokasi,
partisipan: k.partisipan,
imageId: imageId,
kategoriKegiatanId: k.kategoriKegiatanId,
},
});
}
console.log("✅ Gotong Royong seeded successfully");
}

View File

@@ -0,0 +1,27 @@
import prisma from "@/lib/prisma";
import dataLingkunganDesa from "../../data/lingkungan/data-lingkungan-desa/data-lingkungan-desa.json";
export async function seedDataLingkunganDesa() {
console.log("🔄 Seeding Data Lingkungan Desa...");
for (const p of dataLingkunganDesa) {
await prisma.dataLingkunganDesa.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
jumlah: p.jumlah,
deskripsi: p.deskripsi,
icon: p.icon,
},
create: {
id: p.id,
name: p.name,
jumlah: p.jumlah,
deskripsi: p.deskripsi,
icon: p.icon,
},
});
}
console.log("✅ Data Lingkungan Desa seeded successfully");
}

View File

@@ -0,0 +1,63 @@
import prisma from "@/lib/prisma";
import tujuanEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
import materiEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
import contohEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
export async function seedEdukasiLingkungan() {
for (const e of tujuanEdukasiLingkungan) {
await prisma.tujuanEdukasiLingkungan.upsert({
where: {
id: e.id,
},
update: {
judul: e.judul,
deskripsi: e.deskripsi,
},
create: {
id: e.id,
judul: e.judul,
deskripsi: e.deskripsi,
},
});
}
console.log("tujuan edukasi lingkungan success ...");
for (const m of materiEdukasiLingkungan) {
await prisma.materiEdukasiLingkungan.upsert({
where: {
id: m.id,
},
update: {
judul: m.judul,
deskripsi: m.deskripsi,
},
create: {
id: m.id,
judul: m.judul,
deskripsi: m.deskripsi,
},
});
}
console.log("materi edukasi lingkungan success ...");
for (const c of contohEdukasiLingkungan) {
await prisma.contohEdukasiLingkungan.upsert({
where: {
id: c.id,
},
update: {
judul: c.judul,
deskripsi: c.deskripsi,
},
create: {
id: c.id,
judul: c.judul,
deskripsi: c.deskripsi,
},
});
}
console.log("contoh edukasi lingkungan success ...");
}

View File

@@ -0,0 +1,63 @@
import prisma from "@/lib/prisma";
import filosofiTriHita from "../../data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
import bentukKonservasiBerdasarkanAdat from "../../data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
import nilaiKonservasiAdat from "../../data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
export async function seedKonservasiAdatBali() {
for (const f of filosofiTriHita) {
await prisma.filosofiTriHita.upsert({
where: {
id: f.id,
},
update: {
judul: f.judul,
deskripsi: f.deskripsi,
},
create: {
id: f.id,
judul: f.judul,
deskripsi: f.deskripsi,
},
});
}
console.log("filosofi tri hita success ...");
for (const b of bentukKonservasiBerdasarkanAdat) {
await prisma.bentukKonservasiBerdasarkanAdat.upsert({
where: {
id: b.id,
},
update: {
judul: b.judul,
deskripsi: b.deskripsi,
},
create: {
id: b.id,
judul: b.judul,
deskripsi: b.deskripsi,
},
});
}
console.log("bentuk konservasi berdasarkan adat success ...");
for (const n of nilaiKonservasiAdat) {
await prisma.nilaiKonservasiAdat.upsert({
where: {
id: n.id,
},
update: {
judul: n.judul,
deskripsi: n.deskripsi,
},
create: {
id: n.id,
judul: n.judul,
deskripsi: n.deskripsi,
},
});
}
console.log("nilai konservasi adat success ...");
}

View File

@@ -0,0 +1,51 @@
import prisma from "@/lib/prisma";
import pengelolaanSampah from "../../data/lingkungan/pengelolaan-sampah/pengelolaan-sampah.json";
import keteranganBankSampah from "../../data/lingkungan/pengelolaan-sampah/keterangan-bank-sampah.json";
export async function seedPengelolaanSampah() {
console.log("🔄 Seeding Pengelolaan Sampah...");
for (const p of pengelolaanSampah) {
await prisma.pengelolaanSampah.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
icon: p.icon,
},
create: {
id: p.id,
name: p.name,
icon: p.icon,
},
});
}
console.log("✅ Pengelolaan Sampah seeded successfully");
console.log("🔄 Seeding Keterangan Bank Sampah...");
for (const p of keteranganBankSampah) {
await prisma.keteranganBankSampahTerdekat.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
alamat: p.alamat,
namaTempatMaps: p.namaTempatMaps,
linkPetunjukArah: p.linkPetunjukArah,
lat: p.lat,
lng: p.lng,
},
create: {
id: p.id,
name: p.name,
alamat: p.alamat,
namaTempatMaps: p.namaTempatMaps,
linkPetunjukArah: p.linkPetunjukArah,
lat: p.lat,
lng: p.lng,
},
});
}
console.log("✅ Keterangan Bank Sampah seeded successfully");
}

View File

@@ -0,0 +1,27 @@
import prisma from "@/lib/prisma";
import programPenghijauan from "../../data/lingkungan/program-penghijauan/program-penghijauan.json";
export async function seedProgramPenghijauan() {
console.log("🔄 Seeding Program Penghijauan...");
for (const p of programPenghijauan) {
await prisma.programPenghijauan.upsert({
where: {
id: p.id,
},
update: {
name: p.name,
judul: p.judul,
deskripsi: p.deskripsi,
icon: p.icon,
},
create: {
id: p.id,
name: p.name,
judul: p.judul,
deskripsi: p.deskripsi,
icon: p.icon,
},
});
}
console.log("✅ Program Penghijauan seeded successfully");
}

View File

@@ -0,0 +1,60 @@
import prisma from "@/lib/prisma";
import tujuanBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
import lokasiJadwalBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
import fasilitasBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
export async function seedBimbinganBelajar() {
for (const t of tujuanBimbinganBelajarDesa) {
await prisma.tujuanBimbinganBelajarDesa.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ tujuan bimbingan belajar desa seeded (editable later via UI)",
);
for (const t of lokasiJadwalBimbinganBelajarDesa) {
await prisma.lokasiJadwalBimbinganBelajarDesa.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)",
);
for (const t of fasilitasBimbinganBelajarDesa) {
await prisma.fasilitasBimbinganBelajarDesa.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
);
}

View File

@@ -0,0 +1,23 @@
import prisma from "@/lib/prisma";
import dataPendidikan from "../../data/pendidikan/data-pendidikan/data-pendidikan.json";
export async function seedDataPendidikan() {
console.log("🔄 Seeding Data pendidikan...");
for (const k of dataPendidikan) {
await prisma.dataPendidikan.upsert({
where: {
id: k.id,
},
update: {
name: k.name,
jumlah: k.jumlah,
},
create: {
id: k.id,
name: k.name,
jumlah: k.jumlah,
},
});
}
console.log("✅ Data pendidikan seeded successfully");
}

View File

@@ -0,0 +1,71 @@
import prisma from "@/lib/prisma";
import dataPerpustakaan from "../../data/pendidikan/perpustakaan-digital/perpustakaan-digital.json";
import kategoriBuku from "../../data/pendidikan/perpustakaan-digital/kategori-buku.json";
export async function seedDataPerpustakaan() {
console.log("🔄 Seeding Kategori Buku...");
for (const k of kategoriBuku) {
await prisma.kategoriBuku.upsert({
where: {
id: k.id,
},
update: {
name: k.name,
},
create: {
id: k.id,
name: k.name,
},
});
}
console.log("✅ Kategori Buku seeded successfully");
console.log("🔄 Seeding Data perpustakaan...");
for (const k of dataPerpustakaan) {
let imageId: string | null = null;
if (k.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: k.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for perpustakaan "${k.judul}": ${k.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.dataPerpustakaan.upsert({
where: {
id: k.id,
},
update: {
judul: k.judul,
deskripsi: k.deskripsi,
kategoriId: k.kategoriId,
imageId: imageId
},
create: {
id: k.id,
judul: k.judul,
deskripsi: k.deskripsi,
kategoriId: k.kategoriId,
imageId: imageId
},
});
}
console.log("✅ Data perpustakaan seeded successfully");
}
if (import.meta.main) {
seedDataPerpustakaan()
.then(() => {
console.log("seed data perpustakaan success");
})
.catch((err) => {
console.log("gagal seed data perpustakaan", JSON.stringify(err));
});
}

View File

@@ -0,0 +1,36 @@
import prisma from "@/lib/prisma";
import tujuanProgram from "../../data/pendidikan/program-pendidikan-anak/tujuan-program.json";
import programUnggulan from "../../data/pendidikan/program-pendidikan-anak/program-unggulan.json";
export async function seedInfoProgramPendidikan() {
for (const t of tujuanProgram) {
await prisma.tujuanProgram.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log("✅ tujuan program seeded (editable later via UI)");
for (const t of programUnggulan) {
await prisma.programUnggulan.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log("✅ program unggulan seeded (editable later via UI)");
}

View File

@@ -0,0 +1,74 @@
import prisma from "@/lib/prisma";
import jenjangPendidikan from "../../data/pendidikan/info-sekolah/jenjang-pendidikan.json";
import lembagaPendidikan from "../../data/pendidikan/info-sekolah/lembaga.json";
import siswa from "../../data/pendidikan/info-sekolah/siswa.json";
import pengajar from "../../data/pendidikan/info-sekolah/pengajar.json";
export async function seedInfoSekolah() {
for (const j of jenjangPendidikan) {
await prisma.jenjangPendidikan.upsert({
where: {
id: j.id,
},
update: {
nama: j.nama,
},
create: {
id: j.id,
nama: j.nama,
},
});
}
console.log("✅ Jenjang Pendidikan seeded successfully");
for (const j of lembagaPendidikan) {
await prisma.lembaga.upsert({
where: {
id: j.id,
},
update: {
nama: j.nama,
jenjangId: j.jenjangId,
},
create: {
id: j.id,
nama: j.nama,
jenjangId: j.jenjangId,
},
});
}
console.log("✅ Lembaga Pendidikan seeded successfully");
for (const j of siswa) {
await prisma.siswa.upsert({
where: {
id: j.id,
},
update: {
nama: j.nama,
lembagaId: j.lembagaId,
},
create: {
id: j.id,
nama: j.nama,
lembagaId: j.lembagaId,
},
});
}
console.log("✅ siswa seeded successfully");
for (const j of pengajar) {
await prisma.pengajar.upsert({
where: {
id: j.id,
},
update: {
nama: j.nama,
lembagaId: j.lembagaId,
},
create: {
id: j.id,
nama: j.nama,
lembagaId: j.lembagaId,
},
});
}
console.log("✅ pengajar seeded successfully");
}

View File

@@ -0,0 +1,60 @@
import prisma from "@/lib/prisma";
import tujuanProgram from "../../data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
import tempatKegiatan from "../../data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
import jenisProgramYangDiselenggarakan from "../../data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
export async function seedPendidikanNonFormal() {
for (const t of tujuanProgram) {
await prisma.tujuanPendidikanNonFormal.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
);
for (const t of tempatKegiatan) {
await prisma.tempatKegiatan.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
);
for (const t of jenisProgramYangDiselenggarakan) {
await prisma.jenisProgramYangDiselenggarakan.upsert({
where: { id: t.id },
update: {
judul: t.judul,
deskripsi: t.deskripsi,
},
create: {
id: t.id,
judul: t.judul,
deskripsi: t.deskripsi,
},
});
}
console.log(
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
);
}

View File

@@ -0,0 +1,76 @@
import prisma from "@/lib/prisma";
import daftarInformasiPublik from "../../../data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json"
import jenisInformasiDiminta from "../../../data/list-jenisInfromasi.json"
import caraMemperolehInformasi from "../../../data/list-caraMemperolehInformasi.json"
import caraMemperolehSalinanInformasi from "../../../data/list-caraMemperolehSalinanInformasi.json"
export async function seedDaftarInformasiPublikPpid() {
for (const v of daftarInformasiPublik) {
// Convert string date to Date object
const tanggal = new Date(v.tanggal);
await prisma.daftarInformasiPublik.upsert({
where: {
id: v.id,
},
update: {
jenisInformasi: v.jenisInformasi,
deskripsi: v.deskripsi,
tanggal: tanggal,
},
create: {
id: v.id,
jenisInformasi: v.jenisInformasi,
deskripsi: v.deskripsi,
tanggal: tanggal,
},
});
}
console.log("daftar informasi publik PPID success ...");
for (const j of jenisInformasiDiminta) {
await prisma.jenisInformasiDiminta.upsert({
where: {
name: j.name,
},
update: {
name: j.name,
},
create: {
name: j.name,
},
});
}
console.log("jenis informasi diminta success ...");
for (const c of caraMemperolehInformasi) {
await prisma.caraMemperolehInformasi.upsert({
where: {
name: c.name,
},
update: {
name: c.name,
},
create: {
name: c.name,
},
});
}
console.log("cara memperoleh informasi success ...");
for (const c of caraMemperolehSalinanInformasi) {
await prisma.caraMemperolehSalinanInformasi.upsert({
where: {
name: c.name,
},
update: {
name: c.name,
},
create: {
name: c.name,
},
});
}
console.log("cara memperoleh salinan informasi success ...");
}

View File

@@ -0,0 +1,22 @@
import prisma from "@/lib/prisma";
import dasarHukumPPID from "../../../data/ppid/dasar-hukum-ppid/dasarhukumPPID.json"
export async function seedDasarHukumPpid() {
for (const v of dasarHukumPPID) {
await prisma.dasarHukumPPID.upsert({
where: {
id: v.id,
},
update: {
judul: v.judul,
content: v.content,
},
create: {
id: v.id,
judul: v.judul,
content: v.content,
},
});
}
console.log("dasar hukum PPID success ...");
}

View File

@@ -0,0 +1,54 @@
import prisma from "@/lib/prisma";
import jenisKelamin from "../../../data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
import pilihanRatingResponden from "../../../data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
import umurResponden from "../../../data/ppid/ikm/umur-responden/umur-responden.json";
export async function seedIkmPpid() {
for (const j of jenisKelamin) {
await prisma.jenisKelaminResponden.upsert({
where: {
id: j.id,
},
update: {
name: j.name,
},
create: {
id: j.id,
name: j.name,
},
});
}
console.log("jenis kelamin responden success ...");
for (const r of pilihanRatingResponden) {
await prisma.pilihanRatingResponden.upsert({
where: {
id: r.id,
},
update: {
name: r.name,
},
create: {
id: r.id,
name: r.name,
},
});
}
console.log("pilihan rating responden success ...");
for (const u of umurResponden) {
await prisma.umurResponden.upsert({
where: {
id: u.id,
},
update: {
name: u.name,
},
create: {
id: u.id,
name: u.name,
},
});
}
console.log("umur responden success ...");
}

View File

@@ -0,0 +1,48 @@
import prisma from "@/lib/prisma";
import profilPpd from "../../../data/ppid/profile-ppid/profilePPid.json"
export async function seedProfilPpd() {
console.log("🔄 Seeding Profil PPD...");
for (const m of profilPpd) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for berita "${m.name}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.profilePPID.upsert({
where: { id: m.id },
update: {
name: m.name,
biodata: m.biodata,
riwayat: m.riwayat,
pengalaman: m.pengalaman,
unggulan: m.unggulan,
imageId,
},
create: {
id: m.id,
name: m.name,
biodata: m.biodata,
riwayat: m.riwayat,
pengalaman: m.pengalaman,
unggulan: m.unggulan,
imageId,
},
});
}
console.log("profil ppd success ...");
}

View File

@@ -0,0 +1,82 @@
import prisma from "@/lib/prisma";
import pegawaiPpid from "../../../data/ppid/struktur-ppid/pegawai-PPID.json"
import posisiOrganisasiPPID from "../../../data/ppid/struktur-ppid/posisi-organisasi-PPID.json"
export async function seedPegawaiPpid() {
const flattenedPosisi = posisiOrganisasiPPID.flat();
// ✅ Urutkan berdasarkan hierarki
const sortedPosisi = flattenedPosisi.sort((a, b) => a.hierarki - b.hierarki);
for (const p of sortedPosisi) {
console.log(`Seeding: ${p.nama} (id: ${p.id}, parent: ${p.parentId})`);
if (p.parentId) {
const parentExists = flattenedPosisi.some((pos) => pos.id === p.parentId);
if (!parentExists) {
console.warn(
`⚠️ Parent tidak ditemukan: ${p.parentId} untuk ${p.nama}`,
);
continue;
}
}
await prisma.posisiOrganisasiPPID.upsert({
where: { id: p.id },
update: p,
create: p,
});
}
console.log("posisi organisasi berhasil");
console.log("🔄 Seeding Struktur Ppid...");
for (const m of pegawaiPpid) {
let imageId: string | null = null;
if (m.imageName) {
const image = await prisma.fileStorage.findUnique({
where: { name: m.imageName },
select: { id: true },
});
if (!image) {
console.warn(
`⚠️ Image not found for pegawai ppid "${m.namaLengkap}": ${m.imageName}`,
);
} else {
imageId = image.id;
}
}
await prisma.pegawaiPPID.upsert({
where: { id: m.id },
update: {
namaLengkap: m.namaLengkap,
gelarAkademik: m.gelarAkademik,
tanggalMasuk: m.tanggalMasuk,
email: m.email,
telepon: m.telepon,
alamat: m.alamat,
imageId,
posisiId: m.posisiId,
isActive: m.isActive,
},
create: {
id: m.id,
namaLengkap: m.namaLengkap,
gelarAkademik: m.gelarAkademik,
tanggalMasuk: m.tanggalMasuk,
email: m.email,
telepon: m.telepon,
alamat: m.alamat,
imageId,
posisiId: m.posisiId,
isActive: m.isActive,
},
});
}
console.log("struktur ppid success ...");
}

View File

@@ -0,0 +1,23 @@
import prisma from "@/lib/prisma";
import visiMisiPPID from "../../../data/ppid/visi-misi-ppid/visimisiPPID.json"
export async function seedVisiMisiPpid() {
for (const v of visiMisiPPID) {
await prisma.visiMisiPPID.upsert({
where: {
id: v.id,
},
update: {
misi: v.misi,
visi: v.visi,
},
create: {
id: v.id,
misi: v.misi,
visi: v.visi,
},
});
}
console.log("visi misi PPID success ...");
}

View File

@@ -1,8 +0,0 @@
[
{ "name": "Sosial & Kesehatan" },
{ "name": "Ekonomi & UMKM" },
{ "name": "Pendidikan & Kepemudaan" },
{ "name": "Lingkungan & Bencana" },
{ "name": "Adat & Budaya" },
{ "name": "Digitalisasi Desa" }
]

View File

@@ -0,0 +1,146 @@
[
{
"id": "cmk6ae8rz00003b6r06x7hsqi",
"judul": "TP. Posyandu Bali Gelar Aksi Sosial Membina dan Berbagi di Desa Darmasaba",
"deskripsi": "<p>Kegiatan pembinaan dan bantuan kepada kader Posyandu Desa Darmasaba oleh TP Posyandu Provinsi Bali.</p>",
"content": "<p>Sebanyak 50 kader posyandu mendapatkan pembinaan dan sembako sebagai dukungan terhadap peran Posyandu dalam pemberdayaan masyarakat. Kegiatan ini menunjukkan peran strategis posyandu dalam layanan publik desa.</p>",
"kategoriBeritaId": "cmk69tghy000vvnv8xeouenv5",
"imageName": "Wp41ccw3yma9W8i6zBr6E-mobile.webp"
},
{
"id": "cmk6af7vf00013b6rj2br4nv8",
"judul": "Desa Darmasaba Gelar Temu Sadar Hukum, Bahas Isu KDRT",
"deskripsi": "<p>Temu Sadar Hukum untuk meningkatkan kesadaran hukum warga Desa Darmasaba.</p>",
"content": "<p>Kegiatan ini membahas isu kekerasan dalam rumah tangga dengan narasumber dari Kanwil Kemenkum Bali, menjadi forum penting dalam membangun masyarakat yang melek hukum.</p>",
"kategoriBeritaId": "cmk69tghy000vvnv8xeouenv5",
"imageName": "IwedNmhjD_wGpY6PvYX7W-mobile.webp"
},
{
"id": "cmk6afo0g00033b6rjc2pae67",
"judul": "Bicara Darmasaba Bahas Berbagai Persoalan, Dorong Warga Sampaikan Aspirasi",
"deskripsi": "<p>Ruang dialog terbuka di Desa Darmasaba untuk membahas persoalan sampah dan partisipasi publik.</p>",
"content": "<p>Forum dialog ini membantu pemerintahan desa menyusun kebijakan tepat sasaran, terutama terkait permasalahan lingkungan dan aspirasi warga.</p>",
"kategoriBeritaId": "cmk69tghy000vvnv8xeouenv5",
"imageName": "EVkMxPdoWyL3y31L7d7x1-mobile.webp"
},
{
"id": "cmk6ag56y00053b6rj9481z6m",
"judul": "Bicara Darmasaba Bahas Sampah Kita, Tanggung Jawab Siapa?",
"deskripsi": "<p>Diskusi terbuka antara pemerintah desa dan warga mengenai isu sampah.</p>",
"content": "<p>Acara ini mendukung perumusan kebijakan desa yang sesuai kebutuhan warga dan meningkatkan partisipasi dalam pembangunan lingkungan.</p>",
"kategoriBeritaId": "cmk69tghx000tvnv8g2d206wv",
"imageName": "c_5xOKUbMiD8dTAbkAv9a-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxcsj",
"judul": "Penutupan KKN-PMM Periode II Universitas Warmadewa di Desa Darmasaba",
"deskripsi": "<p>Penutupan program KKN-PMM yang berjalan dengan berbagai kegiatan pemberdayaan masyarakat.</p>",
"content": "<p>Kegiatan KKN meliputi edukasi kesehatan, pengelolaan sampah, literasi keuangan, dan upaya ekonomi lokal sebagai bagian dari pembangunan desa berkelanjutan.</p>",
"kategoriBeritaId": "cmk69tghx000tvnv8g2d206wv",
"imageName": "I9CDBqdeDXRbbzbPWhy6h-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxasj",
"judul": "Desa Darmasaba Siap Kelola Sampah Mandiri, Anggarkan Rp1,5 Miliar",
"deskripsi": "<p>Desa Darmasaba mengalokasikan anggaran untuk pengelolaan sampah berbasis komunitas.</p>",
"content": "<p>Pengelolaan sampah mandiri melalui TPS3R, kader penyuluh, dan inovasi CINtA menjadi strategi desa dalam penanganan sampah sesuai kebijakan provinsi dan desa.</p>",
"kategoriBeritaId": "cmk69tghx000tvnv8g2d206wv",
"imageName": "Gq-gEDaGNb-FkKasVs7i4-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxbsj",
"judul": "Sekda Adi Arnawa Buka Darmasaba Village Festival II",
"deskripsi": "<p>Pembukaan festival desa untuk mendorong UMKM dan ekonomi lokal.</p>",
"content": "<p>Kegiatan ini menampilkan berbagai UMKM yang membantu meningkatkan pendapatan masyarakat setempat.</p>",
"kategoriBeritaId": "cmk69tghx000uvnv847ppcxqh",
"imageName": "TymQ5xDH7vEUOA9BY63hr-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxdsj",
"judul": "Membangun Desa Berkelanjutan Melalui Ekowisata dan Kuliner di Darmasaba",
"deskripsi": "<p>Program inovatif untuk memperkuat ekonomi lokal melalui ekowisata dan kuliner.</p>",
"content": "<p>Kegiatan mencakup pembangunan green house, edukasi pemasaran digital, literasi bahasa Inggris, dan pengembangan potensi kuliner desa.</p>",
"kategoriBeritaId": "cmk69tghx000uvnv847ppcxqh",
"imageName": "2nUvEBsMuigIJQWZIdcEJ-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxesj",
"judul": "Inovasi Desa Darmasaba Lanjutkan Perjuangan ke Tingkat Nasional",
"deskripsi": "<p>Desa Darmasaba meraih penghargaan juara dalam evaluasi perkembangan desa untuk mendukung perekonomian dan pemerintahan lokal.</p>",
"content": "<p>Prestasi desa ditandai dengan keberhasilan dalam lomba evaluasi perkembangan desa di tingkat provinsi dan kabupaten, yang berdampak positif pada ekonomi desa.</p>",
"kategoriBeritaId": "cmk69tghx000uvnv847ppcxqh",
"imageName": "Hokgum3-nI_NWTWJRnWi3-mobile.webp"
},
{
"id": "cmk6agzxx00073b6rr3vhxfsj",
"judul": "Desa Darmasaba Kembali Ukir Prestasi Internasional BAJRA",
"deskripsi": "<p>Prestasi desa dalam forum internasional mengenai penanggulangan rabies.</p>",
"content": "<p>Partisipasi dalam konferensi Rabies in Borneo menunjukkan kolaborasi lintas sektor dan penggunaan data dalam pelayanan publik desa.</p>",
"kategoriBeritaId": "cmk69tght000svnv8ok5rid2v",
"imageName": "T1fcksUoZSUqNMbzvr9WI-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp1z",
"judul": "Cegah Penyebaran Rabies, Darmasaba Keluarkan Larangan Membuang Hewan",
"deskripsi": "<p>Pemasangan spanduk larangan buang hewan sebagai langkah proteksi kesehatan masyarakat.</p>",
"content": "<p>Pemerintah desa bersama Tim Bajra aktif dalam kampanye dan regulasi untuk mencegah rabies di tingkat desa.</p>",
"kategoriBeritaId": "cmk69tght000svnv8ok5rid2v",
"imageName": "-M_tICRVz6ZxOfvkuHQgU-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp2z",
"judul": "TP. Posyandu Bali dan Pemerintah Desa Kolaborasi Tingkatkan Pelayanan",
"deskripsi": "<p>Kolaborasi pemerintahan desa dengan TP Posyandu untuk meningkatkan layanan masyarakat.</p>",
"content": "<p>Kegiatan ini menunjukkan peran pemerintahan desa dalam mendukung layanan kesehatan dan pemberdayaan masyarakat.</p>",
"kategoriBeritaId": "cmk69tght000svnv8ok5rid2v",
"imageName": "O11hmN9oNwFKs_ACpH9uV-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp3z",
"judul": "Membangun Desa Berkelanjutan Melalui Inovasi Pengelolaan Sampah",
"deskripsi": "<p>Inisiatif pengelolaan sampah desa sebagai bagian dari inovasi teknologi lokal.</p>",
"content": "<p>Penerapan metode pengelolaan sampah dan biopori menunjukkan upaya Desa Darmasaba dalam menggunakan solusi teknologi sederhana untuk masalah lingkungan.</p>",
"kategoriBeritaId": "cmk69tghz000xvnv8kxzzt24h",
"imageName": "rrgHHUYHDuq3jW94HCRsq-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp4z",
"judul": "Inovasi BAJRA Integrasikan Pelaporan Cepat Berbasis Data",
"deskripsi": "<p>Program BAJRA menerapkan mekanisme pelaporan cepat berbasis data untuk penanggulangan rabies.</p>",
"content": "<p>Penggunaan teknologi informasi dalam pelaporan kasus rabies membantu respons cepat pemerintahan desa dan komunitas.</p>",
"kategoriBeritaId": "cmk69tghz000xvnv8kxzzt24h",
"imageName": "igz0V0MCoLYqAgLIBRZdG-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp5z",
"judul": "Digitalisasi Desa Darmasaba",
"deskripsi": "<p>Digitalisasi Desa Darmasaba Bersama PT. Bali Interaktif Perkasa.</p>",
"content": "<p>Digitalisasi Desa Darmasaba Bersama PT. Bali Interaktif Perkasa<br><br>Dalam rangka mendukung transformasi digital dan inovasi desa, Desa Darmasaba bekerja sama dengan PT. Bali Interaktif Perkasa melaksanakan kegiatan Digitalisasi Desa.<br><br>Program ini bertujuan untuk memperkuat kapasitas desa dalam pemanfaatan teknologi informasi dan komunikasi, sehingga pelayanan publik menjadi lebih efektif, transparan, dan cepat. Masyarakat juga diberikan pemahaman terkait pemanfaatan platform digital untuk kegiatan administrasi, komunikasi, dan pengembangan potensi desa.<br><br>Kegiatan digitalisasi ini menjadi bagian dari komitmen Desa Darmasaba untuk mewujudkan desa cerdas (smart village) yang mampu bersaing dan beradaptasi di era digital, sekaligus meningkatkan inovasi dan pemberdayaan masyarakat.<br><br>Dengan kolaborasi ini, Desa Darmasaba menegaskan tekadnya untuk terus berinovasi, menghadirkan kemudahan bagi masyarakat, dan memperkuat tata kelola desa berbasis teknologi modern.<br><br>? Digitalisasi hari ini, kemajuan desa esok!<br><br>#DesaDarmasaba #DigitalisasiDesa #DesaCerdas #InovasiDesa #TransformasiDigital<br>#PemdesDarmasaba<br>#PerbekelDarmasaba<br>#DesaDarmasaba<br> #KitaDarmasaba<br> #DarmasabaBisa<br> <br> @kostergubernurbali<br> @giri.prasta<br> @iwayanadiarnawa<br> @gus.bota<br> @puturasniathiadiarnawa<br> @yunita_oktarini<br> @surya.suamba<br> @budhi.argawakba<br> @pemkabbadung<br> @ppidbadung<br> @dinaspmddukcapilprovbali<br> @surya_prabhawa<br> @kecamatanabiansemal<br> @dpmdbadungkab<br> @pemprov_bali<br> @prokompimbadung<br> @seputar_darmasaba</p>",
"kategoriBeritaId": "cmk69tghz000xvnv8kxzzt24h",
"imageName": "DzVIfpiAP3OcCsZ_VJ02b-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp6z",
"judul": "Festival Desa Tingkatkan Kreativitas Digital UMKM",
"deskripsi": "<p>Festival Darmasaba Village Festival II melibatkan promosi digital produk UMKM.</p>",
"content": "<p>Promosi dan dokumentasi digital menjadi bagian dari strategi pemasaran UMKM dalam festival desa.</p>",
"kategoriBeritaId": "cmk69tghy000wvnv8umg2vloa",
"imageName": "xzM77A6bDW2silyp_8W7n-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp7z",
"judul": "Sekda Adi Arnawa dan Pementasan Seni Tradisional di Festival Darmasaba",
"deskripsi": "<p>Pementasan seni tradisional menjadi bagian dari Darmasaba Village Festival II.</p>",
"content": "<p>Kegiatan ini mengangkat warisan budaya lokal melalui pertunjukan dan lomba di festival desa.</p>",
"kategoriBeritaId": "cmk69tghy000wvnv8umg2vloa",
"imageName": "2wivBEDcVNxHGG8HUBsNH-mobile.webp"
},
{
"id": "cmk6aih8f00093b6rqw63yp8z",
"judul": "Dialog Publik Tingkatkan Partisipasi Budaya Lokal",
"deskripsi": "<p>Forum dialog desa mengangkat tema partisipasi masyarakat dalam kegiatan budaya lokal.</p>",
"content": "<p>Diskusi ini memperkuat peran budaya dalam pembangunan desa melalui keterlibatan warga dalam kegiatan adat dan sosial.</p>",
"kategoriBeritaId": "cmk69tghy000wvnv8umg2vloa",
"imageName": "T1fcksUoZSUqNMbzvr9WI-mobile.webp"
}
]

View File

@@ -1,8 +1,8 @@
[
{ "name": "Pemerintahan" },
{ "name": "Pembangunan" },
{ "name": "Ekonomi" },
{ "name": "Sosial" },
{ "name": "Budaya" },
{ "name": "Teknologi" }
{ "id": "cmk69tght000svnv8ok5rid2v", "name": "Pemerintahan" },
{ "id": "cmk69tghx000tvnv8g2d206wv", "name": "Pembangunan" },
{ "id": "cmk69tghx000uvnv847ppcxqh", "name": "Ekonomi" },
{ "id": "cmk69tghy000vvnv8xeouenv5", "name": "Sosial" },
{ "id": "cmk69tghy000wvnv8umg2vloa", "name": "Budaya" },
{ "id": "cmk69tghz000xvnv8kxzzt24h", "name": "Teknologi" }
]

View File

@@ -0,0 +1,20 @@
[
{
"id": "cml0aiiv1000004l754ldaf2v",
"name": "Kunjungan Ibu TP PKK Kabupaten Badung",
"deskripsi": "<p>Dokumentasi kunjungan Ibu TP PKK Kabupaten Badung ke Desa Darmasaba pada awal tahun 2026.</p>",
"imageName": "foto1Gallery.webp"
},
{
"id": "cml0aiqd4000104l7f91ee3xu",
"name": "Darmasaba Village Festival II 2024",
"deskripsi": "<p>Foto kegiatan Darmasaba Village Festival II Tahun 2024 yang diselenggarakan di Lapangan Umum Desa Darmasaba, menampilkan lomba, pementasan seni, dan UMKM lokal.</p>",
"imageName": "foto2Gallery.webp"
},
{
"id": "cml0aiyi7000204l7f2sy657c",
"name": "Lomba Mancing Air Deras Banjar Gulingan",
"deskripsi": "<p>Galeri foto kegiatan lomba mancing air deras Komunitas Pemancing Gulingan di Desa Darmasaba, bagian dari pemberdayaan masyarakat.</p>",
"imageName": "foto3Gallery.webp"
}
]

View File

@@ -0,0 +1,20 @@
[
{
"id": "cmk6kvn6b0000vn6qzg5z6qa6",
"judul": "TAHAP PENILAIAN VERIFIKASI LAPANGAN AJANG MANGUPURA AWARD TAHUN 2025",
"deskripsi": "<p>TAHAP PENILAIAN VERIFIKASI LAPANGAN AJANG MANGUPURA AWARD Senin, 29 September 2025 Pemerintah Desa Darmasaba mengikuti tahap penilaian verifikasi lapangan dalam rangkaian Ajang Mangupura Award Tahun 2025 pada kategori Pemerintah Desa. Ajang bergengsi ini merupakan bentuk apresiasi Pemerintah Kabupaten Badung kepada desa-desa yang berprestasi dalam tata kelola aset, keuangan, arsip, tata kelola sumber daya manusia, pelayanan publik dan persampahan, inovasi, sinergitas, dan akuntabilitas. Proses verifikasi lapangan diawali di Kantor Perbekel Darmasaba dengan pemeriksaan langsung kepada masing-masing pengampu indikator, kemudian dilanjutkan dengan kunjungan ke BUMDes Pudak Mesari serta TPS 3R Pudak Mesari sebagai bentuk evaluasi nyata terhadap kinerja dan program desa. Kegiatan ini menjadi langkah penting dalam menilai implementasi tata kelola pemerintahan desa yang transparan, inovatif, dan berkelanjutan. Melalui tahapan ini, Pemerintah Desa Darmasaba berharap dapat terus menghadirkan pelayanan terbaik bagi masyarakat, mengembangkan inovasi desa, serta memperkuat sinergi antara pemerintah, desa adat, dan masyarakat dalam mewujudkan pembangunan daerah yang maju, berdaya saing, dan berkelanjutan. #MangupuraAward2025 #Darmasaba #DesaBerprestasi #PemerintahDesa #Badung #Abiansemal #PemdesDarmasaba #PerbekelDarmasaba #DesaDarmasaba #KitaDarmasaba #DarmasabaBisa</p>",
"linkVideo": "https://www.youtube.com/watch?v=e2tSRnNkYDE"
},
{
"id": "cmk6kvn6b0000vn6qzg5z6qb7",
"judul": "Vaksinasi Rabies di Desa Darmasaba",
"deskripsi": "<p>Vaksinasi Rabies di Desa Darmasaba Selasa, 7 Oktober 2025 Pemerintah Desa Darmasaba melalui Tim Bajra Desa Darmasaba, bekerja sama dengan Dinas Pertanian dan Pangan Kabupaten Badung Bidang Kesehatan Hewan, menyelenggarakan kegiatan Vaksinasi Rabies bagi hewan penular rabies (HPR) yang meliputi anjing, kucing, dan kera di wilayah Desa Darmasaba. Kegiatan ini dilaksanakan sebagai langkah preventif untuk menekan penyebaran virus rabies sekaligus memberikan perlindungan kesehatan bagi hewan peliharaan maupun masyarakat. Melalui program vaksinasi ini, diharapkan Desa Darmasaba dapat terbebas dari ancaman rabies dan semakin meningkatkan kesadaran masyarakat akan pentingnya menjaga kesehatan hewan peliharaan. Pemerintah Desa Darmasaba mengimbau seluruh warga untuk memastikan hewan kesayangan mendapatkan vaksinasi sesuai jadwal yang telah ditentukan. Informasi lengkap mengenai jadwal vaksinasi dapat dilihat pada pengumuman yang tertera. Selain itu, demi kelancaran proses vaksinasi, diharapkan pemilik hewan dapat mengikat atau mengandangkan hewan peliharaannya saat proses vaksinasi berlangsung. Dengan adanya kolaborasi antara pemerintah desa, dinas terkait, dan partisipasi aktif masyarakat, kegiatan ini diharapkan mampu memberikan manfaat nyata serta menciptakan lingkungan Desa Darmasaba yang lebih sehat, aman, dan terbebas dari rabies. #VaksinasiRabies #KesehatanHewan #BebasRabies #Badung #Abiansemal #TimBajraDarmasaba #PemdesDarmasaba #PerbekelDarmasaba #DesaDarmasaba #KitaDarmasaba #DarmasabaBisa</p>",
"linkVideo": "https://www.youtube.com/watch?v=bc99y94FBx8"
},
{
"id": "cmk6kvn6b0000vn6qzg5z6qc8",
"judul": "Musyawarah Perencanaan Pembangunan Desa Darmasaba Tahun 2026",
"deskripsi":"<p>Musyawarah Perencanaan Pembangunan Desa Darmasaba Tahun 2026 Pemerintah Desa Darmasaba menyelenggarakan Musyawarah Perencanaan Pembangunan Desa (Musrenbangdes)dalam rangka penyusunan Rencana Kerja Pemerintah Desa (RKP Desa) Tahun 2026. Musrenbangdes ini merupakan forum resmi yang mempertemukan perwakilan dari DPMD Kab. Badung, Kecamatan Abiansemal, Pemerintah Desa, Lembaga Desa, Tokoh Masyarakat, serta perwakilan unsur lainnya untuk bersama-sama merumuskan arah pembangunan desa di tahun mendatang. Melalui kegiatan ini, seluruh peserta diberikan ruang untuk menyampaikan usulan, gagasan, serta masukan yang berkaitan dengan prioritas pembangunan, baik di bidang infrastruktur, pemberdayaan masyarakat, ekonomi, sosial, maupun pelestarian adat dan budaya. Proses musyawarah ini menjadi bagian penting dalam mewujudkan pembangunan desa yang partisipatif, transparan, dan berorientasi pada kebutuhan masyarakat. Dengan terselenggaranya Musrenbangdes ini, Pemerintah Desa Darmasaba berharap RKP Desa Tahun 2026 dapat disusun secara komprehensif, berkelanjutan, dan selaras dengan visi pembangunan daerah. Selain itu, kegiatan ini juga menegaskan komitmen Pemerintah Desa Darmasaba untuk terus menghadirkan pembangunan yang inklusif, berkeadilan, dan bermanfaat bagi seluruh lapisan masyarakat. #Musrenbangdes2026 #RKPDarmasaba2026 #PemdesDarmasaba #PerbekelDarmasaba #DesaDarmasaba #KitaDarmasaba #DarmasabaBisa</p>",
"linkVideo": "https://www.youtube.com/watch?v=7pirwEmyP-4"
}
]

View File

@@ -1,57 +1,79 @@
[
{
"id" : "cmdxyb9zi0010vniiaeyi55ui",
"name" : "Surat Keterangan Beda Biodata Diri",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Fotocopy dokumen bersangkutan yang terdapat perbedaan biodata diri misal : Sertifikat Tanah/Ijazah/Polis Asuransi dan lainnya.</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxycqz40014vniidftrixvf",
"name" : "Surat Keterangan Yatim Piatu",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau KIA atau Kartu Keluarga</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdwx3wph0003vnr74us2t7h7",
"name" : "Surat Keterangan Domisili Organisasi",
"deskripsi" : "<p>Persyaratan Dokumen:</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy Surat Keterangan Terdaftar (SKT) organisasi atau Pengukuhan Kelompok</p></li><li><p>Jika Pengajuan baru pembuatan SKT maka melengkapi Susunan Pengurus lengkap dengan Kop Organisasi</p></li><li><p>Tanggal berdiri/Tahun berdiri/Sejak kapan berdirinya organisasi</p></li></ul><p>Alur Pelayanan:</p>"
},
{
"id" : "cmdxxv3i80004vniidg1mrucc",
"name" : "Surat Keterangan Penghasilan",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP orang tua atau Fotocopy Kartu keluarga</p></li><li><p>Membuat Surat Pernyataan Penghasilan bermaterai (disertai jumlah penghasilan)</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxxwp070008vnii9jbdcto7",
"name" : "Surat Keterangan Tidak Mampu",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP/KIA atau Kartu Keluarga</p></li><li><p>Fotocopy Kartu Indonesia Pintar/Kartu Perlindungan Sosial/Terdaftar dalam DTKS</p></li><li><p>Jika tidak memiliki Kartu tersebut diatas diwajibkan membuat Surat Pernyataan Tidak Mampu</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxxyfkl000cvnii1bxinnfi",
"name" : "Surat Keterangan Kelahiran",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy Surat lahir dari dokter/bidan (jika ada)</p></li><li><p>Fotocopy Kartu Keluarga</p></li><li><p>Fotocopy KTP 2 orang saksi</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxy23pl000gvniihsg38aq4",
"name" : "Surat Keterangan Usaha",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Foto Lokasi dan Kegiatan Usaha di cetak dalam selembar kertas (diparaf dan stempel oleh Kelian Banjar Dinas)</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxy4mgt000kvniib1nemjem",
"name" : "Surat Keterangan Kematian",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Surat Kematian dari rumah sakit atau dokter (jika ada)</p></li><li><p>tanggal kematian</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxy61a1000ovniif4ytb9hs",
"name" : "Surat Keterangan Tempat Usaha",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Foto Lokasi&nbsp;dan Kegiatan Usaha di cetak dalam selembar kertas (diparaf dan stempel oleh Kelian Banjar Dinas)</p></li><li><p>Surat Perjanjian Sewa/Kontrak atau Kwintansi Pembayaran Sewa 3 bulan terakhir bagi yang mengontrak tempat usaha, apabila tempat usaha milik sendiri lampiri dengan dokumen kepemilikan tempat usaha (dapat berupa fotocopy sppt atau Fotocopy Sertipikat Hak Milik)</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxy754q000svniiiz8oqyo0",
"name" : "Surat Keterangan Belum Kawin",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Khusus bagi yang berstatus duda atau janda melampirkan fotocopy akta cerai atau dokumen pendukung lainnya</p></li></ul><p>Alur Pelayanan :</p>"
},
{
"id" : "cmdxy8pi2000wvnii48fc1sxd",
"name" : "Surat Keterangan Kelakuan Baik",
"deskripsi" : "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li></ul><p>Alur Pelayanan :</p>"
}
]
{
"id": "cmdxyb9zi0010vniiaeyi55ui",
"name": "Surat Keterangan Beda Biodata Diri",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Fotocopy dokumen bersangkutan yang terdapat perbedaan biodata diri misal : Sertifikat Tanah/Ijazah/Polis Asuransi dan lainnya.</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "wFXYVHKHtU7posfhBKjZt-mobile.webp",
"image2Name": "kTiZ9uhRUEwu0WeASU00b-mobile.webp"
},
{
"id": "cmdxycqz40014vniidftrixvf",
"name": "Surat Keterangan Yatim Piatu",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau KIA atau Kartu Keluarga</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "ZkvjJ7Zx8uBy2-d8RWNEt-mobile.webp",
"image2Name": "hHfOWKz4USZK-z0nsD7Uz-mobile.webp"
},
{
"id": "cmdwx3wph0003vnr74us2t7h7",
"name": "Surat Keterangan Domisili Organisasi",
"deskripsi": "<p>Persyaratan Dokumen:</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy Surat Keterangan Terdaftar (SKT) organisasi atau Pengukuhan Kelompok</p></li><li><p>Jika Pengajuan baru pembuatan SKT maka melengkapi Susunan Pengurus lengkap dengan Kop Organisasi</p></li><li><p>Tanggal berdiri/Tahun berdiri/Sejak kapan berdirinya organisasi</p></li></ul><p>Alur Pelayanan:</p>",
"imageName": "03WZn5JMKffo62cKzShF4-mobile.webp",
"image2Name": "dnTcxeYQACzY5yzq-Rjoz-mobile.webp"
},
{
"id": "cmdxxv3i80004vniidg1mrucc",
"name": "Surat Keterangan Penghasilan",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP orang tua atau Fotocopy Kartu keluarga</p></li><li><p>Membuat Surat Pernyataan Penghasilan bermaterai (disertai jumlah penghasilan)</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "7er4OinxhuKRZUSkKeSYR-mobile.webp",
"image2Name": "8ZtJeCnKwMAcEUBU0QvE7-mobile.webp"
},
{
"id": "cmdxxwp070008vnii9jbdcto7",
"name": "Surat Keterangan Tidak Mampu",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP/KIA atau Kartu Keluarga</p></li><li><p>Fotocopy Kartu Indonesia Pintar/Kartu Perlindungan Sosial/Terdaftar dalam DTKS</p></li><li><p>Jika tidak memiliki Kartu tersebut diatas diwajibkan membuat Surat Pernyataan Tidak Mampu</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "Y7IuwpwjT3ZFYWpiXJZYw-mobile.webp",
"image2Name": "Fbi-6gnhokkwux9hvriS--mobile.webp"
},
{
"id": "cmdxxyfkl000cvnii1bxinnfi",
"name": "Surat Keterangan Kelahiran",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy Surat lahir dari dokter/bidan (jika ada)</p></li><li><p>Fotocopy Kartu Keluarga</p></li><li><p>Fotocopy KTP 2 orang saksi</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "qtdJ39rIbjGTJJQZflrDL-mobile.webp",
"image2Name": "ldmfJBS2ZBhIda60yU2JW-mobile.webp"
},
{
"id": "cmdxy23pl000gvniihsg38aq4",
"name": "Surat Keterangan Usaha",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Foto Lokasi dan Kegiatan Usaha di cetak dalam selembar kertas (diparaf dan stempel oleh Kelian Banjar Dinas)</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "CAtRFHiM11gsY4ExcvGgc-mobile.webp",
"image2Name": "MLWp-38kKygXKVekCh0q7-mobile.webp"
},
{
"id": "cmdxy4mgt000kvniib1nemjem",
"name": "Surat Keterangan Kematian",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Surat Kematian dari rumah sakit atau dokter (jika ada)</p></li><li><p>tanggal kematian</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "C0zE5lneKa888VJDHzgh--mobile.webp",
"image2Name": "hhDK7OL0wQLik5dsh1a-L-mobile.webp"
},
{
"id": "cmdxy61a1000ovniif4ytb9hs",
"name": "Surat Keterangan Tempat Usaha",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Foto Lokasi&nbsp;dan Kegiatan Usaha di cetak dalam selembar kertas (diparaf dan stempel oleh Kelian Banjar Dinas)</p></li><li><p>Surat Perjanjian Sewa/Kontrak atau Kwintansi Pembayaran Sewa 3 bulan terakhir bagi yang mengontrak tempat usaha, apabila tempat usaha milik sendiri lampiri dengan dokumen kepemilikan tempat usaha (dapat berupa fotocopy sppt atau Fotocopy Sertipikat Hak Milik)</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "sVIfCUGBplNU8h1x99l8z-mobile.webp",
"image2Name": "MM-1CZMai3eXwbVr2HAEv-mobile.webp"
},
{
"id": "cmdxy754q000svniiiz8oqyo0",
"name": "Surat Keterangan Belum Kawin",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li><li><p>Khusus bagi yang berstatus duda atau janda melampirkan fotocopy akta cerai atau dokumen pendukung lainnya</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "oNH9VvRPlAmTI_Ndu3slN-mobile.webp",
"image2Name": "Wze2x68vn-ShZAqgkSCMC-mobile.webp"
},
{
"id": "cmdxy8pi2000wvnii48fc1sxd",
"name": "Surat Keterangan Kelakuan Baik",
"deskripsi": "<p>Persyaratan Dokumen :</p><ul><li><p>Pengantar Kelian Banjar Dinas di Wilayah Masing - masing</p></li><li><p>Fotocopy KTP atau Kartu Keluarga</p></li></ul><p>Alur Pelayanan :</p>",
"imageName": "tK9T6BObEQEdYU-5y1xnJ-mobile.webp",
"image2Name": "sX9yfcM05OOx2ELhcSNWl-mobile.webp"
}
]

View File

@@ -0,0 +1,30 @@
[
{
"id": "cmkal9dd70002vnexhvn4j2fv",
"name": "Perbekel Darmasaba Terima Penghargaan pada Indonesia Alternative Dispute Resolution Awards 2025",
"juara": "Penghargaan IADRA 2025",
"deskripsi": "<p>Perbekel Darmasaba, Ida Bagus Surya Prabhawa Manuaba menerima penghargaan pada Indonesia Alternative Dispute Resolution Awards 2025 atas kontribusi dalam penyelesaian sengketa secara damai dan berkeadilan.</p>",
"imageName": "cte_gy0V8glhDcghMa3-B-mobile.webp"
},
{
"id": "cmkalfbux0005vnexj8zplube",
"name": "Penghargaan Bhawana Sewaka Nugraha kepada Perbekel Darmasaba",
"juara": "Penghargaan Bhawana Sewaka Nugraha",
"deskripsi": "<p>Penghargaan Bhawana Sewaka Nugraha diberikan kepada Perbekel Desa Darmasaba atas dedikasi dan komitmen dalam menjaga kelestarian lingkungan serta menginspirasi masyarakat untuk menciptakan desa yang hijau, bersih, dan berkelanjutan.</p>",
"imageName": "hLoy_DjB_3Yie2vjaXDYz-mobile.webp"
},
{
"id": "cmkalg6hk0008vnexmsqwd3n7",
"name": "Desa Darmasaba Raih Juara 1 Lomba Desa Tingkat Provinsi Bali Tahun 2025",
"juara": "Juara 1 Lomba Desa Provinsi Bali 2025",
"deskripsi": "<p>Desa Darmasaba meraih juara 1 dalam Lomba Desa Tingkat Provinsi Bali Tahun 2025 melalui sinergi elemen desa serta inovasi dalam pelayanan publik dan pemberdayaan masyarakat.</p>",
"imageName": "VxELyZ0ifdHOdRFu7aBSz-mobile.webp"
},
{
"id": "cmkalgucu000bvnexw2blt1v3",
"name": "Pemerintah Desa Darmasaba Raih Peringkat IV dalam Ajang Mangupura Award Tahun 2025",
"juara": "Peringkat IV Mangupura Award 2025",
"deskripsi": "<p>Desa Darmasaba mendapatkan penghargaan Peringkat IV pada Mangupura Award 2025 dari Pemerintah Kabupaten Badung atas tata kelola pemerintahan, inovasi layanan, dan pemberdayaan masyarakat.</p>",
"imageName": "xgrBxDdo8g7KA-3zNbRGj-mobile.webp"
}
]

View File

@@ -0,0 +1,8 @@
[
{ "id": "cmk69tghx111tvnv8g2d206wv", "name": "Digitalisasi Desa" },
{ "id": "cmk69tghx111uvnv847ppcxqh", "name": "Adat & Budaya" },
{ "id": "cmk69tght111svnv8ok5rid2v", "name": "Lingkungan & Bencana" },
{ "id": "cmk69tghy111wvnv8umg2vloa", "name": "Pendidikan & Kepemudaan" },
{ "id": "cmk69tghy111vvnv8xeouenv5", "name": "Ekonomi & UMKM" },
{ "id": "cmk69tghz111xvnv8kxzzt24h", "name": "Sosial & Kesehatan" }
]

View File

@@ -0,0 +1,37 @@
[
{
"id": "cmk6ae8rz00003b6r06x7hsqz",
"judul": "Pengumuman Lelang Pengadaan Pick UpDump TPS3R Pudak Mesari",
"deskripsi": "<p>Pengumuman lelang pengadaan alat Pick UpDump untuk TPS3R Pudak Mesari Desa Darmasaba.</p>",
"content": "<p>Desa Darmasaba membuka lelang pengadaan Pick UpDump untuk mendukung kegiatan pengelolaan sampah di TPS3R Pudak Mesari.</p>",
"categoryPengumumanId": "cmk69tghy111vvnv8xeouenv5"
},
{
"id": "cmk6af7vf00013b6rj2br4nv7",
"judul": "Pengumuman Lelang Pembangunan Taman BR. Darmasaba",
"deskripsi": "<p>Pengumuman lelang pembangunan taman di Banjar BR. Darmasaba.</p>",
"content": "<p>Desa Darmasaba mengumumkan pelaksanaan lelang pembangunan taman sebagai bagian dari upaya memperindah ruang publik desa.</p>",
"categoryPengumumanId": "cmk69tghy111vvnv8xeouenv5"
},
{
"id": "cmk6afo0g00033b6rjc2pae69",
"judul": "Pengumuman Lelang Penataan Lapangan Desa Darmasaba Tahun Anggaran 2024",
"deskripsi": "<p>Pengumuman lelang penataan lapangan Desa Darmasaba untuk tahun anggaran 2024.</p>",
"content": "<p>Lelang penataan lapangan desa dilaksanakan untuk menunjang kegiatan desa dan fasilitas masyarakat di Darmasaba.</p>",
"categoryPengumumanId": "cmk69tghy111vvnv8xeouenv5"
},
{
"id": "cmk6ag56y00053b6rj9481z5l",
"judul": "Pengumuman Lelang Penataan Landscape Lapangan Desa",
"deskripsi": "<p>Pengumuman lelang penataan landscape lapangan Desa Darmasaba.</p>",
"content": "<p>Desa Darmasaba menyelenggarakan lelang untuk kegiatan penataan landscape lapangan desa dalam rangka peningkatan fasilitas umum.</p>",
"categoryPengumumanId": "cmk69tghx111tvnv8g2d206wv"
},
{
"id": "cmk6agzxx00073b6rr3vhxcti",
"judul": "Penutupan KKN-PMM Periode II Universitas Warmadewa di Desa Darmasaba",
"deskripsi": "<p>Penutupan program KKN-PMM yang berjalan dengan berbagai kegiatan pemberdayaan masyarakat.</p>",
"content": "<p>Kegiatan KKN meliputi edukasi kesehatan, pengelolaan sampah, literasi keuangan, dan upaya ekonomi lokal sebagai bagian dari pembangunan desa berkelanjutan.</p>",
"categoryPengumumanId": "cmk69tghx111tvnv8g2d206wv"
}
]

View File

@@ -0,0 +1,14 @@
[
{
"id": "cmk3pmwq10008vn9bqdquv153",
"nama": "Wisata"
},
{
"id": "cmk3s1ks6000ivn9bcrv960ko",
"nama": "Ekonomi"
},
{
"id": "cmk3s1r0m000jvn9b8tlhogwn",
"nama": "Lingkungan"
}
]

View File

@@ -1,74 +1,90 @@
[
{
"id": "cmdyamai40004vnw3sdjbvn48",
"name": "TPS3R Pudak Mesari",
"deskripsi": "TPS 3R Pudak Mesari Darmasaba layak mendapat penghargaan demikian apresiasi dari Delterra Sosial Indonesia nie Semeton Darmasaba!, Hal tersebut dikarenakan walaupun baru berdiri namun TPS 3R kebanggaan Desa Darmasaba tersebut sudah berjalan dengan sangat baik.",
"content": "<p>TPS3R Pudak Mesari adalah Tempat Pengolahan Sampah dengan konsep Reduce, Reuse, dan Recycle (TPS3R) yang berlokasi di Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung, Bali. Fasilitas ini berperan penting dalam pengelolaan sampah berbasis masyarakat, dengan tujuan mengurangi volume sampah yang masuk ke Tempat Pembuangan Akhir (TPA) dan meningkatkan kesadaran warga tentang pentingnya pengelolaan sampah yang berkelanjutan.</p><p>Potensi Desa melalui TPS3R Pudak Mesari:</p><ol><li><p><strong>Peningkatan Kesehatan Lingkungan:</strong></p><p>Dengan pengelolaan sampah yang efektif, desa dapat menjaga kebersihan lingkungan, mengurangi risiko penyakit, dan menciptakan suasana yang lebih nyaman bagi warga.</p></li><li><p><strong>Pemberdayaan Ekonomi Masyarakat:</strong></p><p>TPS3R membuka peluang usaha bagi warga melalui pemilahan dan pengolahan sampah, seperti produksi kompos dari sampah organik dan kerajinan tangan dari sampah anorganik yang dapat meningkatkan pendapatan masyarakat.</p></li><li><p><strong>Edukasi dan Kesadaran Lingkungan:</strong></p><p>Fasilitas ini dapat menjadi pusat edukasi bagi masyarakat tentang pentingnya pengelolaan sampah, mendorong partisipasi aktif dalam menjaga kelestarian lingkungan.</p></li><li><p><strong>Pengembangan Pariwisata Berkelanjutan:</strong></p><p>Dengan lingkungan yang bersih dan asri, Desa Darmasaba memiliki potensi untuk menarik wisatawan yang tertarik pada ekowisata dan budaya lokal, sehingga meningkatkan perekonomian desa.</p></li></ol>"
},
{
"id": "cmdyb7h440003vngjapbc84f7",
"name": "Bumdes Pudak Mesari",
"deskripsi": "Bumdes Pudak Mesari sangat membantu warga desa Darmasaba dalam mengelola dan membangun sebuah desa yang lebih baik lagi",
"content": "<p>Badan Usaha Milik Desa (BUMDes) Pudak Mesari adalah lembaga ekonomi desa yang berperan penting dalam pengembangan potensi dan kesejahteraan masyarakat Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung, Bali. BUMDes ini berfungsi sebagai motor penggerak perekonomian desa melalui berbagai unit usaha yang dikelola secara profesional.</p><p>Potensi dan Peran BUMDes Pudak Mesari:</p><ol><li><p><strong>Pengembangan Usaha Mikro dan Kecil:</strong></p><p>BUMDes Pudak Mesari menyediakan layanan bagi pelaku usaha mikro dan kecil di desa, seperti penyediaan konsumsi dan snack kotak untuk berbagai acara.</p></li><li><p><strong>Pengelolaan Sampah Berbasis Masyarakat:</strong></p><p>Melalui kolaborasi dengan komunitas pemuda peduli lingkungan, BUMDes Pudak Mesari aktif dalam pengelolaan sampah berbasis masyarakat.</p></li><li><p><strong>Peningkatan Kapasitas dan Transparansi:</strong></p><p>Untuk memastikan pengelolaan yang akuntabel, BUMDes Pudak Mesari rutin mengadakan rapat koordinasi dan pendampingan penyusunan laporan pertanggungjawaban.</p></li><li><p><strong>Kolaborasi Internasional:</strong></p><p>Desa Darmasaba, melalui BUMDes Pudak Mesari, menerima kunjungan dari tim Osaki Jepang untuk memperkuat pengelolaan sampah dan lingkungan.</p></li></ol><p>Dengan berbagai inisiatif tersebut, BUMDes Pudak Mesari menunjukkan perannya sebagai pilar utama dalam pengembangan ekonomi dan kesejahteraan masyarakat Desa Darmasaba, sekaligus menjaga kelestarian lingkungan melalui program-program inovatif dan kolaboratif.</p>"
},
{
"id": "cmdybb53i0007vngjet38spn8",
"id": "cmk3rbc7s000evn9bvb8p0xk1",
"name": "Taman Beji Cengana",
"deskripsi": "Tirta Klebutan di Pura Taman Beji Cengana di Desa Adat Darmasaba, Badung, selain dipercaya nunas Taksu serta pembersihan diri. Tersemat juga asal usul cerita ditemukannya Tirta Klebutan yang tepat berada di pinggir Tukad Cengana tersebut.",
"content": "<p>Taman Beji Cengana, terletak di Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung, Bali, adalah situs suci yang memiliki nilai spiritual dan sejarah yang tinggi. Tempat ini dikenal sebagai lokasi untuk ritual pembersihan diri (melukat) dan peribadatan oleh umat Hindu Bali. Keberadaan mata air suci (Tirta Klebutan) di Taman Beji Cengana dipercaya memberikan berkah dan penyucian bagi mereka yang datang untuk berdoa dan melakukan ritual.</p><p>Potensi Desa melalui Taman Beji Cengana:</p><ol><li><p><strong>Pengembangan Pariwisata Spiritual:</strong></p><p>Taman Beji Cengana memiliki potensi besar sebagai destinasi wisata spiritual. Wisatawan yang mencari pengalaman spiritual dan ketenangan batin dapat tertarik untuk mengunjungi tempat ini, mengikuti ritual melukat, dan merasakan suasana sakral yang ditawarkan.</p></li><li><p><strong>Pelestarian Budaya dan Tradisi:</strong></p><p>Dengan mempromosikan Taman Beji Cengana sebagai pusat kegiatan budaya dan ritual tradisional, desa dapat memastikan bahwa warisan budaya dan tradisi lokal tetap lestari.</p></li><li><p><strong>Pendidikan dan Penelitian:</strong></p><p>Taman Beji Cengana dapat dijadikan sebagai pusat pendidikan dan penelitian bagi akademisi, peneliti, dan pelajar yang tertarik mempelajari budaya, agama, dan sejarah Bali.</p></li><li><p><strong>Pengembangan Ekonomi Kreatif:</strong></p><p>Dengan meningkatnya jumlah pengunjung ke Taman Beji Cengana, peluang bagi pengembangan ekonomi kreatif juga terbuka lebar. Masyarakat lokal dapat mengembangkan produk kerajinan tangan, kuliner khas, dan suvenir yang mencerminkan budaya dan tradisi desa.</p></li><li><p><strong>Konservasi Lingkungan:</strong></p><p>Sebagai situs suci dengan mata air alami, Taman Beji Cengana memiliki peran penting dalam konservasi lingkungan. Upaya menjaga kebersihan dan kelestarian mata air serta lingkungan sekitarnya dapat menjadi contoh praktik konservasi yang baik.</p></li></ol><p>Dengan memanfaatkan potensi yang dimiliki Taman Beji Cengana, Desa Darmasaba dapat mengembangkan sektor pariwisata, budaya, pendidikan, ekonomi, dan lingkungan secara berkelanjutan, yang pada gilirannya akan meningkatkan kesejahteraan masyarakat dan pelestarian warisan budaya.</p>"
"deskripsi": "<p>Taman Beji Cengana adalah situs keagamaan dan budaya tradisional Bali</p>",
"content": "<p>Taman Beji Cengana adalah situs keagamaan dan budaya tradisional Bali yang memadukan unsur spiritual, ritual pembersihan (melukat), serta nilai budaya lokal yang berpadu dengan suasana alam yang tenang dan harmonis.</p>",
"kategoriId": "cmk3pmwq10008vn9bqdquv153",
"imageName": "yySqpA7ougpXi6cJPskg9-mobile.webp"
},
{
"id": "cmdybckcz000avngjfzpy60uk",
"id": "cmk3q0sez000bvn9b3iyyct5m",
"name": "Gumuh Sari Water Park",
"deskripsi": "Gumuh Sari Rekreasi atau waterpark, tempat wisata yang asyik dan seru untuk kamu sekeluarga! Tempat liburan di Bali memang seakan nggak ada habisnya. Selalu ada aja destinasi wisata seru yang bisa jadi wishlist. Ada banyak banget tempat wisata yang kamu kunjungi di Bali, mulai dari wisata alam, wisata modern, sampai wisata air.",
"content": "<p>Gumuh Sari Waterpark, terletak di Jl. Tegal Gumuh No. 9, Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung, Bali, adalah destinasi rekreasi yang menawarkan berbagai fasilitas untuk pengunjung dari segala usia. Taman rekreasi ini tidak hanya menyediakan wahana air yang menyenangkan, tetapi juga fasilitas olahraga dan kuliner, menjadikannya tempat ideal untuk rekreasi keluarga dan komunitas.</p><p>Potensi Desa melalui Gumuh Sari Waterpark:</p><ol><li><p><strong>Pengembangan Pariwisata Lokal:</strong></p><p>Dengan adanya destinasi seperti Gumuh Sari Waterpark, Desa Darmasaba dapat menarik lebih banyak wisatawan lokal maupun mancanegara. Kehadiran pengunjung ini berpotensi meningkatkan pendapatan desa dan membuka peluang usaha baru bagi masyarakat setempat.</p></li><li><p><strong>Peningkatan Ekonomi Masyarakat:</strong></p><p>Fasilitas seperti restoran dan pusat olahraga di dalam kompleks waterpark memberikan peluang bagi warga lokal untuk terlibat dalam sektor jasa dan perdagangan. Hal ini dapat menciptakan lapangan pekerjaan dan mendukung pertumbuhan ekonomi desa.</p></li><li><p><strong>Pengembangan Fasilitas Olahraga dan Kesehatan:</strong></p><p>Dengan adanya pusat futsal dan gym, Gumuh Sari Waterpark mendorong masyarakat untuk berpartisipasi dalam kegiatan olahraga, yang dapat meningkatkan kesehatan dan kesejahteraan warga.</p></li><li><p><strong>Pemberdayaan Komunitas Melalui Event dan Acara:</strong></p><p>Waterpark ini sering menjadi tuan rumah berbagai acara komunitas, seperti pesta busa dan bola, yang dapat mempererat hubungan antarwarga dan menciptakan lingkungan yang harmonis.</p></li><li><p><strong>Peningkatan Infrastruktur dan Aksesibilitas:</strong></p><p>Dengan meningkatnya jumlah pengunjung, infrastruktur desa seperti jalan, transportasi, dan layanan umum lainnya akan berkembang untuk memenuhi kebutuhan tersebut, yang pada gilirannya meningkatkan kualitas hidup masyarakat setempat.</p></li></ol><p>Melalui pengelolaan dan pengembangan yang tepat, Gumuh Sari Waterpark dapat menjadi motor penggerak bagi kemajuan Desa Darmasaba, meningkatkan kesejahteraan masyarakat, dan menjadikan desa ini sebagai destinasi wisata yang dikenal luas.</p>"
"deskripsi": "<p>Gumuh Sari merupakan tempat rekreasi nyaman di kawasan badung yang dapat dinikmati oleh semua umur dengan berbagai fasilitas hiburan, seperti Water Park, Pusat Kebugaran, Lapangan Futsal dan Restaurant.</p>",
"content": "<p>Gumuh Sari merupakan tempat rekreasi nyaman di kawasan badung yang dapat dinikmati oleh semua umur dengan berbagai fasilitas hiburan, seperti Water Park, Pusat Kebugaran, Lapangan Futsal dan Restaurant.<br><br><strong>Buka setiap hari</strong><br>Senin-Jumat: pukul 10.00-18.00 WITA (Weekday)<br>Sabtu-Minggu: pukul 09.00-18.00 WITA (Weekend)<br><br><strong>Wahana:</strong><br>- Kolam Renang Anak<br>- Kolam Renang Dewasa<br>- Kolam Renang Olympic<br>- Kids Playground Indoor<br>- Ayunan<br>- ATV<br><br><strong>Fasilitas:</strong><br>- Tempat ibadah<br>- Area parkir<br>- Gazebo<br>- Restoran dan kantin<br>- WiFi gratis<br>- Kamar mandi dan ruang bilas<br>- Ruang loker<br><br><strong>Kategori Tiket:</strong><br>Senin-Sabtu<br>- Dewasa 35.000<br>- Anak-anak (3-12 tahun) 20.000<br><br>Minggu &amp; Libur Nasional<br>- Dewasa 40.000<br>- Anak-anak (3-12 tahun) 25.000<br><br>Hari Raya<br>- Dewasa 45.000<br>- Anak-anak (3-12 tahun) 35.000<br><br><strong>Media Sosial:</strong><br>- Instagram: gumuhsari_rekreasi<br><a target='_blank' rel='noopener noreferrer nofollow' href='https://www.instagram.com/gumuhsari_rekreasi/'><u>https://www.instagram.com/gumuhsari_rekreasi/</u></a><br><br>- Tiktok: gumuhsari_rekreasi<br><a target='_blank' rel='noopener noreferrer nofollow' href='https://www.tiktok.com/@gumuhsari_rekreasi'><u>https://www.tiktok.com/@gumuhsari_rekreasi</u></a></p>",
"kategoriId": "cmk3pmwq10008vn9bqdquv153",
"imageName": "uki9Zy0DqrEtSg9Lrgyyk-mobile.webp"
},
{
"id": "cmdyjuij40002vns5qyyjmzf4",
"id": "cmk3rsch1000hvn9bhmyhsjqm",
"name": "TPS3R Pudak Mesari",
"deskripsi": "<p>Sistem pengelolaan sampah terpadu di Desa Darmasaba yang dikenal dengan TPS3R Pudak Mesari.</p>",
"content": "<p>TPS3R Pudak Mesari adalah fasilitas pengelolaan sampah terpadu yang mengoptimalkan pemilahan, pengolahan dan daur ulang sampah masyarakat sehingga mendukung lingkungan yang bersih dan berkelanjutan di Desa Darmasaba.</p>",
"kategoriId": "cmk3pmwq10008vn9bqdquv153",
"imageName": "F8SuL9DjCqLXlSwmgSJv_-mobile.webp"
},
{
"id": "cmk3s4kz7000mvn9b8thk98c4",
"name": "Bumdes Pudak Mesari",
"deskripsi": "<p>Badan Usaha Milik Desa yang bergerak dalam berbagai usaha ekonomi masyarakat Darmasaba.</p>",
"content": "<p>Bumdes Pudak Mesari merupakan badan usaha milik desa yang mengembangkan kegiatan usaha produktif untuk meningkatkan perekonomian masyarakat lokal, termasuk pengelolaan usaha jasa dan komoditas lokal yang dikelola secara partisipatif.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "daDa40Y8dxune0l_cxULD-mobile.webp"
},
{
"id": "cmk3sbgge000pvn9bd3r8i0on",
"name": "Pertanian",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, Bali, memiliki potensi pertanian yang besar sebagai bagian dari warisan agraris yang telah diwariskan secara turun-temurun. Dengan kondisi tanah yang subur serta sistem irigasi tradisional subak, pertanian di Darmasaba memainkan peran penting dalam ekonomi dan keberlanjutan lingkungan desa.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, Bali, memiliki potensi pertanian yang besar sebagai bagian dari warisan agraris yang telah diwariskan secara turun-temurun. Dengan kondisi tanah yang subur serta sistem irigasi tradisional subak, pertanian di Darmasaba memainkan peran penting dalam ekonomi dan keberlanjutan lingkungan desa.</p><p>Potensi Desa melalui Pertanian:</p><ol><li><p><strong>Potensi dan Komoditas Unggulan</strong></p><p>Pertanian di Desa Darmasaba mengandalkan berbagai jenis tanaman yang memiliki nilai ekonomi tinggi, di antaranya:</p><p>- Padi : Sebagai salah satu desa yang masih mempertahankan sistem subak, Darmasaba menjadi bagian dari lumbung pangan di Bali.</p><p>- Sayur-mayur : Beberapa jenis sayuran seperti kangkung, bayam, cabai, dan tomat banyak dibudidayakan oleh petani lokal.</p><p>- Buah-buahan tropis : Termasuk pisang, mangga, dan kelapa, yang menjadi sumber pendapatan tambahan bagi petani.</p><p>- Tanaman obat dan rempah : Seperti jahe, kunyit, dan lengkuas, yang memiliki permintaan tinggi baik untuk kebutuhan rumah tangga maupun industri herbal.</p></li><li><p><strong>Sistem Irigasi Tradisional Subak:</strong></p><p>Sebagai bagian dari warisan budaya Bali, sistem irigasi subak masih diterapkan di Darmasaba. Sistem ini memungkinkan distribusi air yang adil di antara lahan pertanian dan membantu menjaga keberlanjutan produksi pangan desa.</p></li><li><p><strong>Pengembangan Pertanian Organik:</strong></p><p>Dengan meningkatnya kesadaran akan pentingnya produk sehat dan ramah lingkungan, beberapa petani di Darmasaba mulai beralih ke metode pertanian organik. Hal ini membuka peluang bagi desa untuk mengembangkan produk-produk pertanian yang memiliki nilai jual lebih tinggi.</p></li><li><p><strong>Agrowisata sebagai Sumber Pendapatan Baru:</strong></p><p>Potensi pertanian Darmasaba juga dapat dikembangkan menjadi agrowisata, di mana wisatawan dapat merasakan pengalaman langsung dalam bertani, mengikuti workshop bercocok tanam, serta menikmati hasil pertanian segar. Hal ini dapat menarik wisatawan lokal maupun mancanegara, meningkatkan perekonomian desa.</p></li><li><p><strong>Pemberdayaan Petani dan UMKM Berbasis Pertanian:</strong></p><p>Dengan adanya BUMDes Pudak Mesari dan dukungan dari pemerintah setempat, petani di Darmasaba dapat diberikan pelatihan dan akses pasar yang lebih luas. Produk pertanian dapat diolah menjadi berbagai produk turunan seperti keripik pisang, sambal khas desa, hingga minuman herbal yang dapat dipasarkan ke luar daerah.</p></li></ol><p>Dengan berbagai potensi yang dimiliki, pertanian di Desa Darmasaba dapat terus berkembang melalui inovasi dan pemanfaatan teknologi pertanian modern. Dukungan dari masyarakat, pemerintah, dan lembaga terkait sangat penting untuk menjaga keberlanjutan sektor pertanian dan meningkatkan kesejahteraan petani di desa ini.</p>"
"deskripsi": "<p>Sektor pertanian sebagai salah satu potensi utama Desa Darmasaba.</p>",
"content": "<p>Pertanian di Darmasaba mencakup berbagai komoditas yang ditanam oleh masyarakat termasuk padi, tanaman hortikultura dan lain-lain, yang menjadi basis mata pencaharian dan kontribusi terhadap ekonomi desa.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "yms7mL_T6fy--Eze-mTwc-mobile.webp"
},
{
"id": "cmdykerrq0002vn6fy4sv7uvm",
"name": "Kawasan Kuliner",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, Bali, memiliki potensi besar dalam sektor kuliner. Sebagai desa yang strategis dan terus berkembang, Darmasaba mulai dikenal sebagai destinasi kuliner yang menawarkan beragam makanan khas Bali hingga makanan modern yang menarik minat wisatawan dan masyarakat lokal.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, Bali, memiliki potensi besar dalam sektor kuliner. Sebagai desa yang strategis dan terus berkembang, Darmasaba mulai dikenal sebagai destinasi kuliner yang menawarkan beragam makanan khas Bali hingga makanan modern yang menarik minat wisatawan dan masyarakat lokal.</p><p>Potensi Desa melalui Kawasan Kuliner:</p><ol><li><p><strong>Ragam Kuliner Khas Bali</strong></p><p>Darmasaba memiliki banyak warung dan rumah makan yang menyajikan hidangan khas Bali yang otentik, seperti:</p><p>- Babi Guling : Salah satu kuliner favorit di Bali yang banyak ditemukan di Darmasaba.</p><p>- Ayam Betutu : Hidangan ayam berbumbu khas yang dimasak dengan teknik khas Bali.</p><p>- Lawar : Campuran daging dan sayuran berbumbu khas Bali.</p><p>- Sate Lilit : Sate khas Bali yang terbuat dari daging cincang yang dibalut pada batang serai.</p></li><li><p><strong>Wisata Kuliner Modern &amp; Cafe Kekinian:</strong></p><p>Selain makanan tradisional, Darmasaba juga mulai berkembang dengan hadirnya cafe dan resto kekinian yang menyajikan menu modern seperti kopi spesial, burger, pizza, dan aneka dessert yang digemari anak muda. Keberadaan tempat-tempat ini menjadikan Darmasaba sebagai pilihan destinasi kuliner bagi wisatawan maupun warga sekitar.</p></li><li><p><strong>Pasar Kuliner Malam:</strong></p><p>Salah satu daya tarik Darmasaba adalah pusat kuliner malam yang menghadirkan aneka makanan kaki lima seperti nasi jinggo, tipat cantok, bakso, dan berbagai jajanan khas Bali. Suasana yang ramai dan harga yang terjangkau membuat pasar kuliner ini menjadi tempat favorit bagi masyarakat lokal.</p></li><li><p><strong>Potensi Ekonomi &amp; UMKM Kuliner:</strong></p><p>Dengan berkembangnya sektor kuliner, banyak pelaku UMKM di Darmasaba mulai merintis usaha makanan, baik dalam bentuk warung makan, katering, hingga produksi makanan ringan seperti keripik, sambal, dan minuman tradisional. Potensi ini dapat terus dikembangkan dengan dukungan pemerintah desa dan promosi melalui media sosial.</p></li><li><p><strong>Kawasan Kuliner Berbasis Pariwisata:</strong></p><p>Untuk menarik lebih banyak pengunjung, Darmasaba berpotensi mengembangkan kawasan kuliner berbasis wisata yang menggabungkan pengalaman makan dengan konsep alam terbuka, pertunjukan seni, dan edukasi kuliner khas Bali. Hal ini dapat menjadi daya tarik tambahan bagi wisatawan yang ingin merasakan pengalaman kuliner yang lebih autentik.</p></li></ol><p>Dengan kekayaan kuliner yang dimiliki, Desa Darmasaba berpotensi menjadi kawasan kuliner unggulan di Kabupaten Badung. Dukungan dari masyarakat, pemerintah desa, serta promosi yang lebih luas dapat menjadikan Darmasaba sebagai destinasi kuliner yang semakin dikenal dan berkembang.</p>"
"id": "cmk3smnj3000svn9b2ww5hesp",
"name": "Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma",
"deskripsi": "<p>Jalur jogging dan area rekreasi alam yang dimanfaatkan masyarakat untuk aktivitas sehat dan pariwisata lokal.</p>",
"content": "<p>Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma adalah area terbuka hijau yang dikembangkan sebagai fasilitas olahraga dan rekreasi, memberikan ruang beraktivitas fisik sambil menikmati suasana alam Desa Darmasaba.</p>",
"kategoriId": "cmk3pmwq10008vn9bqdquv153",
"imageName": "AFA1PZtHwKkwmWCC4M7lM-mobile.webp"
},
{
"id": "cmdykhfhf0005vn6fnz25kify",
"name": "IKM Berbasis Pengolahan Pangan",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam Industri Kecil dan Menengah (IKM) berbasis pengolahan pangan. Dengan sumber daya alam yang melimpah dan warisan kuliner khas Bali, Darmasaba dapat mengembangkan sektor ini untuk meningkatkan kesejahteraan masyarakat dan menciptakan lapangan kerja baru.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam Industri Kecil dan Menengah (IKM) berbasis pengolahan pangan. Dengan sumber daya alam yang melimpah dan warisan kuliner khas Bali, Darmasaba dapat mengembangkan sektor ini untuk meningkatkan kesejahteraan masyarakat dan menciptakan lapangan kerja baru.</p><p>Potensi dan Peran IKM Berbasis Pengolahan Pangan:</p><ol><li><p><strong>Produk Unggulan Pengolahan Pangan</strong></p><p>Beberapa produk olahan pangan yang potensial dikembangkan di Darmasaba meliputi:</p><p>- Keripik dan Snack Tradisional : Seperti keripik pisang, keripik singkong, dan rengginang.</p><p>- Sambal Khas Bali : Seperti sambal matah dan sambal embe yang banyak diminati pasar lokal dan nasional.</p><p>- Minuman Herbal dan Jamu : Berbasis rempah seperti kunyit asam, beras kencur, dan wedang jahe.</p><p>- Olahan Makanan Berbasis Kelapa : Seperti virgin coconut oil (VCO), serundeng, dan gula aren.</p><p>- Kue Tradisional Bali : Seperti jaje laklak, jaje uli, dan klepon yang dapat dikemas secara modern.</p></li><li><p><strong>Peluang Ekonomi dan Pemberdayaan UMKM:</strong></p><p>IKM berbasis pengolahan pangan dapat membuka peluang bagi masyarakat, terutama ibu rumah tangga dan pemuda desa, untuk berwirausaha. Dengan dukungan modal dan pelatihan dari pemerintah desa atau BUMDes Pudak Mesari, usaha kecil ini dapat berkembang menjadi industri yang lebih besar.</p></li><li><p><strong>Digitalisasi dan Pemasaran Online:</strong></p><p>Darmasaba dapat mengembangkan kawasan sentra IKM sebagai pusat produksi, pelatihan, dan pemasaran produk olahan pangan. Dengan adanya fasilitas ini, para pelaku usaha dapat lebih mudah berkolaborasi, meningkatkan kualitas produk, serta mendapatkan akses ke permodalan dan distribusi yang lebih luas.</p></li><li><p><strong>Pengembangan Kawasan Sentra IKM:</strong></p><p>Dengan berkembangnya sektor kuliner, banyak pelaku UMKM di Darmasaba mulai merintis usaha makanan, baik dalam bentuk warung makan, katering, hingga produksi makanan ringan seperti keripik, sambal, dan minuman tradisional. Potensi ini dapat terus dikembangkan dengan dukungan pemerintah desa dan promosi melalui media sosial.</p></li><li><p><strong>Sinergi dengan Pariwisata dan Agrowisata:</strong></p><p>Dengan berkembangnya sektor wisata di Darmasaba, produk olahan pangan dapat dijadikan suvenir khas desa. Pengunjung dapat membeli oleh-oleh seperti sambal kemasan, jajanan khas, atau minuman herbal sebagai bagian dari pengalaman wisata mereka.</p></li></ol><p>IKM berbasis pengolahan pangan memiliki potensi besar untuk menjadi sektor unggulan di Desa Darmasaba. Dengan inovasi, dukungan teknologi, serta pemasaran yang baik, produk-produk lokal dapat bersaing di pasar yang lebih luas, meningkatkan kesejahteraan masyarakat, dan menjadikan Darmasaba sebagai pusat industri pangan kreatif di Kabupaten Badung.</p>"
},
{
"id": "cmdykjgmv0008vn6fwg0rr2nh",
"name": "Genteng",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam industri genteng yang dikelola oleh Usaha Mikro, Kecil, dan Menengah (UMKM). Sebagai desa yang masih mempertahankan nilai-nilai tradisional dalam pembangunan, industri genteng di Darmasaba berperan penting dalam penyediaan bahan bangunan berkualitas bagi masyarakat lokal maupun luar daerah.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam industri genteng yang dikelola oleh Usaha Mikro, Kecil, dan Menengah (UMKM). Sebagai desa yang masih mempertahankan nilai-nilai tradisional dalam pembangunan, industri genteng di Darmasaba berperan penting dalam penyediaan bahan bangunan berkualitas bagi masyarakat lokal maupun luar daerah.</p><p>Potensi dan Peran UMKM Genteng:</p><ol><li><p><strong>Genteng Tradisional Berkualitas Tinggi</strong></p><p>UMKM di Darmasaba memproduksi genteng dari bahan baku pilihan seperti tanah liat berkualitas, yang menghasilkan genteng dengan daya tahan tinggi, kuat, dan cocok untuk iklim tropis. Beberapa jenis genteng yang dihasilkan meliputi:</p><p>- Genteng Tanah Liat : Kuat, tahan lama, dan memiliki estetika khas tradisional.</p><p>- Genteng Beton : Cocok untuk bangunan modern dengan ketahanan lebih tinggi.</p><p>- Genteng Keramik : Memberikan tampilan elegan dan daya serap air yang lebih rendah.</p></li><li><p><strong>Peluang Ekonomi dan Pemberdayaan Masyarakat:</strong></p><p>Industri genteng di Darmasaba memberikan peluang kerja bagi masyarakat setempat, terutama dalam bidang produksi, distribusi, hingga pemasaran. UMKM genteng juga mendukung keberlanjutan ekonomi desa dengan meningkatkan pendapatan warga serta mengurangi angka pengangguran.</p></li><li><p><strong>Inovasi dan Pengembangan Teknologi</strong></p><p>Beberapa pengrajin genteng di Darmasaba telah mulai mengadopsi teknologi modern dalam proses produksi, seperti:</p><p>- Penggunaan cetakan dan oven pembakaran efisien untuk meningkatkan kualitas dan kapasitas produksi.</p><p>- Teknik pelapisan anti bocor dan anti lumut untuk membuat genteng lebih tahan lama.</p><p>- Desain genteng inovatif yang lebih ringan dan mudah dipasang.</p></li><li><p><strong>Pemasaran dan Ekspansi Pasar</strong></p><p>Dengan meningkatnya pembangunan perumahan dan proyek konstruksi di Bali, permintaan akan genteng berkualitas terus bertambah. UMKM genteng Darmasaba dapat memperluas pasarnya dengan:</p><p>- Menjalin kerja sama dengan kontraktor dan pengembang properti.</p><p>- Mempromosikan produk melalui media sosial dan marketplace online.</p><p>- Menyediakan layanan custom sesuai kebutuhan pelanggan.</p></li><li><p><strong>Keberlanjutan dan Ramah Lingkungan:</strong></p><p>Industri genteng di Darmasaba berpotensi dikembangkan secara lebih ramah lingkungan dengan menerapkan metode produksi yang mengurangi limbah dan emisi. Pemanfaatan energi alternatif serta daur ulang bahan limbah dapat membantu menciptakan industri yang lebih berkelanjutan.</p></li></ol><p>UMKM genteng di Desa Darmasaba memiliki potensi besar untuk terus berkembang sebagai sektor industri unggulan. Dengan inovasi, pemasaran yang lebih luas, serta dukungan dari pemerintah dan masyarakat, industri ini dapat meningkatkan kesejahteraan warga dan memperkuat perekonomian desa.</p>"
},
{
"id": "cmdyklax3000bvn6fdu53f3xq",
"name": "Peternakan Ikan Lele",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam sektor peternakan lele. Dengan kondisi lingkungan yang mendukung serta meningkatnya permintaan ikan lele di pasaran, budidaya ikan lele dapat menjadi salah satu sektor ekonomi unggulan yang mampu meningkatkan kesejahteraan masyarakat desa.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam sektor peternakan lele. Dengan kondisi lingkungan yang mendukung serta meningkatnya permintaan ikan lele di pasaran, budidaya ikan lele dapat menjadi salah satu sektor ekonomi unggulan yang mampu meningkatkan kesejahteraan masyarakat desa.</p><p>Potensi dan Peran Peternakan Ikan Lele:</p><ol><li><p><strong>Kondisi Lingkungan yang Mendukung</strong></p><p>Darmasaba memiliki sumber air yang cukup serta iklim yang cocok untuk budidaya ikan lele. Kolam-kolam budidaya dapat dibuat dengan berbagai sistem, seperti:</p><p>- Kolam Terpal : Mudah dibuat dan lebih efisien dalam perawatan.</p><p>- Kolam Beton : Lebih tahan lama dan cocok untuk produksi skala besar.</p><p>- Sistem Bioflok : Teknologi modern yang dapat meningkatkan kepadatan ikan dan mengurangi limbah.</p></li><li><p><strong>Permintaan Pasar yang Tinggi:</strong></p><p>Lele merupakan salah satu jenis ikan yang memiliki permintaan tinggi di Bali, baik untuk konsumsi rumah tangga, warung makan, hingga restoran. Produk olahan seperti lele goreng, pecel lele, dan abon lele semakin diminati, membuka peluang besar bagi peternak lele di Darmasaba.</p></li><li><p><strong>Inovasi dan Pengembangan Teknologi</strong></p><p>Beberapa pengrajin genteng di Darmasaba telah mulai mengadopsi teknologi modern dalam proses produksi, seperti:</p><p>- Penggunaan cetakan dan oven pembakaran efisien untuk meningkatkan kualitas dan kapasitas produksi.</p><p>- Teknik pelapisan anti bocor dan anti lumut untuk membuat genteng lebih tahan lama.</p><p>- Desain genteng inovatif yang lebih ringan dan mudah dipasang.</p></li><li><p><strong>Pemasaran dan Ekspansi Pasar</strong></p><p>Dengan meningkatnya pembangunan perumahan dan proyek konstruksi di Bali, permintaan akan genteng berkualitas terus bertambah. UMKM genteng Darmasaba dapat memperluas pasarnya dengan:</p><p>- Menjalin kerja sama dengan kontraktor dan pengembang properti.</p><p>- Mempromosikan produk melalui media sosial dan marketplace online.</p><p>- Menyediakan layanan custom sesuai kebutuhan pelanggan.</p></li><li><p><strong>Keberlanjutan dan Ramah Lingkungan:</strong></p><p>Industri genteng di Darmasaba berpotensi dikembangkan secara lebih ramah lingkungan dengan menerapkan metode produksi yang mengurangi limbah dan emisi. Pemanfaatan energi alternatif serta daur ulang bahan limbah dapat membantu menciptakan industri yang lebih berkelanjutan.</p></li></ol><p>UMKM genteng di Desa Darmasaba memiliki potensi besar untuk terus berkembang sebagai sektor industri unggulan. Dengan inovasi, pemasaran yang lebih luas, serta dukungan dari pemerintah dan masyarakat, industri ini dapat meningkatkan kesejahteraan warga dan memperkuat perekonomian desa.</p>"
},
{
"id": "cmdykpkwf000gvn6ftas2cjje",
"name": "Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma Desa",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi wisata olahraga dan rekreasi melalui Jogging Track Tegeh Aban, Karang Gadon, dan Munduk Uma Desa. Jalur jogging ini tidak hanya menjadi fasilitas olahraga bagi warga, tetapi juga berpotensi dikembangkan sebagai destinasi wisata sehat berbasis alam yang menarik bagi wisatawan lokal maupun luar daerah.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi wisata olahraga dan rekreasi melalui Jogging Track Tegeh Aban, Karang Gadon, dan Munduk Uma Desa. Jalur jogging ini tidak hanya menjadi fasilitas olahraga bagi warga, tetapi juga berpotensi dikembangkan sebagai destinasi wisata sehat berbasis alam yang menarik bagi wisatawan lokal maupun luar daerah.</p><p>Potensi dan Peran Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma Desa:</p><ol><li><p><strong>Keindahan Alam dan Udara Segar:</strong></p><p>Jogging track yang membentang di Tegeh Aban, Karang Gadon, dan Munduk Uma Desa menawarkan pemandangan alam yang asri dengan udara segar khas pedesaan. Jalur ini melewati area persawahan hijau, perkebunan, serta hutan kecil yang memberikan pengalaman jogging yang lebih menyenangkan dan menenangkan.</p></li><li><p><strong>Fasilitas Olahraga dan Rekreasi</strong></p><p>Selain untuk jogging, jalur ini juga cocok digunakan untuk:</p><p>- Bersepeda santai : Jalur yang nyaman untuk pecinta sepeda.</p><p>- Trekking ringan : Cocok bagi wisatawan yang ingin menikmati suasana pedesaan.</p><p>- Meditasi dan Yoga : Area yang tenang dan alami, ideal untuk relaksasi.</p></li><li><p><strong>Destinasi Wisata Sehat dan Edukasi:</strong></p><p>Jogging track ini berpotensi dikembangkan sebagai wisata sehat berbasis alam, di mana pengunjung bisa menikmati udara segar sambil berolahraga. Selain itu, jalur ini dapat dijadikan sebagai rute edukasi lingkungan, mengenalkan keanekaragaman hayati, pertanian, serta kehidupan masyarakat desa.</p></li><li><p><strong>Potensi Ekonomi bagi Masyarakat</strong></p><p>Dengan meningkatnya jumlah pengunjung, masyarakat sekitar dapat memanfaatkan peluang usaha seperti:</p><p>- Warung sehat dan kuliner lokal : Menyediakan makanan dan minuman sehat bagi para pengunjung.</p><p>- Jasa penyewaan sepeda : Menarik bagi wisatawan yang ingin berkeliling lebih jauh.</p><p>- Pemandu wisata lokal : Memberikan pengalaman lebih bagi wisatawan yang ingin mengenal sejarah dan budaya desa.</p></li><li><p><strong>Pengembangan Berkelanjutan:</strong></p><p>Agar semakin menarik, jogging track ini bisa dilengkapi dengan fasilitas tambahan seperti tempat istirahat, spot foto alami, papan informasi tentang flora dan fauna, serta area taman bunga untuk mempercantik jalur jogging.</p></li></ol><p>Jogging Track Tegeh Aban, Karang Gadon, dan Munduk Uma Desa memiliki potensi besar sebagai destinasi wisata sehat dan olahraga berbasis alam. Dengan pengelolaan yang baik serta dukungan dari pemerintah desa dan masyarakat, jalur ini bisa menjadi ikon baru Desa Darmasaba yang menarik bagi wisatawan serta meningkatkan perekonomian warga setempat.</p>"
},
{
"id": "cmdykr76v000jvn6fqngibbmq",
"id": "cmk3t8hgs000vvn9bna6pnw8r",
"name": "Dam Tanah Putih",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi wisata olahraga dan rekreasi melalui Jogging Track Tegeh Aban, Karang Gadon, dan Munduk Uma Desa. Jalur jogging ini tidak hanya menjadi fasilitas olahraga bagi warga, tetapi juga berpotensi dikembangkan sebagai destinasi wisata sehat berbasis alam yang menarik bagi wisatawan lokal maupun luar daerah.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki Dam Tanah Putih sebagai salah satu potensi desa yang bernilai strategis. Selain berfungsi sebagai infrastruktur pengairan, dam ini juga memiliki potensi untuk dikembangkan sebagai destinasi wisata alam, edukasi, dan rekreasi bagi masyarakat lokal maupun wisatawan.</p><p>Potensi dan Peran Dam Tanah Putih:</p><ol><li><p><strong>Fungsi Utama Sebagai Sumber Pengairan</strong></p><p>Dam Tanah Putih memiliki peran penting dalam sistem irigasi yang menopang sektor pertanian di Darmasaba. Air dari dam ini digunakan untuk:</p><p>- Mengairi sawah dan ladang : Menjamin ketersediaan air bagi petani sepanjang tahun.</p><p>- Menjaga keseimbangan ekosistem : Menjadi habitat bagi ikan air tawar dan berbagai biota air.</p><p>- Menampung air hujan : Membantu mengurangi risiko banjir dan kekeringan.</p></li><li><p><strong>Potensi Wisata Alam dan Rekreasi</strong></p><p>Dengan pemandangan alam yang asri dan suasana yang sejuk, Dam Tanah Putih memiliki potensi besar untuk dikembangkan sebagai tempat wisata alam. Beberapa kegiatan yang bisa dikembangkan di area ini antara lain:</p><p>- Trekking dan jogging di sekitar dam : Menikmati udara segar dan pemandangan indah.</p><p>- Berkemah dan piknik : Cocok untuk keluarga dan komunitas yang ingin menikmati alam.</p><p>- Wisata air : Seperti pemancingan atau wisata perahu kecil yang dapat menarik wisatawan.</p><p>- Spot fotografi alam : Keindahan dam dan sekitarnya menjadi latar yang menarik bagi para fotografer.</p></li><li><p><strong>Potensi Ekonomi dan UMKM Lokal</strong></p><p>Dengan pengembangan dam sebagai destinasi wisata, masyarakat sekitar dapat memanfaatkan peluang usaha seperti:</p><p>- Warung makan dan jajanan tradisional : Menyediakan makanan khas Bali bagi wisatawan.</p><p>- Jasa penyewaan alat rekreasi : Seperti pancing atau perahu kecil.</p><p>- Produk kerajinan tangan dan suvenir : Oleh-oleh khas Darmasaba yang menarik bagi pengunjung.</p></li><li><p><strong>Pengembangan Konservasi dan Edukasi Lingkungan</strong></p><p>Dam Tanah Putih juga bisa menjadi tempat edukasi lingkungan dengan konsep konservasi, di mana pengunjung bisa belajar tentang:</p><p>- Pengelolaan sumber daya air yang berkelanjutan.</p><p>- Keanekaragaman hayati di sekitar dam.</p><p>- Pentingnya ekosistem perairan bagi pertanian dan kehidupan masyarakat.</p></li></ol><p>Dengan berbagai fungsi dan keindahannya, Dam Tanah Putih memiliki potensi besar untuk dikembangkan sebagai destinasi wisata alam, rekreasi, serta edukasi lingkungan. Dengan pengelolaan yang baik dan dukungan dari masyarakat serta pemerintah desa, dam ini dapat menjadi aset penting bagi Darmasaba, baik dari sisi ekonomi maupun kelestarian lingkungan.</p>"
"deskripsi": "<p>Bendungan lokal yang berfungsi sebagai sumber irigasi pertanian.</p>",
"content": "<p>Dam Tanah Putih merupakan bendungan yang mendukung pengairan sawah dan lahan pertanian di Desa Darmasaba, yang membantu peningkatan produktivitas pertanian masyarakat setempat.</p>",
"kategoriId": "cmk3pmwq10008vn9bqdquv153",
"imageName": "84pnYeV2_9f4xplh9RBXW-mobile.webp"
},
{
"id": "cmdyku9qh000mvn6ft76322sv",
"id": "cmk3tlrkb000yvn9bo1vse4c5",
"name": "UMKM",
"deskripsi": "Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam sektor Usaha Mikro, Kecil, dan Menengah (UMKM). Keberadaan UMKM di desa ini tidak hanya menjadi motor penggerak ekonomi lokal, tetapi juga mendukung pelestarian budaya dan kearifan lokal melalui berbagai produk unggulan.",
"content": "<p>Desa Darmasaba, yang terletak di Kecamatan Abiansemal, Kabupaten Badung, memiliki potensi besar dalam sektor Usaha Mikro, Kecil, dan Menengah (UMKM). Keberadaan UMKM di desa ini tidak hanya menjadi motor penggerak ekonomi lokal, tetapi juga mendukung pelestarian budaya dan kearifan lokal melalui berbagai produk unggulan.</p><p>Potensi dan Peran UMKM:</p><ol><li><p><strong>Kerajinan Tangan dan Produk Lokal</strong></p><p>Darmasaba memiliki banyak pengrajin yang menghasilkan produk unik dengan nilai seni tinggi, seperti:</p><p>- Genteng dan bahan bangunan tradisional : Genteng khas Darmasaba yang berkualitas tinggi.</p><p>- Kerajinan anyaman dan ukiran : Produk berbasis rotan dan kayu yang banyak diminati pasar lokal dan internasional.</p><p>- Pakaian adat dan kain tradisional : Mendukung pelestarian budaya Bali.</p></li><li><p><strong>Industri Kuliner Khas Darmasaba</strong></p><p>Kuliner khas desa ini memiliki potensi besar untuk dikembangkan sebagai bisnis UMKM, seperti:</p><p>- Babi Guling : Salah satu kuliner favorit yang banyak diminati wisatawan.</p><p>- Jajanan tradisional Bali : Seperti laklak, jaja uli, dan klepon yang masih dibuat dengan cara tradisional.</p><p>- Olahan ikan lele : Seperti abon lele, lele asap, dan pecel lele yang memiliki pasar luas.</p></li><li><p><strong>UMKM Berbasis Pengolahan Pangan</strong></p><p>Beberapa UMKM di Darmasaba mengolah hasil pertanian dan peternakan menjadi produk bernilai tambah, seperti:</p><p>- Keripik singkong dan pisang : Camilan sehat berbasis bahan lokal.</p><p>- Olahan kelapa : Seperti minyak kelapa murni dan gula aren.</p><p>- Produk herbal dan jamu : Menggunakan bahan-bahan alami dari tanaman lokal.</p></li><li><p><strong>Dukungan dan Pengembangan UMKM</strong></p><p>Agar UMKM di Darmasaba semakin berkembang, perlu adanya:</p><p>- Pelatihan dan pendampingan usaha : Untuk meningkatkan kualitas produk dan manajemen usaha.</p><p>- Pemasaran digital : Menggunakan media sosial dan e-commerce untuk menjangkau pasar lebih luas.</p><p>- Kerja sama dengan BUMDes Pudak Mesari : Untuk membantu akses modal dan pengelolaan bisnis yang lebih profesional.</p></li></ol><p>UMKM di Desa Darmasaba memiliki potensi besar dalam berbagai sektor, mulai dari kerajinan tangan, kuliner, hingga wisata berbasis masyarakat. Dengan inovasi, pemasaran yang lebih luas, dan dukungan dari pemerintah desa serta masyarakat, UMKM Darmasaba dapat berkembang pesat dan menjadi tulang punggung perekonomian desa.</p>"
"deskripsi": "<p>Usaha mikro, kecil, dan menengah masyarakat Desa Darmasaba.</p>",
"content": "<p>UMKM di Darmasaba mencakup berbagai usaha kecil produktif seperti kuliner, kerajinan tangan, dan jasa lainnya, yang menjadi pilar kegiatan ekonomi dan pemberdayaan masyarakat lokal.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "5VSeupjyjtam02PNJW3ZG-mobile.webp"
},
{
"id": "cmk3tzpku0011vn9beq2kzyen",
"name": "Kawasan Kuliner",
"deskripsi": "<p>Wilayah yang menyediakan berbagai pilihan kuliner khas lokal Desa Darmasaba.</p>",
"content": "<p>Kawasan kuliner di Darmasaba menjadi tempat berkumpul dan menikmati makanan khas lokal, mendukung kegiatan ekonomi UMKM kuliner desa serta daya tarik wisata kuliner.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "gjwx1dcHKMJEICbLF6g88-mobile.webp"
},
{
"id": "cmk3u7gzh0014vn9brvlz3fjp",
"name": "IKM berbasis Pengolahan Pangan",
"deskripsi": "<p>Industri kecil menengah yang fokus pada pengolahan produk pangan lokal.</p>",
"content": "<p>IKM berbasis pengolahan pangan di desa mencakup produksi makanan olahan yang dihasilkan oleh masyarakat setempat, memperkaya nilai tambah hasil pertanian lokal dan menciptakan peluang bisnis.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "j3q1NLvwPFrxAmgMXBmq2-mobile.webp"
},
{
"id": "cmk3udr960017vn9bq33ce6mw",
"name": "Peternakan Ikan Lele",
"deskripsi": "<p>Usaha budidaya ikan lele sebagai potensi perikanan desa.</p>",
"content": "<p>Peternakan ikan lele menjadi salah satu bentuk usaha budidaya perikanan di Darmasaba, memberikan sumber pendapatan tambahan bagi petani ikan dan diversifikasi komoditas desa.</p>",
"kategoriId": "cmk3s1ks6000ivn9bcrv960ko",
"imageName": "eZCq49lXnx6zKslb6hLxz-mobile.webp"
}
]

View File

@@ -1,9 +1,10 @@
[
{
"id": "edit",
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
"pengalaman": "<ul><li>2021 - 2027: Perbekel Desa Darmasaba</li><li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li><li>2020 - Sekarang: Founder Ugawa Record Music Studio</li><li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li></ul>",
"pengalamanOrganisasi": "<ul> <li>1996 1997: Ketua OSIS SMP Negeri 1 Abiansemal</li><li>1999 2000: Ketua OSIS SMA Negeri 1 Mengwi</li> <li>2008 2009: Ketua BEM Universitas Mahasaraswati Denpasar</li> <li>2008 2010: Ketua Sekaa Taruna Sila Dharma, Banjar Tengah, Desa Adat Tegal, Darmasaba</li> <li>2020 Sekarang: Pengurus Young Lawyer Committee Peradi Denpasar</li> <li>2021 Sekarang: Dewan Kehormatan Himpunan Pengusaha Muda Indonesia (HIPMI) Badung</li> <li>2023 2028: Komite Tetap Advokasi Bidang Hukum dan Regulasi Kamar Dagang dan Industri Badung</li> </ul>",
"programUnggulan": "<h3>Pemberdayaan Ekonomi dan UMKM</h3> <ul> <li>Pelatihan dan pendampingan UMKM lokal</li> <li>Program bantuan modal usaha bagi pelaku usaha kecil</li><li>Digitalisasi UMKM untuk meningkatkan pemasaran produk lokal</li></ul>"
}
]
{
"id": "edit",
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
"pengalaman": "<ul><li>2021 - 2027: Perbekel Desa Darmasaba</li><li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li><li>2020 - Sekarang: Founder Ugawa Record Music Studio</li><li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li></ul>",
"pengalamanOrganisasi": "<ul> <li>1996 1997: Ketua OSIS SMP Negeri 1 Abiansemal</li><li>1999 2000: Ketua OSIS SMA Negeri 1 Mengwi</li> <li>2008 2009: Ketua BEM Universitas Mahasaraswati Denpasar</li> <li>2008 2010: Ketua Sekaa Taruna Sila Dharma, Banjar Tengah, Desa Adat Tegal, Darmasaba</li> <li>2020 Sekarang: Pengurus Young Lawyer Committee Peradi Denpasar</li> <li>2021 Sekarang: Dewan Kehormatan Himpunan Pengusaha Muda Indonesia (HIPMI) Badung</li> <li>2023 2028: Komite Tetap Advokasi Bidang Hukum dan Regulasi Kamar Dagang dan Industri Badung</li> </ul>",
"programUnggulan": "<h3>Pemberdayaan Ekonomi dan UMKM</h3> <ul> <li>Pelatihan dan pendampingan UMKM lokal</li> <li>Program bantuan modal usaha bagi pelaku usaha kecil</li><li>Digitalisasi UMKM untuk meningkatkan pemasaran produk lokal</li></ul>",
"imageName": "perbekel-profile-desa.webp"
}
]

Some files were not shown because too many files have changed in this diff Show More