بنقرة واحدة
frontend-ui-components
Provides guidelines for using shared UI components and styling. This skill should be used when implementing UI features using Shadcn/Radix components and the shared @eridu/ui package.
القائمة
Provides guidelines for using shared UI components and styling. This skill should be used when implementing UI features using Shadcn/Radix components and the shared @eridu/ui package.
Patterns for auditing and improving erify_api query performance and response efficiency. Use when detecting N+1 queries, reducing over-fetching, designing lean select/include strategies, replacing in-memory joins with DB aggregations, adding pagination guards, or defining API performance baselines before scaling. Complements database-patterns which covers the basic N+1 and Promise.all rules.
Patterns for building the studio Operations review surfaces in erify_studios (`/task-review`, `/show-run-review`, `/task-setup`, and future `/costs` / analytics views). Use BEFORE adding or changing an operational-day-scoped review screen — the lean-summary + lazy-paginated-sub-resources read model, URL-synced multi-tab DataTables, per-tab "export the full filtered set" CSV, and the 06:00–05:59 operational-day window computed on the frontend. Required reading before cloning `show-run-summary` for a new review surface.
Patterns for adding extractors and write surfaces to the PR 12 fact-extraction pipeline (`apps/erify_api/src/orchestration/fact-extraction/`). Use BEFORE implementing any new `IngestionExtractor`, paired-atomic write, `SystemFactKey`, or hydrated-scope target type. Required reading before PR 12.3.2 (violations), 12.4 (review surface), or any follow-on extractor work — every Codex finding on PR 12.1.2 (#103) and PR 12.2 (#104) is encoded here. The "State-transition handoff between co-submitted facts" section is mandatory before adding ANY fact whose write semantics depend on another fact's value in the same submission.
Provides patterns for building and optimizing large frontend tabular views across the eridu-services monorepo. Use when building or refactoring server-driven tables, dense tabular UIs, virtualized grids, inline editing, saved views, and table URL state in erify_creators, erify_studios, or shared @eridu/ui.
Use when expanding the SystemFactKey catalog, onboarding task templates that need operational fact extraction, a prod-db-sync reveals task templates without system_fact_key bindings, or a field-type mismatch (e.g. select where checkbox or multiselect is required) blocks binding a template field to the fact-extraction pipeline.
Provides Prisma-specific patterns for soft delete, transactions, optimistic locking, advisory locks, bulk operations, and performance optimization. This skill should be used when implementing data persistence, handling concurrent updates, serializing concurrent operations on the same resource, managing complex multi-table operations, or optimizing query performance.
| name | frontend-ui-components |
| description | Provides guidelines for using shared UI components and styling. This skill should be used when implementing UI features using Shadcn/Radix components and the shared @eridu/ui package. |
How to build and use UI components using the shared @eridu/ui package and Shadcn patterns.
See references/ui-component-details.md for detailed code examples.
@eridu/ui PackageAll generic UI components live in packages/ui. Do NOT create local copies in apps.
import { Button } from '@eridu/ui/components/button';
import { Input } from '@eridu/ui/components/input';
import { cn } from '@eridu/ui/lib/utils';
| Component | Rule |
|---|---|
| Date/Time Pickers | Use ResponsiveDateTimePicker (or DatePicker/DateTimePicker) from @eridu/ui, not native <input type="date"> |
| Mobile-visible Dialogs | Render as Drawer (vaul) below md; share body with the desktop Dialog. Default to ResponsiveDateTimePicker and the responsive dialog pattern for any new dialog reachable on mobile |
| Async Lookup Fields | 2+ AsyncCombobox in same form → extract each into memo() field component |
| Searchable Inputs | onSearch must update query state — never leave as no-op |
| Refresh Buttons | Icon-only (RotateCw) + aria-label + spinning state while fetching |
| Collapsible Sections | ChevronUp/ChevronDown toggle, smooth animated transitions |
| Cross-Field Form Invariants | When BE Zod superRefine ties one field's value to another's, build the payload through a buildXxxPayload(form) helper that clears irrelevant fields (don't trust user residue). Disable the irrelevant inputs. Never submit raw state directly. |
On viewports below the md breakpoint (768px), Radix Popover/Dialog content frequently overflows the viewport or clips inside parent dialogs. House rule:
Dialog, Popover).Drawer with the same body, switched via useIsMobile() from @eridu/ui.erify_studios wrapper: use apps/erify_studios/src/components/responsive-dialog.tsx for app-local Dialog → Drawer conversions before hand-rolling the shell in feature code. It owns the aria-describedby suppression — never re-add that prop on top of it.ResponsiveDateTimePicker in packages/ui/src/components/date-picker.tsx.Applies to: every dialog reachable on a mobile route (actuals editing, shift compensation, task forms, json-form modals, schedule dialogs). Plain confirmations with one button can stay as Dialog — escalate when the dialog contains forms, pickers, multi-step content, or anything wider than ~280px.
Migration guide + code recipe: references/ui-component-details.md#responsive-dialog-pattern.
When designing a feature scoped to an identity-bearing entity — Creator, studio Member (manager / operator / account-manager), or Show — consider how it lands across three perspectives. The pattern is a design checklist, not a global mandate: each PRD decides which of the three a given sub-PR delivers, defers, or skips.
/task-review, /show-run-review, /task-setup, creator/member roster tables). Manager-facing, studio-wide visibility./studios/:studioId/creators/:creatorId — single creator's attendance, rates, overrides, performance./studios/:studioId/members/:memberId — single member's assignments, audit trail, role context./studios/:studioId/shows/:showId — single show's actuals, platform metrics, violations.erify_creators app is the creator's self-view. Routes are top-level (/shows, /shows/:showId) — no /me/* prefix, because the JWT scope already identifies the viewer as the creator.erify_studios, which also hosts P1/P2 manager surfaces. A member self-view here needs an explicit /me/* prefix to disambiguate from /studios/:studioId/... manager routes. Forward-looking — no member /me/* ships today.Cross-app widget sharing: because Perspective 3 for creators lives in a different app (
erify_creators) from P1/P2 (erify_studios), any widget reused across these perspectives MUST live in a shared package (packages/uior a domain-shared package), not in either app'ssrc/features/. App-local widgets do not satisfy the reuse rule.When a PRD does add a feature in more than one perspective, the perspectives must consume the same shared widgets with only filter / role-scope variation — no duplicated visualization or query code. Whether all three perspectives are in scope is a PRD decision; widget reuse across whichever perspectives ship is not.
For Studio Individual Overview routes such as /studios/:studioId/creators/:creatorId,
/studios/:studioId/members/:memberId, /studios/:studioId/shifts/:shiftId, and
/studios/:studioId/shows/:showId:
Defaults:
Default Rate or
similar when they describe stored operational defaults, but the user-facing first tab
reads as the entity profile/detail page.shows/$showId/tasks / ShowHeaderSection): compact icon-only back
link, entity title / subtitle, and a metadata panel above the tabs.PageLayout.actions; it is
less consistent with adjacent detail routes and less clear on mobile.overflow-x-auto scrollbar-none flex-nowrap scroll-smooth and style each link as shrink-0.To prevent code duplication and logic drift across these three views, extract and share core unit components. Component wrappers should simply configure the appropriate API filters and role context before passing them to the shared visual unit:
ActualsTimelineViewer: Shared timeline block visualizing planned vs actual times.ShowRunSummary: Shared range summary for submitted and signed-off show runs, creator attendance, phase checks, and active platform issues.PerformanceMetricsWidget: Graphical/tabular widget detailing analytical platform statistics (GMV, views, CTR, CTO) (shipped in PR 21.6/7).CompensationBreakdownCard: Shared card computing base compensation, commissions, and line items.AttendanceStatusBadge: Shared visual badge translating actualStartTime and Show.startTime into colored status highlights.AuditLogTimeline: Polymorphic audit log history renderer.Ensure that any new feature touching operational entities adheres to this three-perspective layout from day one.
DatePicker; datetime: ResponsiveDateTimePicker for mobile-reachable surfaces, DateTimePicker otherwiseUse cn() from @eridu/ui/lib/utils to merge classes safely. Use theme-mapped colors (bg-primary, text-muted-foreground).
children prop for composable layouts@eridu/ui when: Used in multiple apps, generic, stable API, well-tested. Wait for 2-3 use cases.@eridu/ui primitives, keep in src/components/{feature}/packages/ui/src/components/, follow Radix+Tailwind pattern@eridu/uicn() for class mergingaria-label on icon buttons)DatePicker / DateTimePicker / ResponsiveDateTimePickerResponsiveDateTimePickerDrawer below md (responsive dialog → drawer pattern) with a shared bodyerify_studios mobile-reachable forms use the app-local ResponsiveDialog wrapper unless a feature needs custom shell behaviormemo() field componentsonSearch wired to real search statebuildXxxPayload helper + disabled inputs (not by trusting form state on submit)/me/* self-view) — perspectives in scope share one set of widgets; perspectives out of scope are an explicit PRD decision, not an oversightProfile for people entities, Details for record entities like shows) rather than Defaults