Frontend development in ayunis-core. Use when creating, modifying, or debugging frontend code (React, Feature-Sliced Design, API client).
Scanned 9/20/2026
Install to Claude Code
npx -y skills add ayunis-core/ayunis-core --skill ayunis-core-frontend-dev --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ayunis Core Frontend Dev?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ayunis-core-ayunis-core-frontend-dev)More formats (shields.io, HTML) on the badges page.
---
name: ayunis-core-frontend-dev
description: Frontend development in ayunis-core. Use when creating, modifying, or debugging frontend code (React, Feature-Sliced Design, API client).
---
# Frontend Development — ayunis-core-frontend
## Working Directory
**All commands run from `ayunis-core-frontend/`:**
```bash
cd ayunis-core-frontend
```
Before modifying any layer, read its `SUMMARY.md` in `src/[layer]/SUMMARY.md`. The top-level `src/SUMMARY.md` provides an overview.
## Validation Sequence
Choose validation breadth using the repository's Proportional Workflow.
For Standard and High-Risk changes:
```bash
pnpm run build # Must succeed
pnpm run lint # Must pass
```
For Fast Path changes, run the narrowest relevant test when behavior or test
code changed, plus any lint/type check applicable to the touched files. Run the
build when imports, types, dependencies, bundling, or other compile-time
behavior could be affected.
**Browser journey or system boundary changed?** Load the `e2e` skill when
lower-level tests do not sufficiently prove the behavior. Add `data-testid`s
needed by the journey to touched components in the same PR
(`<feature>-<element>`, kebab-case) — text selectors are banned because the UI
is i18n'd.
**Would visual evidence materially help review?** After the product PR exists,
load the `pr-media` skill and publish the smallest useful scene set to
`pr-media/pr-<number>`. Do not commit media scenes to the product branch.
## Architecture (Feature-Sliced Design)
```text
packages/ui/ # Framework-level UI primitives, tokens, and utilities
ayunis-core-frontend/src/
├── pages/ # Route components (compose widgets/features)
├── widgets/ # Reusable composites (used in ≥2 pages)
├── features/ # Self-contained business logic
└── shared/ # App-wide infrastructure and app-aware UI
```
**Import rules**: `pages → widgets → features → shared`
Layers only depend on layers to their right. Never import upward.
### Check demonstrated conventions before deciding placement
The FSD rules above are the theory; **this repo's actual conventions are the tie-breaker.** Before deciding where a slice or component lives — feature vs widget vs page, which page a route maps to, whether something is "shared enough" to promote a layer — grep how comparable cases are already structured and follow that, rather than reasoning from FSD principles alone.
- The abstract heuristics ("used in ≥2 pages → widget", "used from more than one slice → promote") are necessary but not sufficient. They routinely disagree with how the codebase actually draws its boundaries when viewed across the whole repo instead of a single branch.
- Concrete convention that has bitten before: **pages map one slice per route** — e.g. a list route and its detail route are separate page slices (`skills.index` vs `skill.$id`), not one page reused across two routes. Check the route files and `src/pages/` before assuming a shared placement.
- When a colocated placement (feature/page) and a "promote to shared/widget" placement both look defensible, the existing convention wins. Look at the `Reference Pages` in the `new-page` skill and grep sibling slices before moving code.
- Do not double down on a theory-driven placement after pushback — re-check the convention first. See "Confirm placement before mutating a stacked PR chain" below.
### Confirm placement before mutating a stacked PR chain
Do not execute structural moves and amend commits across a stacked-PR chain (e.g. `gt modify` a parent, then check out and amend the child) off a *preliminary* placement conclusion. Settle the placement against repo conventions first, then move — reverting a wrong move across stacked branches means restoring exact pre-session SHAs from the reflog.
## Shared UI Package — Registry-Managed Primitives
Framework-level primitives live in the repository-root `packages/ui/` workspace and are imported through `@ayunis/ui` subpaths. App-aware shared components remain in `ayunis-core-frontend/src/shared/ui/`.
- Run shadcn registry commands from `packages/ui/`, whose `components.json` owns the aliases and registry configuration: `cd ../packages/ui && pnpm dlx shadcn@latest add <component>`.
- Do not patch `packages/ui/src/components/` for a feature-specific use case. Wrap or compose the primitive in the relevant frontend `ui/` directory or `src/shared/ui/` instead.
- Changes inside `packages/ui/` must remain application-independent and be intentional design-system work. If a primitive genuinely needs a new generic capability, confirm that scope with the user before changing it.
- Every newly introduced `packages/ui/src/components/<name>.tsx` component must include a colocated `<name>.stories.tsx`. Cover its representative default state and meaningful generic variants, states, or interactions; compound components should be demonstrated as a usable composition.
- Import primitives from their public subpaths, such as `@ayunis/ui/components/button`, and `cn` from `@ayunis/ui/lib/cn`. Do not reach into `packages/ui/src/` from the frontend.
### Reach for existing primitives and tokens
Compose the existing design system before hand-rolling layout, and use design tokens instead of raw Tailwind color scales:
- **Look for a composite primitive first.** For an icon-plus-label row (banners, result cards, list rows) use the `Item` family — `Item` / `ItemMedia variant="icon"` / `ItemContent` — rather than assembling a bare `flex` container yourself. Check `@ayunis/ui` for a framework primitive and `src/shared/ui/` for an app-aware component before adding your own.
- **Use semantic color tokens, never hardcoded palette classes.** `text-brand`, `text-muted-foreground`, etc. — not `text-amber-500`, `text-blue-600`, or other raw Tailwind color scales, which break theming and dark mode.
### Page module internals
Each page module can have these subdirectories:
```text
src/pages/<page-name>/
├── ui/ # Components — state, hooks, JSX only
├── api/ # Mutation hooks (one per operation)
├── model/ # Types, constants, schemas
└── lib/ # Pure helper functions (formatting, URL building, data transforms)
```
Keep `ui/` components focused on component logic. Extract pure functions that don't depend on React state or hooks into `lib/`.
## API Client
After backend API changes, regenerate the client:
```bash
pnpm run openapi:update # Regenerates src/shared/api/generated/
```
**Never edit generated code manually** — it will be overwritten.
## Hook Pattern
One hook per operation, encapsulating mutation logic. Use `showSuccess`/`showError` from `@/shared/lib/toast` for user feedback, and `extractErrorData` from `@/shared/api/extract-error-data` for structured error handling.
For hooks that back a form (create/update dialogs), load the **frontend-form-pattern** skill — it covers form types, structure, and the full end-to-end validation pattern including backend DTO validation, field-level error display, and i18n.
## Verifying in the Browser
When the change affects rendered UI or browser behavior, use your harness's browser tooling to check the affected page renders and the console is clean. A render failure shows the React dev-server error overlay — the element `#webpack-dev-server-client-overlay` must not exist. The frontend URL depends on the dev slot (see `dev-environment`); seeded login credentials are in `seed-database`.
## Completion Checklist
- [ ] Validation matches the repository's Proportional Workflow
- [ ] Relevant focused tests pass when behavior or test code changed
- [ ] Build and package lint pass for Standard and High-Risk changes
- [ ] Affected page renders without console errors when UI or browser behavior changed
- [ ] No `any` types introduced
- [ ] Import rules respected (no upward imports)
- [ ] UI primitives use public `@ayunis/ui` subpaths
- [ ] New `packages/ui` components include representative Storybook stories
- [ ] No feature-specific behavior added to `packages/ui/`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!