Best Practices

Best Practices

Follow these best practices to build maintainable, performant applications with @wayvo-ai/core.

Code Organization

File Structure

src/app/(secure)/module/feature/
├── page.tsx
├── page-content.tsx
├── hooks/
│   ├── use-store.ts
│   ├── use-table-columns.tsx
│   └── smart-search-columns.ts
└── components/
    └── edit-form.tsx

Naming Conventions

  • Store aliases: {module}-list, {module}-edit, {module}-dialog, {module}-combobox
  • Hooks: use{Entity}Store, use{Entity}TableColumns, use{Entity}SmartSearchColumns
  • Components: PascalCase (e.g., EntityForm, EntityDialog)

Performance Optimization

Use select for Lookup Stores

Only fetch needed fields:

const store = useStore<Customer>({
  datasourceId: 'Customers',
  alias: 'customer-options',
  select: ['customerId', 'customerName'],  // Only these fields
  limit: 1000,
});

Use filterLocally for Small Datasets

When the complete dataset is loaded:

const store = useStore<Status>({
  datasourceId: 'StatusLookup',
  alias: 'status-combobox',
  limit: 100,  // Load all
  autoQuery: true,
  filterLocally: true,  // Filter client-side
});

Appropriate limit Values

  • List pages: 20 (standard pagination)
  • Lookup stores: 1000 (for combobox options)
  • Detail pages: 1 (single record)

Type Safety

Always Define TypeScript Types

// src/lib/common/ds/types/module/Entity.ts
export interface Entity {
  id: string;
  name: string;
  description?: string;
  createdAt: string;
}

Use Type Inference

// TypeScript infers Entity from DataSource
const store = useStore<Entity>({
  datasourceId: 'Entity',
  // ...
});

// row is typed as Entity
const row = useCurrentRowSync(store);

Store Configuration

Share Stores via Same Key

// Both return the SAME store instance
const tableStore = useEntityStore();
const formStore = useEntityStore();  // Same instance!

Use Descriptive Aliases

// ✅ Good
alias: 'entity-list'
alias: 'entity-edit'
alias: 'entity-dialog'

// ❌ Bad
alias: 'list'
alias: 'edit'

Date Handling

Use UTC Methods

// ❌ Wrong - timezone shifts the date
const formatDate = (date: string) => format(new Date(date), 'MMM yyyy');

// ✅ Correct - use UTC methods
const formatDate = (date: string) => {
  const d = new Date(date);
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  return `${months[d.getUTCMonth()]} ${d.getUTCFullYear()}`;
};

Scrollbar Styling

All scrollable regions should include:

className="overflow-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-muted-foreground/20 hover:scrollbar-thumb-muted-foreground/40"

Form Layout

Grid Alignment

Always use items-start for side-by-side fields:

// ✅ Correct
<div className="grid grid-cols-2 items-start gap-4">
  <TextInput label="Field 1" helpText="Has help text" />
  <ComboboxInput label="Field 2" />
</div>

Next Steps

Previous
Data Fetching