Files
monitoring-app/docs/CONVENTIONS.md
amaliadwiy 7808de0db3 docs: split CLAUDE.md into focused reference files
Move Common Commands to docs/COMMANDS.md and add docs/CONVENTIONS.md
for frontend patterns (SWR, filters, Mantine, routing, API URLs).
CLAUDE.md now only contains runtime rules and pointers.
2026-05-22 12:08:39 +08:00

2.5 KiB

Frontend Conventions

Data Fetching

  • SWR for read-only data in route components (tables, lists, charts).
  • TanStack Query (useQuery, useMutation) for auth state — see src/frontend/hooks/useAuth.ts.
  • Never mix both in the same component/page.
  • Debounce search inputs: useDebouncedValue(search, 400) + useEffect that only triggers when length >= 3 or === 0.

API URL Builder

All URLs go through src/frontend/config/api.tsAPI_URLS. Add new entries there, never inline URLs in components.

Desa+ endpoints are proxied via /api/proxy/desa-plusDESA_PLUS_PROXY constant. The actual API source is at: /Users/wibu04/Documents/Projects/sistem-desa-mandiri/src/app/api/monitoring/[[...slug]]/route.ts

Filters & Pagination Pattern

Server-side filtering — always pass filter params to the API, never filter client-side on paginated data.

State pattern for a filtered table page:

const [page, setPage] = useState(1)
const [search, setSearch] = useState('')          // raw input
const [searchQuery, setSearchQuery] = useState('') // debounced, sent to API
const [debouncedSearch] = useDebouncedValue(search, 400)

useEffect(() => {
  if (debouncedSearch.length >= 3 || debouncedSearch.length === 0) {
    setSearchQuery(debouncedSearch)
    setPage(1)
  }
}, [debouncedSearch])

useEffect(() => { setPage(1) }, [filterA, filterB]) // reset page on filter change

Mantine Components

  • Dark theme forced (#242424). Never add light-mode conditionals.
  • radius="md" on inputs, radius="2xl" on container Paper.
  • className="glass" on Paper cards for the frosted glass effect.
  • size="sm" on table inputs and selects.
  • Icons from react-icons/tb only — no other icon libraries.
  • DatePickerInput from @mantine/dates with type="range" returns [string | null, string | null], not Date objects.

Route Files

File-based routing via TanStack Router Vite plugin. Files in src/frontend/routes/:

Pattern Route
apps.$appId.tsx Layout wrapper for per-app pages
apps.$appId.index.tsx Overview/dashboard for an app
apps.$appId.users.index.tsx User management
apps.$appId.logs.tsx Activity logs
apps.$appId.villages.tsx Villages layout
apps.$appId.villages.index.tsx Village list
apps.$appId.villages.$villageId.tsx Village detail

routeTree.gen.ts is auto-generated — never edit it manually.

App Registration

App configs (ID, menu items) live in src/frontend/config/appMenus.ts. Add new apps there to register them. Currently active app: desa-plus.