app-specific-patterns
Maintains development standards for the GROWI application, focusing on Next.js structures, state management, and testing.
Install
mkdir -p .claude/skills/app-specific-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2721" && unzip -o skill.zip -d .claude/skills/app-specific-patterns && rm skill.zipInstalls to .claude/skills/app-specific-patterns
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
GROWI main application (apps/app) specific patterns for Next.js, Jotai, SWR, and testing. Auto-invoked when working in apps/app.Key capabilities
- →Implement Next.js page layouts
- →Structure Jotai state atoms
- →Fetch data using SWR hooks
- →Mock Next.js router for tests
- →Hydrate Jotai atoms in tests
How it works
The skill enforces specific file naming conventions, directory structures for state management, and testing patterns tailored to the GROWI main application.
Inputs & outputs
When to use app-specific-patterns
- →Implementing growi pages
- →Structuring jotai state
- →Following growth app architecture
About this skill
App Specific Patterns (apps/app)
For general testing patterns, see the global .claude/skills/essential-test-patterns and .claude/skills/essential-test-design skills.
Next.js Pages Router
File Naming
Pages must use .page.tsx suffix:
pages/
├── _app.page.tsx # App wrapper
├── [[...path]]/index.page.tsx # Catch-all wiki pages
└── admin/index.page.tsx # Admin pages
getLayout Pattern
// pages/admin/index.page.tsx
import type { NextPageWithLayout } from '~/interfaces/next-page';
const AdminPage: NextPageWithLayout = () => <AdminDashboard />;
AdminPage.getLayout = (page) => <AdminLayout>{page}</AdminLayout>;
export default AdminPage;
Jotai State Management
Directory Structure
src/states/
├── ui/
│ ├── sidebar/ # Multi-file feature
│ ├── device.ts # Single-file feature
│ └── modal/ # 1 modal = 1 file
│ ├── page-create.ts
│ └── page-delete.ts
├── page/ # Page data state
├── server-configurations/
└── context.ts
features/{name}/client/states/ # Feature-scoped atoms
Placement Rules
| Category | Location |
|---|---|
| UI state | states/ui/ |
| Modal state | states/ui/modal/ (1 file per modal) |
| Page data | states/page/ |
| Feature-specific | features/{name}/client/states/ |
Derived Atoms
import { atom } from 'jotai';
export const currentPageAtom = atom<Page | null>(null);
// Derived (read-only)
export const currentPagePathAtom = atom((get) => {
return get(currentPageAtom)?.path ?? null;
});
SWR Data Fetching
Directory
src/stores-universal/
├── pages.ts # Page hooks
├── users.ts # User hooks
└── admin/settings.ts
Patterns
import useSWR from 'swr';
import useSWRImmutable from 'swr/immutable';
// Auto-revalidation
export const usePageList = () => useSWR<Page[]>('/api/v3/pages', fetcher);
// No auto-revalidation (static data)
export const usePageById = (id: string | null) =>
useSWRImmutable<Page>(id ? `/api/v3/pages/${id}` : null, fetcher);
Testing (apps/app Specific)
Mocking Next.js Router
import { mockDeep } from 'vitest-mock-extended';
import type { NextRouter } from 'next/router';
const createMockRouter = (overrides = {}) => {
const mock = mockDeep<NextRouter>();
mock.pathname = '/test';
mock.push.mockResolvedValue(true);
return Object.assign(mock, overrides);
};
vi.mock('next/router', () => ({
useRouter: () => createMockRouter(),
}));
Testing with Jotai
import { Provider } from 'jotai';
import { useHydrateAtoms } from 'jotai/utils';
const HydrateAtoms = ({ initialValues, children }) => {
useHydrateAtoms(initialValues);
return children;
};
const renderWithJotai = (ui, initialValues = []) => render(
<Provider>
<HydrateAtoms initialValues={initialValues}>{ui}</HydrateAtoms>
</Provider>
);
// Usage
renderWithJotai(<PageHeader />, [[currentPageAtom, mockPage]]);
Testing SWR
import { SWRConfig } from 'swr';
const wrapper = ({ children }) => (
<SWRConfig value={{ dedupingInterval: 0, provider: () => new Map() }}>
{children}
</SWRConfig>
);
const { result } = renderHook(() => usePageById('123'), { wrapper });
Path Aliases
Always use ~/ for imports:
import { PageService } from '~/server/services/PageService';
import { currentPageAtom } from '~/states/page/page-atoms';
Summary
- Next.js:
.page.tsxsuffix,getLayoutfor layouts - Jotai:
states/global,features/*/client/states/feature-scoped - SWR:
stores-universal/, null key for conditional fetch - Testing: Mock router, hydrate Jotai, wrap SWR config
- Imports: Always
~/path alias
When not to use it
- →Projects outside apps/app directory
- →Non-Next.js applications
Prerequisites
Limitations
- →Strict file naming requirements
- →Limited to GROWI codebase
How it compares
It provides strict architectural constraints for GROWI development rather than generic React best practices.
Compared to similar skills
app-specific-patterns side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| app-specific-patterns (this skill) | 4 | 2mo | No flags | Intermediate |
| javascript-typescript-typescript-scaffold | 3 | 4mo | Review | Beginner |
| web-frameworks | 1 | 9mo | Review | Intermediate |
| open-notebook-lm-guidelines | 0 | 5mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by growilabs
View all by growilabs →You might also like
javascript-typescript-typescript-scaffold
sickn33
You are a TypeScript project architecture expert specializing in scaffolding production-ready Node.js and frontend applications. Generate complete project structures with modern tooling (pnpm, Vite, N
web-frameworks
mrgoonie
Build modern full-stack web applications with Next.js (App Router, Server Components, RSC, PPR, SSR, SSG, ISR), Turborepo (monorepo management, task pipelines, remote caching, parallel execution), and RemixIcon (3100+ SVG icons in outlined/filled styles). Use when creating React applications, implementing server-side rendering, setting up monorepos with multiple packages, optimizing build performance and caching strategies, adding icon libraries, managing shared dependencies, or working with TypeScript full-stack projects.
open-notebook-lm-guidelines
RainLib
Core project guidelines, architecture, and UI styling instructions for the FerrisMind (openNotebookLm) AI workspace project. Use this whenever working on the frontend or backend of this project.
nextjs-best-practices
davila7
Next.js App Router principles. Server Components, data fetching, routing patterns.
add-setting-env
lobehub
Guide for adding environment variables to configure user settings. Use when implementing server-side environment variables that control default values for user settings. Triggers on env var configuration or setting default value tasks.
nextjs-supabase-auth
davila7
Expert integration of Supabase Auth with Next.js App Router Use when: supabase auth next, authentication next.js, login supabase, auth middleware, protected route.