chore(WEB): package-lock.json git 트래킹 제거
- .gitignore에 이미 등록되어 있으나 과거 커밋으로 트래킹 중이던 파일 제거 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,606 @@
|
||||
# Research: Next.js / React ERP & Admin Panel Architecture Patterns (2025-2026)
|
||||
|
||||
**Date**: 2026-02-11
|
||||
**Purpose**: Compare SAM ERP's current architecture against proven open-source patterns
|
||||
**Confidence**: High (0.85) - Based on 6 major open-source projects and established methodologies
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
After investigating 6 major open-source admin/ERP frameworks and 3 architectural methodologies, the dominant pattern emerging in 2025-2026 is a **hybrid approach**: domain/feature-based folder organization combined with headless CRUD hooks and a provider-based API abstraction layer. Pure Atomic Design is losing ground to Feature-Sliced Design (FSD) for application-level organization, though Atomic Design remains useful for the shared UI component layer.
|
||||
|
||||
### Key Findings
|
||||
|
||||
1. **Resource-based CRUD abstraction** (react-admin, Refine) is the most proven pattern for 50+ page admin apps
|
||||
2. **Feature/domain-based folder structure** is winning over layer-based (atoms/molecules/organisms) for application code
|
||||
3. **Provider pattern** (dataProvider, authProvider) decouples UI from API more effectively than scattered Server Actions
|
||||
4. **Config-driven UI generation** (Payload CMS) reduces code duplication for similar pages
|
||||
5. **Headless hooks** (useListController, useTable, useForm) separate business logic from UI completely
|
||||
|
||||
---
|
||||
|
||||
## 1. Project-by-Project Architecture Analysis
|
||||
|
||||
### 1.1 React-Admin (marmelab) -- 25K+ GitHub Stars
|
||||
|
||||
**Architecture**: Resource-based SPA with Provider pattern
|
||||
|
||||
**Key Concepts**:
|
||||
- **Resources**: The core abstraction. Each entity (posts, users, orders) is a "resource" with CRUD views
|
||||
- **Providers**: Adapter layer between UI and backend
|
||||
- `dataProvider` - abstracts all API calls (getList, getOne, create, update, delete)
|
||||
- `authProvider` - handles authentication flow
|
||||
- `i18nProvider` - internationalization
|
||||
- **Headless Core**: `ra-core` package contains all hooks, zero UI dependency
|
||||
- **Controller Hooks**: `useListController`, `useEditController`, `useCreateController`, `useShowController`
|
||||
|
||||
**Folder Pattern**:
|
||||
```
|
||||
src/
|
||||
resources/
|
||||
posts/
|
||||
PostList.tsx # <List> view
|
||||
PostEdit.tsx # <Edit> view
|
||||
PostCreate.tsx # <Create> view
|
||||
PostShow.tsx # <Show> view
|
||||
users/
|
||||
UserList.tsx
|
||||
UserEdit.tsx
|
||||
providers/
|
||||
dataProvider.ts # API abstraction
|
||||
authProvider.ts # Auth abstraction
|
||||
App.tsx # Resource registration
|
||||
```
|
||||
|
||||
**CRUD Registration Pattern**:
|
||||
```tsx
|
||||
<Admin dataProvider={dataProvider} authProvider={authProvider}>
|
||||
<Resource name="posts" list={PostList} edit={PostEdit} create={PostCreate} />
|
||||
<Resource name="users" list={UserList} edit={UserEdit} />
|
||||
</Admin>
|
||||
```
|
||||
|
||||
**SAM Comparison**:
|
||||
| Aspect | react-admin | SAM ERP |
|
||||
|--------|-------------|---------|
|
||||
| API Layer | Centralized dataProvider | 89 scattered actions.ts files |
|
||||
| CRUD Views | Resource-based registration | Manual page creation per domain |
|
||||
| State | React Query (built-in) | Zustand + manual fetching |
|
||||
| Form | react-hook-form (built-in) | Mixed (migrating to RHF+Zod) |
|
||||
|
||||
**Sources**:
|
||||
- [Architecture Docs](https://marmelab.com/react-admin/Architecture.html)
|
||||
- [Resource Component](https://marmelab.com/react-admin/Resource.html)
|
||||
- [CRUD Pages](https://marmelab.com/react-admin/CRUD.html)
|
||||
- [GitHub](https://github.com/marmelab/react-admin)
|
||||
|
||||
---
|
||||
|
||||
### 1.2 Refine -- 30K+ GitHub Stars
|
||||
|
||||
**Architecture**: Headless meta-framework with resource-based CRUD
|
||||
|
||||
**Key Concepts**:
|
||||
- **Headless by design**: Zero UI opinion, works with Ant Design, Material UI, Shadcn, or custom
|
||||
- **Data Provider Interface**: Standardized CRUD methods (getList, getOne, create, update, deleteOne)
|
||||
- **Resource Hooks**: `useTable`, `useForm`, `useShow`, `useSelect` -- all headless
|
||||
- **Inferencer**: Auto-generates CRUD pages from API schema
|
||||
|
||||
**Data Provider Interface**:
|
||||
```typescript
|
||||
const dataProvider = {
|
||||
getList: ({ resource, pagination, sorters, filters }) => Promise,
|
||||
getOne: ({ resource, id }) => Promise,
|
||||
create: ({ resource, variables }) => Promise,
|
||||
update: ({ resource, id, variables }) => Promise,
|
||||
deleteOne: ({ resource, id }) => Promise,
|
||||
getMany: ({ resource, ids }) => Promise,
|
||||
custom: ({ url, method, payload }) => Promise,
|
||||
};
|
||||
```
|
||||
|
||||
**Headless Hook Pattern**:
|
||||
```tsx
|
||||
// useTable returns data + controls, you handle UI
|
||||
const { tableProps, sorters, filters } = useTable({ resource: "products" });
|
||||
|
||||
// useForm returns form state + submit, you handle UI
|
||||
const { formProps, saveButtonProps } = useForm({ resource: "products", action: "create" });
|
||||
```
|
||||
|
||||
**SAM Comparison**:
|
||||
| Aspect | Refine | SAM ERP |
|
||||
|--------|--------|---------|
|
||||
| API Abstraction | Single dataProvider | Per-domain actions.ts |
|
||||
| List Page | useTable hook | UniversalListPage template |
|
||||
| Form | useForm hook (headless) | Manual per-page forms |
|
||||
| Code Generation | Inferencer auto-gen | Manual creation |
|
||||
|
||||
**Sources**:
|
||||
- [Data Provider Docs](https://refine.dev/docs/data/data-provider/)
|
||||
- [useTable Hook](https://refine.dev/docs/data/hooks/use-table/)
|
||||
- [GitHub](https://github.com/refinedev/refine)
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Payload CMS 3.0 -- 30K+ GitHub Stars
|
||||
|
||||
**Architecture**: Config-driven, Next.js-native with auto-generated admin UI
|
||||
|
||||
**Key Concepts**:
|
||||
- **Collection Config**: Define schema once, get admin UI + API + types automatically
|
||||
- **Field System**: Rich field types auto-generate corresponding UI components
|
||||
- **Hooks**: beforeChange, afterRead, beforeValidate at collection and field level
|
||||
- **Access Control**: Document-level and field-level permissions in config
|
||||
- **Next.js Native**: Installs directly into /app folder, uses Server Components
|
||||
|
||||
**Config-Driven Pattern**:
|
||||
```typescript
|
||||
// collections/Products.ts
|
||||
export const Products: CollectionConfig = {
|
||||
slug: 'products',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
defaultColumns: ['name', 'price', 'status'],
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
create: isAdmin,
|
||||
update: isAdminOrSelf,
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [calculateTotal],
|
||||
afterRead: [formatCurrency],
|
||||
},
|
||||
fields: [
|
||||
{ name: 'name', type: 'text', required: true },
|
||||
{ name: 'price', type: 'number', min: 0 },
|
||||
{ name: 'status', type: 'select', options: ['draft', 'published'] },
|
||||
{ name: 'category', type: 'relationship', relationTo: 'categories' },
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
**SAM Comparison**:
|
||||
| Aspect | Payload CMS | SAM ERP |
|
||||
|--------|-------------|---------|
|
||||
| Page Generation | Auto from config | Manual per page |
|
||||
| Field Definitions | Centralized schema | Inline JSX per form |
|
||||
| Access Control | Config-based per field | Manual per component |
|
||||
| Type Safety | Auto-generated from schema | Manual interface definitions |
|
||||
|
||||
**Sources**:
|
||||
- [Collection Configs](https://payloadcms.com/docs/configuration/collections)
|
||||
- [Fields Overview](https://payloadcms.com/docs/fields/overview)
|
||||
- [Collection Hooks](https://payloadcms.com/docs/hooks/collections)
|
||||
- [GitHub](https://github.com/payloadcms/payload)
|
||||
|
||||
---
|
||||
|
||||
### 1.4 Medusa Admin v2 -- 26K+ GitHub Stars
|
||||
|
||||
**Architecture**: Domain-based routes with widget injection system
|
||||
|
||||
**Key Concepts**:
|
||||
- **Domain Routes**: Routes organized by business domain (products, orders, customers)
|
||||
- **Widget System**: Inject custom React components into predetermined zones
|
||||
- **UI Routes**: File-based routing under src/admin/routes/
|
||||
- **Hook-based data fetching**: Domain-specific hooks for API integration
|
||||
- **Monorepo**: UI library (@medusajs/ui) separate from admin logic
|
||||
|
||||
**Folder Structure**:
|
||||
```
|
||||
packages/admin/dashboard/src/
|
||||
routes/
|
||||
products/
|
||||
product-list/
|
||||
components/
|
||||
hooks/
|
||||
page.tsx
|
||||
product-detail/
|
||||
components/
|
||||
hooks/
|
||||
page.tsx
|
||||
orders/
|
||||
order-list/
|
||||
order-detail/
|
||||
customers/
|
||||
hooks/ # Shared hooks
|
||||
components/ # Shared components
|
||||
lib/ # Utilities
|
||||
```
|
||||
|
||||
**SAM Comparison**:
|
||||
| Aspect | Medusa Admin | SAM ERP |
|
||||
|--------|-------------|---------|
|
||||
| Route Organization | Domain > Action > Components | Domain > page.tsx + actions.ts |
|
||||
| Shared Components | Separate UI package | organisms/molecules/atoms |
|
||||
| Hooks | Per-route + shared | Global + inline |
|
||||
| Extensibility | Widget injection zones | N/A |
|
||||
|
||||
**Sources**:
|
||||
- [Admin UI Routes](https://docs.medusajs.com/learn/fundamentals/admin/ui-routes)
|
||||
- [Admin Development](https://docs.medusajs.com/learn/fundamentals/admin)
|
||||
- [GitHub](https://github.com/medusajs/medusa)
|
||||
|
||||
---
|
||||
|
||||
### 1.5 AdminJS
|
||||
|
||||
**Architecture**: Auto-generated admin from resource configuration
|
||||
|
||||
**Key Concepts**:
|
||||
- **Resource Registration**: Register database models, get admin UI automatically
|
||||
- **Component Customization**: Override via ComponentLoader
|
||||
- **Dashboard Customization**: Custom React components for dashboard
|
||||
|
||||
**SAM Relevance**: Lower -- AdminJS is more backend-driven (Node.js ORM-based) and less applicable to a frontend-heavy ERP.
|
||||
|
||||
**Sources**:
|
||||
- [AdminJS Documentation](https://adminjs.co/)
|
||||
- [GitHub](https://github.com/SoftwareBrothers/adminjs)
|
||||
|
||||
---
|
||||
|
||||
### 1.6 Hoppscotch
|
||||
|
||||
**Architecture**: Monorepo with shared-library pattern
|
||||
|
||||
**Key Concepts**:
|
||||
- **@hoppscotch/common**: 90% of UI and business logic in shared package
|
||||
- **@hoppscotch/data**: Type safety across all layers
|
||||
- **Platform-specific code**: Thin wrapper handling native capabilities
|
||||
|
||||
**SAM Relevance**: The shared-library-as-core pattern is interesting for large codebases where most logic is platform-agnostic.
|
||||
|
||||
**Sources**:
|
||||
- [DeepWiki Analysis](https://deepwiki.com/hoppscotch/hoppscotch)
|
||||
|
||||
---
|
||||
|
||||
## 2. Architectural Methodologies Comparison
|
||||
|
||||
### 2.1 Feature-Sliced Design (FSD) -- Rising Standard
|
||||
|
||||
**7-Layer Architecture**:
|
||||
```
|
||||
app/ # App initialization, providers, routing
|
||||
processes/ # Complex cross-page business flows (deprecated in latest)
|
||||
pages/ # Full page compositions
|
||||
widgets/ # Self-contained UI blocks with business logic
|
||||
features/ # User-facing actions (login, add-to-cart)
|
||||
entities/ # Business entities (user, product, order)
|
||||
shared/ # Reusable utilities, UI kit, configs
|
||||
```
|
||||
|
||||
**Key Rules**:
|
||||
- Layers can ONLY import from layers below them
|
||||
- Each layer divided into **slices** (domain groupings)
|
||||
- Each slice divided into **segments** (ui/, model/, api/, lib/, config/)
|
||||
|
||||
**FSD Applied to ERP**:
|
||||
```
|
||||
src/
|
||||
app/ # App shell, providers
|
||||
pages/
|
||||
quality-qms/ # QMS page composition
|
||||
sales-quote/ # Quote page composition
|
||||
widgets/
|
||||
inspection-report/ # Self-contained inspection UI
|
||||
ui/
|
||||
model/
|
||||
api/
|
||||
quote-calculator/
|
||||
features/
|
||||
add-inspection-item/
|
||||
approve-quote/
|
||||
entities/
|
||||
inspection/
|
||||
ui/ (InspectionCard, InspectionRow)
|
||||
model/ (types, store)
|
||||
api/ (getInspection, updateInspection)
|
||||
quote/
|
||||
ui/
|
||||
model/
|
||||
api/
|
||||
shared/
|
||||
ui/ (Button, Table, Modal -- your atoms)
|
||||
lib/ (formatDate, exportUtils)
|
||||
api/ (httpClient, apiProxy)
|
||||
config/ (constants)
|
||||
```
|
||||
|
||||
**Sources**:
|
||||
- [Feature-Sliced Design](https://feature-sliced.design/)
|
||||
- [Layers Reference](https://feature-sliced.design/docs/reference/layers)
|
||||
- [Slices and Segments](https://feature-sliced.design/docs/reference/slices-segments)
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Atomic Design -- Aging for App-Level Organization
|
||||
|
||||
**SAM's Current Approach**:
|
||||
```
|
||||
components/
|
||||
atoms/ # Basic UI elements
|
||||
molecules/ # (unused)
|
||||
organisms/ # Complex composed components
|
||||
templates/ # Page layout templates
|
||||
```
|
||||
|
||||
**Industry Assessment (2025-2026)**:
|
||||
- Atomic Design excels for **UI component libraries** (shared/ layer)
|
||||
- Struggles with **domain complexity** -- "UserCard" and "ProductCard" are both organisms but semantically distinct
|
||||
- Grouping by visual complexity (atom/molecule/organism) dilutes domain boundaries
|
||||
- Most large-scale projects have moved to **feature/domain organization** for application code
|
||||
- Atomic Design remains valuable for the **shared UI kit layer only**
|
||||
|
||||
**Sources**:
|
||||
- [Atomic Design Meets Feature-Based Architecture](https://medium.com/@buwanekasumanasekara/atomic-design-meets-feature-based-architecture-in-next-js-a-practical-guide-c06ea56cf5cc)
|
||||
- [From Components to Systems](https://www.codewithseb.com/blog/from-components-to-systems-scalable-frontend-with-atomiec-design)
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Modular Monolith (Frontend)
|
||||
|
||||
**Key Principles for ERP**:
|
||||
- Single deployment, but internally organized as independent modules
|
||||
- Each module = bounded context with clear API boundaries
|
||||
- Modules communicate through well-defined interfaces, not direct imports
|
||||
- Common concerns (auth, logging) handled at application level
|
||||
|
||||
**Applied to Next.js ERP**:
|
||||
```
|
||||
src/
|
||||
modules/
|
||||
quality/
|
||||
components/
|
||||
hooks/
|
||||
actions/
|
||||
types/
|
||||
index.ts # Public API -- only exports from here
|
||||
sales/
|
||||
components/
|
||||
hooks/
|
||||
actions/
|
||||
types/
|
||||
index.ts
|
||||
accounting/
|
||||
...
|
||||
shared/ # Cross-module utilities
|
||||
app/ # Next.js routing (thin layer)
|
||||
```
|
||||
|
||||
**Sources**:
|
||||
- [Modular Monolith Revolution](https://medium.com/@bhargavkoya56/the-modular-monolith-revolution-enterprise-grade-architecture-part-i-theory-b3705ca70a5f)
|
||||
- [Frontend at Scale](https://frontendatscale.com/issues/45/)
|
||||
|
||||
---
|
||||
|
||||
## 3. Server Actions Organization Patterns
|
||||
|
||||
### Pattern A: Colocated (SAM's Current -- 89 files)
|
||||
```
|
||||
app/[locale]/(protected)/quality/qms/
|
||||
page.tsx
|
||||
actions.ts # Server actions for this route
|
||||
```
|
||||
**Pros**: Easy to find, clear ownership
|
||||
**Cons**: Duplication across similar pages, no reuse
|
||||
|
||||
### Pattern B: Domain-Centralized (react-admin / Refine style)
|
||||
```
|
||||
src/
|
||||
actions/
|
||||
quality/
|
||||
inspection.ts # All inspection-related server actions
|
||||
qms.ts
|
||||
sales/
|
||||
quote.ts
|
||||
order.ts
|
||||
lib/
|
||||
api-client.ts # Shared fetch logic with auth
|
||||
```
|
||||
**Pros**: Reusable across pages, easier to maintain
|
||||
**Cons**: Indirection, harder to find for route-specific logic
|
||||
|
||||
### Pattern C: Hybrid (Recommended for large apps)
|
||||
```
|
||||
app/[locale]/(protected)/quality/qms/
|
||||
page.tsx
|
||||
_actions.ts # Route-specific actions only
|
||||
|
||||
src/
|
||||
domains/
|
||||
quality/
|
||||
actions/ # Shared domain actions
|
||||
inspection.ts
|
||||
qms.ts
|
||||
hooks/
|
||||
types/
|
||||
```
|
||||
**Pros**: Route-specific stays colocated, shared logic centralized
|
||||
**Cons**: Need clear rules on what goes where
|
||||
|
||||
### Industry Consensus
|
||||
For 100+ page apps, the **hybrid approach** (Pattern C) dominates. Route-specific logic stays colocated; shared domain logic is centralized. The key is having a clear **data provider / API client** layer that all server actions delegate to.
|
||||
|
||||
**Sources**:
|
||||
- [Next.js Colocation Template](https://next-colocation-template.vercel.app/)
|
||||
- [Inside the App Router (2025)](https://medium.com/better-dev-nextjs-react/inside-the-app-router-best-practices-for-next-js-file-and-directory-structure-2025-edition-ed6bc14a8da3)
|
||||
|
||||
---
|
||||
|
||||
## 4. CRUD Abstraction Patterns for 50+ Similar Pages
|
||||
|
||||
### Pattern 1: Resource Hooks (react-admin / Refine approach)
|
||||
```typescript
|
||||
// hooks/useResourceList.ts
|
||||
function useResourceList<T>(resource: string, options?: ListOptions) {
|
||||
const [data, setData] = useState<T[]>([]);
|
||||
const [pagination, setPagination] = useState({ page: 1, pageSize: 20 });
|
||||
const [filters, setFilters] = useState({});
|
||||
const [sorters, setSorters] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
fetchList(resource, { pagination, filters, sorters })
|
||||
.then(result => setData(result.data));
|
||||
}, [resource, pagination, filters, sorters]);
|
||||
|
||||
return { data, pagination, setPagination, filters, setFilters, sorters, setSorters };
|
||||
}
|
||||
|
||||
// Usage in any list page
|
||||
function QualityInspectionList() {
|
||||
const { data, pagination, filters } = useResourceList<Inspection>('quality/inspections');
|
||||
return <UniversalListPage data={data} columns={inspectionColumns} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Config-Driven Pages (Payload CMS approach)
|
||||
```typescript
|
||||
// configs/quality-inspection.config.ts
|
||||
export const inspectionConfig: ResourceConfig = {
|
||||
resource: 'quality/inspections',
|
||||
list: {
|
||||
columns: [
|
||||
{ key: 'id', label: '번호' },
|
||||
{ key: 'name', label: '검사명' },
|
||||
{ key: 'status', label: '상태', render: StatusBadge },
|
||||
],
|
||||
filters: [
|
||||
{ key: 'status', type: 'select', options: statusOptions },
|
||||
{ key: 'dateRange', type: 'daterange' },
|
||||
],
|
||||
defaultSort: { key: 'createdAt', direction: 'desc' },
|
||||
},
|
||||
form: {
|
||||
fields: [
|
||||
{ name: 'name', type: 'text', required: true, label: '검사명' },
|
||||
{ name: 'type', type: 'select', options: typeOptions, label: '검사유형' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// Generic page component
|
||||
function ResourceListPage({ config }: { config: ResourceConfig }) {
|
||||
const list = useResourceList(config.resource);
|
||||
return <UniversalListPage {...list} columns={config.list.columns} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: Template Composition (SAM's current direction, improved)
|
||||
```typescript
|
||||
// templates/UniversalCRUDPage.tsx -- enhanced version
|
||||
function UniversalCRUDPage<T>({
|
||||
resource,
|
||||
listConfig,
|
||||
detailConfig,
|
||||
formConfig,
|
||||
}: CRUDPageProps<T>) {
|
||||
// Handles list/detail/form modes based on URL
|
||||
// Integrates data fetching, pagination, filtering
|
||||
// Renders appropriate template based on mode
|
||||
}
|
||||
```
|
||||
|
||||
### Industry Assessment
|
||||
- **Pattern 1** (Resource Hooks) is the most widely adopted -- used by react-admin (25K stars) and Refine (30K stars)
|
||||
- **Pattern 2** (Config-Driven) reduces code the most but requires upfront investment in the config system
|
||||
- **Pattern 3** (Template Composition) is the middle ground -- SAM's `UniversalListPage` is already this direction
|
||||
|
||||
**Recommendation**: Evolve toward a **Provider + Resource Hooks** layer. Keep `UniversalListPage` and `IntegratedDetailTemplate` but back them with a standardized data provider.
|
||||
|
||||
---
|
||||
|
||||
## 5. Comparison Matrix: SAM ERP vs Industry Patterns
|
||||
|
||||
| Dimension | SAM ERP (Current) | react-admin | Refine | Payload CMS | FSD | Recommendation |
|
||||
|-----------|-------------------|-------------|--------|-------------|-----|----------------|
|
||||
| **Folder Structure** | Domain-based (app router) | Resource-based | Resource-based | Collection-based | Layer > Slice > Segment | Hybrid Domain + FSD shared layer |
|
||||
| **Component Org** | Atomic Design (partial) | Flat per resource | Flat per resource | Config-driven | Layer-based (entities/features) | FSD for app code, Atomic for shared UI |
|
||||
| **API Layer** | 89 colocated actions.ts | Centralized dataProvider | Centralized dataProvider | Built-in Local API | api/ segment per slice | Centralized API client + domain actions |
|
||||
| **CRUD Abstraction** | UniversalListPage template | Resource + Controller hooks | useTable/useForm hooks | Auto-generated from config | Manual per feature | Add resource hooks on top of templates |
|
||||
| **Form Handling** | Mixed (migrating to RHF+Zod) | react-hook-form (built-in) | react-hook-form (headless) | Auto from field config | Manual per feature | Complete RHF+Zod migration |
|
||||
| **State Management** | Zustand stores | React Query (built-in) | React Query (built-in) | Server-side | Per-slice model/ | Keep Zustand for UI state, add React Query for server state |
|
||||
| **Type Safety** | Manual interfaces | Built-in types | TypeScript throughout | Auto-generated from schema | Manual per segment | Consider schema-driven type generation |
|
||||
| **50+ Page Scale** | Manual duplication | Resource registration | Inferencer + hooks | Collection config | Slice per entity | Resource hooks + config-driven columns |
|
||||
|
||||
---
|
||||
|
||||
## 6. Actionable Recommendations for SAM ERP
|
||||
|
||||
### Priority 1: Introduce a Data Provider / API Client Layer
|
||||
**Why**: The biggest gap vs. industry standard. 89 scattered actions.ts files means duplicated fetch logic, inconsistent error handling, and no centralized caching.
|
||||
|
||||
**Action**: Create a `dataProvider` abstraction inspired by react-admin/Refine:
|
||||
```typescript
|
||||
// src/lib/data-provider.ts
|
||||
export const dataProvider = {
|
||||
getList: (resource, params) => proxyFetch(`/api/proxy/${resource}`, params),
|
||||
getOne: (resource, id) => proxyFetch(`/api/proxy/${resource}/${id}`),
|
||||
create: (resource, data) => proxyFetch(`/api/proxy/${resource}`, { method: 'POST', body: data }),
|
||||
update: (resource, id, data) => proxyFetch(`/api/proxy/${resource}/${id}`, { method: 'PUT', body: data }),
|
||||
delete: (resource, id) => proxyFetch(`/api/proxy/${resource}/${id}`, { method: 'DELETE' }),
|
||||
};
|
||||
```
|
||||
|
||||
### Priority 2: Create Resource Hooks
|
||||
**Why**: Reduce per-page boilerplate for list/detail/form patterns.
|
||||
|
||||
**Action**: Build `useResourceList`, `useResourceDetail`, `useResourceForm` hooks that wrap the data provider.
|
||||
|
||||
### Priority 3: Evolve Folder Structure Toward Hybrid FSD
|
||||
**Why**: Atomic Design for app-level code leads to unclear domain boundaries.
|
||||
|
||||
**Action**:
|
||||
- Keep `shared/ui/` (atoms/organisms) for reusable UI components
|
||||
- Add `domains/` or `entities/` for business-logic grouping
|
||||
- Keep `app/` routes thin -- delegate to domain components
|
||||
|
||||
### Priority 4: Complete Form Standardization
|
||||
**Why**: Mixed form patterns make maintenance harder and prevent reusable form configs.
|
||||
|
||||
**Action**: Complete the react-hook-form + Zod migration. Consider field-config-driven forms (Payload pattern) for highly repetitive forms.
|
||||
|
||||
### Priority 5: Consider Server State Management (React Query / TanStack Query)
|
||||
**Why**: react-admin and Refine both use React Query internally for caching, optimistic updates, and background refetching. Zustand is better suited for client UI state.
|
||||
|
||||
**Action**: Evaluate adding TanStack Query for server state alongside Zustand for UI state.
|
||||
|
||||
---
|
||||
|
||||
## 7. What SAM ERP Is Already Doing Well
|
||||
|
||||
1. **Domain-based routing** (`app/[locale]/(protected)/quality/...`) aligns with industry best practice
|
||||
2. **UniversalListPage + IntegratedDetailTemplate** is the right abstraction direction (similar to react-admin's List/Edit components)
|
||||
3. **SearchableSelectionModal** as a reusable pattern is good (similar to react-admin's ReferenceInput)
|
||||
4. **Server Actions in colocated files** follows Next.js official recommendation for route-specific logic
|
||||
5. **Zustand for global state** is a solid choice for UI state (sidebar state, theme, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
### Open-Source Projects
|
||||
- [react-admin - Architecture](https://marmelab.com/react-admin/Architecture.html)
|
||||
- [react-admin - GitHub](https://github.com/marmelab/react-admin)
|
||||
- [Refine - Data Provider](https://refine.dev/docs/data/data-provider/)
|
||||
- [Refine - GitHub](https://github.com/refinedev/refine)
|
||||
- [Payload CMS - Collections](https://payloadcms.com/docs/configuration/collections)
|
||||
- [Payload CMS - GitHub](https://github.com/payloadcms/payload)
|
||||
- [Medusa - Admin Development](https://docs.medusajs.com/learn/fundamentals/admin)
|
||||
- [Medusa - GitHub](https://github.com/medusajs/medusa)
|
||||
|
||||
### Architectural Methodologies
|
||||
- [Feature-Sliced Design](https://feature-sliced.design/)
|
||||
- [FSD - Layers Reference](https://feature-sliced.design/docs/reference/layers)
|
||||
- [Atomic Design + FSD Hybrid](https://medium.com/@buwanekasumanasekara/atomic-design-meets-feature-based-architecture-in-next-js-a-practical-guide-c06ea56cf5cc)
|
||||
- [Clean Architecture vs FSD in Next.js](https://medium.com/@metastability/clean-architecture-vs-feature-sliced-design-in-next-js-applications-04df25e62690)
|
||||
|
||||
### Folder Structure & Patterns
|
||||
- [Next.js App Router Best Practices (2025)](https://medium.com/better-dev-nextjs-react/inside-the-app-router-best-practices-for-next-js-file-and-directory-structure-2025-edition-ed6bc14a8da3)
|
||||
- [Scalable Next.js Folder Structure](https://techtales.vercel.app/read/thedon/building-a-scalable-folder-structure-for-large-next-js-projects)
|
||||
- [SaaS Architecture Patterns with Next.js](https://vladimirsiedykh.com/blog/saas-architecture-patterns-nextjs)
|
||||
- [Modular Monolith for Frontend](https://frontendatscale.com/issues/45/)
|
||||
Reference in New Issue
Block a user