AP

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.zip

Installs 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.
128 chars✓ has a “when” trigger
Intermediate

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

You give it
Component or state requirement
You get back
GROWI-compliant code structure

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

CategoryLocation
UI statestates/ui/
Modal statestates/ui/modal/ (1 file per modal)
Page datastates/page/
Feature-specificfeatures/{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

  1. Next.js: .page.tsx suffix, getLayout for layouts
  2. Jotai: states/ global, features/*/client/states/ feature-scoped
  3. SWR: stores-universal/, null key for conditional fetch
  4. Testing: Mock router, hydrate Jotai, wrap SWR config
  5. Imports: Always ~/ path alias

When not to use it

  • Projects outside apps/app directory
  • Non-Next.js applications

Prerequisites

Next.jsJotaiSWR

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.

SkillInstallsUpdatedSafetyDifficulty
app-specific-patterns (this skill)42moNo flagsIntermediate
javascript-typescript-typescript-scaffold34moReviewBeginner
web-frameworks19moReviewIntermediate
open-notebook-lm-guidelines05moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

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

31

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.

10

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.

00

nextjs-best-practices

davila7

Next.js App Router principles. Server Components, data fetching, routing patterns.

3164

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.

469

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.

1259

Search skills

Search the agent skills registry