with one click
add-feature
// Add a new feature to the Ecency web app following established patterns
// Add a new feature to the Ecency web app following established patterns
Add a new query to @ecency/sdk or the web app with React Query integration
Add a new blockchain mutation to @ecency/sdk and wire it up in the web app
Review code changes for bugs, patterns violations, and common pitfalls in the vision-next codebase
Debug common issues in the vision-next Hive web app with known solutions and investigation patterns
| name | add-feature |
| description | Add a new feature to the Ecency web app following established patterns |
| argument-hint | ["feature-name"] |
| disable-model-invocation | true |
Guide for adding a new feature to the Ecency Vision web app.
apps/web/src/features/<feature-name>/
āāā components/ # React components
ā āāā <feature>.tsx
ā āāā index.ts
āāā api/ # Feature-specific API calls (if needed)
āāā hooks/ # Custom hooks
āāā types/ # TypeScript types
āāā index.ts # Public exports
Shared components go in features/shared/, UI primitives in features/ui/.
Add a flag in apps/web/src/config/config.ts under visionFeatures:
visionFeatures: {
// ... existing flags
<featureName>: {
enabled: true // or false for gradual rollout
}
}
Gate UI rendering with the config manager:
import { EcencyConfigManager } from "@/config";
// Conditional rendering
<EcencyConfigManager.Conditional
condition={({ visionFeatures }) => visionFeatures.<featureName>.enabled}
>
<MyFeatureComponent />
</EcencyConfigManager.Conditional>
If the feature needs blockchain data (queries/mutations):
Follow /add-sdk-mutation or /add-query skills to add SDK-level support first.
If the feature needs Ecency private API:
Add the API call in apps/web/src/api/private-api.ts and create a query in apps/web/src/api/queries/.
| State type | Where | When |
|---|---|---|
| Server data (API responses) | React Query via SDK query options | Always for async data |
| Global UI state (modals, settings) | Zustand in core/global-store/modules/ | Shared across routes |
| Local component state | useState/useReducer | Component-specific |
Add strings to apps/web/src/features/i18n/locales/en-US.json only:
{
"<feature-name>": {
"title": "Feature Title",
"description": "Feature description",
"button-label": "Click me"
}
}
Use in components:
import { useTranslation } from "react-i18next";
const { t } = useTranslation();
// t("<feature-name>.title")
Static page: apps/web/src/app/(staticPages)/<route>/page.tsx
Dynamic page: apps/web/src/app/(dynamicPages)/<route>/page.tsx
Add route constant to apps/web/src/routes.ts.
dark: variantsapps/web/tailwind.config.tsCreate test files in apps/web/src/specs/features/<feature-name>/:
import { renderWithQueryClient } from "@/specs/test-utils";
import { screen, fireEvent } from "@testing-library/react";
describe("<FeatureName>", () => {
test("renders correctly", () => {
renderWithQueryClient(<MyComponent />);
expect(screen.getByRole("button")).toBeInTheDocument();
});
});
Run tests: pnpm --filter @ecency/web test
Common integration patterns:
apps/web/src/app/publish/_editor-extensions/apps/web/src/app/(dynamicPages)/profile/[username]/_components/pnpm lint passespnpm test passes