{"owner":"getfider","repo":"fider","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":2291,"categories":["claude-rule"],"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md"],"skills":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code when working with the Fider codebase.\n\n## Repository Structure\n\n**Backend (Go):**\n\n- `app/handlers/` - HTTP request handlers\n- `app/models/` - Data models (entity, cmd, query, action, dto)\n- `app/services/` - Business logic and external service integrations\n- `app/pkg/bus/` - Service registry and dispatch system\n- `app/cmd/routes.go` - All HTTP routes defined here\n- `migrations/` - Database migrations (numbered SQL files)\n\n**Frontend (React/TypeScript):**\n\n- `public/pages/` - Page components (lazy-loaded)\n- `public/components/` - Reusable UI components\n- `public/services/` - Client-side services and API calls\n- `public/hooks/` - Custom React hooks\n- `public/assets/styles/` - SCSS styles with utility classes\n\n**Configuration:**\n\n- `.env` - Local environment config (copy from `.example.env`)\n- `Makefile` - Build and development commands\n\n## Local Development\n\nAll commands are defined in the Makefile.\n\n**Development:**\n\n- `make watch` - Hot reload for both server and UI (use this for active development)\n- `make migrate` - Run database migrations\n\n**Testing:**\n\n- `make test` - Run all tests (both Go and Jest)\n- `make lint` - Lint both server and UI code\n\nEssential: Run \"make lint\" and \"make test\" when you've completed any changes, to check the formatting and tests.\n\n**Building:**\n\n- `make build` - Build production-ready binaries and assets\n\n## Code Patterns & Examples\n\n### Backend: Adding a New API Endpoint\n\n**1. Define the route** in `app/cmd/routes.go`:\n\n```go\n// Public API\nengine.Get(\"/api/v1/posts\", handlers.SearchPosts())\n\n// Authenticated API (requires login)\nengine.Get(\"/api/v1/user/settings\", middlewares.IsAuthenticated(), handlers.UserSettings())\n\n// Admin only\nengine.Post(\"/api/v1/admin/members\", middlewares.IsAuthenticated(), middlewares.IsAuthorized(enum.RoleAdministrator), handlers.CreateMember())\n```\n\n**2. Create the handler** in `app/handlers/`:\n\n```go\npackage handlers\n\nimport (\n\t\"github.com/getfider/fider/app/models/cmd\"\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/bus\"\n\t\"github.com/getfider/fider/app/pkg/web\"\n)\n\n// SearchPosts returns posts matching criteria\nfunc SearchPosts() web.HandlerFunc {\n\treturn func(c *web.Context) error {\n\t\tq := &query.SearchPosts{\n\t\t\tQuery: c.QueryParam(\"query\"),\n\t\t\tLimit: 10,\n\t\t}\n\n\t\tif err := bus.Dispatch(c, q); err != nil {\n\t\t\treturn c.Failure(err)\n\t\t}\n\n\t\treturn c.Ok(q.Result)\n\t}\n}\n```\n\n**3. Define the query** in `app/models/query/`:\n\n```go\npackage query\n\nimport \"github.com/getfider/fider/app/models/entity\"\n\ntype SearchPosts struct {\n\tQuery  string\n\tLimit  int\n\tResult []*entity.Post\n}\n```\n\n**4. Implement the service** in `app/services/`:\n\n```go\npackage postgres\n\nimport (\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/dbx\"\n)\n\nfunc searchPosts(ctx context.Context, q *query.SearchPosts) error {\n\treturn using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error {\n\t\tq.Result = []*entity.Post{}\n\t\treturn trx.Select(&q.Result,\n\t\t\t\"SELECT * FROM posts WHERE title ILIKE $1 LIMIT $2\",\n\t\t\t\"%\"+q.Query+\"%\", q.Limit,\n\t\t)\n\t})\n}\n\nfunc init() {\n\tbus.Register(Service{})\n}\n\nfunc (s Service) Name() string {\n\treturn \"Postgres\"\n}\n\nfunc (s Service) Category() string {\n\treturn \"sqlstore\"\n}\n\nfunc (s Service) Enabled() bool {\n\treturn true\n}\n\nfunc (s Service) Init() {\n\tbus.AddHandler(searchPosts)\n}\n```\n\n### Frontend: Calling the API from React\n\n```typescript\n// In a React component\nimport { http } from \"@fider/services\"\n\nexport const PostSearch: React.FC = () => {\n  const [posts, setPosts] = React.useState([])\n  const [query, setQuery] = React.useState(\"\")\n\n  const handleSearch = async () => {\n    const result = await http.get<Post[]>(`/api/v1/posts?query=${query}`)\n    if (result.ok) {\n      setPosts(result.data)\n    }\n  }\n\n  return (\n    <div className=\"c-post-search\">\n      <input className=\"c-post-search__input\" value={query} onChange={(e) => setQuery(e.target.value)} />\n      <Button onClick={handleSearch}>Search</Button>\n    </div>\n  )\n}\n```\n\n### Model Naming Conventions\n\nUse these strict prefixes in `app/models/`:\n\n```go\n// entity.* - Database tables\ntype entity.User struct {\n    ID    int\n    Name  string\n    Email string\n}\n\n// action.* - User input for POST/PUT/PATCH (maps 1:1 to commands)\ntype action.CreatePost struct {\n    Title       string\n    Description string\n}\n\n// cmd.* - Commands to execute (potentially return values)\ntype cmd.SendEmail struct {\n    To      string\n    Subject string\n    Body    string\n}\n\n// query.* - Queries to fetch data\ntype query.GetPostByID struct {\n    PostID int\n    Result *entity.Post\n}\n\n// dto.* - Data transfer between packages\ntype dto.PostInfo struct {\n    Title     string\n    AuthorName string\n}\n```\n\n### CSS Conventions\n\nMost pages have a corresponding scss file. For example Home.Page.tsx imports Home.Page.scss which contains styles for various components in that page. These follow a BEM style:\n\n```scss\n// Page ID: p-<page_name>\n#p-home {\n  // Component: c-<component>\n  .c-post-list {\n    // Element: c-<component>__<element>\n    &__item {\n      padding: 1rem;\n    }\n\n    &__title {\n      font-size: 1.2rem;\n    }\n\n    // Modifier: c-<component>--<state>\n    &--loading {\n      opacity: 0.5;\n    }\n  }\n}\n```\n\nHowever, more recently, Utility classes were added to the codebase, to make it possible to apply classes in a utility style, similar to tailwind. If possible favour the utility classes over adding new styles for components and pages:\n\n```scss\n// Utility classes (no prefix) - defined in public/assets/styles/utility/\n.mt-2 {\n  margin-top: 0.5rem;\n}\n.flex {\n  display: flex;\n}\n```\n\nImportant: Do not just apply tailwind classes to new code, tailwind is not in use in this project. Check what is available in the utility scss files.\n\n## Common Tasks\n\n### Creating a Database Migration\n\n\"up migrations\" only.\n\n```bash\n# Create new migration file in migrations/ directory\n# Format: YYYYMMDDHHMMSS_description.sql\n# Example: migrations/202601041200_add_user_preferences.sql\n\nCREATE TABLE user_preferences (\n    id SERIAL PRIMARY KEY,\n    user_id INTEGER NOT NULL REFERENCES users(id),\n    theme VARCHAR(50),\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\n```\n\nRun with: `make migrate`\n\n### Adding a New Page Component\n\n```typescript\n// public/pages/MyNewPage/MyNewPage.page.tsx\nimport React from \"react\"\nimport { Page } from \"@fider/components\"\n\ninterface MyNewPageProps {\n  // Props here\n}\n\nconst MyNewPage: React.FC<MyNewPageProps> = (props) => {\n  return (\n    <Page id=\"p-my-new-page\">\n      <h1>My New Page</h1>\n    </Page>\n  )\n}\n\nexport default MyNewPage\n```\n\n```typescript\n// public/pages/MyNewPage/index.ts\nexport { default as MyNewPage } from \"./MyNewPage.page\"\n```\n\nRegister route in `app/handlers/` and lazy-load in `public/index.tsx`.\n\n### Using the Bus System\n\nThe bus handles service registration and dispatch:\n\n```go\n// Register a service\nbus.Register(MyService{})\n\n// Dispatch a query\nq := &query.GetUserByID{UserID: 123}\nif err := bus.Dispatch(ctx, q); err != nil {\n    return err\n}\nuser := q.Result\n\n// Dispatch a command\nc := &cmd.SendEmail{To: \"user@example.com\", Subject: \"Welcome\"}\nif err := bus.Dispatch(ctx, c); err != nil {\n    return err\n}\n```\n\n## Architecture Patterns\n\n**Backend (Go):**\n\n- CQRS: Separate commands (write) and queries (read)\n- Bus system: Dependency injection and service dispatch\n- Middleware chain: Auth, tenant resolution, CORS applied via routes\n- SQL-based data access: Direct SQL queries, no ORM\n\n**Frontend (React):**\n\n- SSR Support: Server-side rendering with React 18 hydration\n- i18n: LinguiJS for translations\n- Code splitting: Lazy-loaded page components\n- Type safety: Full TypeScript coverage\n\n## Troubleshooting\n\n**Database connection errors:**\n\n- Ensure Docker is running: `docker compose ps`\n- Check `.env` has correct `DATABASE_URL`\n- Run migrations: `make migrate`\n\n**Build failures:**\n\n- Clear build cache: `make clean && make build`\n- Check Go version: `go version` (need 1.26+; CI and the Dockerfile use 1.27)\n- Check Node version: `node --version` (need 21/22)\n\n**Tests failing:**\n\n- Ensure test database is migrated (happens automatically with `make test`)\n- Check `.test.env` configuration\n- Run specific test: `go test ./app/handlers -v -run TestName`\n\n**Port conflicts:**\n\n- Default ports: 3000 (app), 5432 (postgres), 8025 (mailhog)\n- Change in `.env` if needed\n\n## Development Tips\n\n- Use `make watch` for active development - it handles hot reload for both frontend and backend\n- MailHog captures all emails at http://localhost:8025\n- Frontend changes: Webpack rebuilds automatically\n- Backend changes: Air restarts server automatically\n- All routes are centralized in `app/cmd/routes.go` - start there when tracing request flow\n- Bus handlers are registered in service `Init()` methods\n- Utility CSS classes are in `public/assets/styles/utility/` - use these before adding custom styles\n"},"files":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code when working with the Fider codebase.\n\n## Repository Structure\n\n**Backend (Go):**\n\n- `app/handlers/` - HTTP request handlers\n- `app/models/` - Data models (entity, cmd, query, action, dto)\n- `app/services/` - Business logic and external service integrations\n- `app/pkg/bus/` - Service registry and dispatch system\n- `app/cmd/routes.go` - All HTTP routes defined here\n- `migrations/` - Database migrations (numbered SQL files)\n\n**Frontend (React/TypeScript):**\n\n- `public/pages/` - Page components (lazy-loaded)\n- `public/components/` - Reusable UI components\n- `public/services/` - Client-side services and API calls\n- `public/hooks/` - Custom React hooks\n- `public/assets/styles/` - SCSS styles with utility classes\n\n**Configuration:**\n\n- `.env` - Local environment config (copy from `.example.env`)\n- `Makefile` - Build and development commands\n\n## Local Development\n\nAll commands are defined in the Makefile.\n\n**Development:**\n\n- `make watch` - Hot reload for both server and UI (use this for active development)\n- `make migrate` - Run database migrations\n\n**Testing:**\n\n- `make test` - Run all tests (both Go and Jest)\n- `make lint` - Lint both server and UI code\n\nEssential: Run \"make lint\" and \"make test\" when you've completed any changes, to check the formatting and tests.\n\n**Building:**\n\n- `make build` - Build production-ready binaries and assets\n\n## Code Patterns & Examples\n\n### Backend: Adding a New API Endpoint\n\n**1. Define the route** in `app/cmd/routes.go`:\n\n```go\n// Public API\nengine.Get(\"/api/v1/posts\", handlers.SearchPosts())\n\n// Authenticated API (requires login)\nengine.Get(\"/api/v1/user/settings\", middlewares.IsAuthenticated(), handlers.UserSettings())\n\n// Admin only\nengine.Post(\"/api/v1/admin/members\", middlewares.IsAuthenticated(), middlewares.IsAuthorized(enum.RoleAdministrator), handlers.CreateMember())\n```\n\n**2. Create the handler** in `app/handlers/`:\n\n```go\npackage handlers\n\nimport (\n\t\"github.com/getfider/fider/app/models/cmd\"\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/bus\"\n\t\"github.com/getfider/fider/app/pkg/web\"\n)\n\n// SearchPosts returns posts matching criteria\nfunc SearchPosts() web.HandlerFunc {\n\treturn func(c *web.Context) error {\n\t\tq := &query.SearchPosts{\n\t\t\tQuery: c.QueryParam(\"query\"),\n\t\t\tLimit: 10,\n\t\t}\n\n\t\tif err := bus.Dispatch(c, q); err != nil {\n\t\t\treturn c.Failure(err)\n\t\t}\n\n\t\treturn c.Ok(q.Result)\n\t}\n}\n```\n\n**3. Define the query** in `app/models/query/`:\n\n```go\npackage query\n\nimport \"github.com/getfider/fider/app/models/entity\"\n\ntype SearchPosts struct {\n\tQuery  string\n\tLimit  int\n\tResult []*entity.Post\n}\n```\n\n**4. Implement the service** in `app/services/`:\n\n```go\npackage postgres\n\nimport (\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/dbx\"\n)\n\nfunc searchPosts(ctx context.Context, q *query.SearchPosts) error {\n\treturn using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error {\n\t\tq.Result = []*entity.Post{}\n\t\treturn trx.Select(&q.Result,\n\t\t\t\"SELECT * FROM posts WHERE title ILIKE $1 LIMIT $2\",\n\t\t\t\"%\"+q.Query+\"%\", q.Limit,\n\t\t)\n\t})\n}\n\nfunc init() {\n\tbus.Register(Service{})\n}\n\nfunc (s Service) Name() string {\n\treturn \"Postgres\"\n}\n\nfunc (s Service) Category() string {\n\treturn \"sqlstore\"\n}\n\nfunc (s Service) Enabled() bool {\n\treturn true\n}\n\nfunc (s Service) Init() {\n\tbus.AddHandler(searchPosts)\n}\n```\n\n### Frontend: Calling the API from React\n\n```typescript\n// In a React component\nimport { http } from \"@fider/services\"\n\nexport const PostSearch: React.FC = () => {\n  const [posts, setPosts] = React.useState([])\n  const [query, setQuery] = React.useState(\"\")\n\n  const handleSearch = async () => {\n    const result = await http.get<Post[]>(`/api/v1/posts?query=${query}`)\n    if (result.ok) {\n      setPosts(result.data)\n    }\n  }\n\n  return (\n    <div className=\"c-post-search\">\n      <input className=\"c-post-search__input\" value={query} onChange={(e) => setQuery(e.target.value)} />\n      <Button onClick={handleSearch}>Search</Button>\n    </div>\n  )\n}\n```\n\n### Model Naming Conventions\n\nUse these strict prefixes in `app/models/`:\n\n```go\n// entity.* - Database tables\ntype entity.User struct {\n    ID    int\n    Name  string\n    Email string\n}\n\n// action.* - User input for POST/PUT/PATCH (maps 1:1 to commands)\ntype action.CreatePost struct {\n    Title       string\n    Description string\n}\n\n// cmd.* - Commands to execute (potentially return values)\ntype cmd.SendEmail struct {\n    To      string\n    Subject string\n    Body    string\n}\n\n// query.* - Queries to fetch data\ntype query.GetPostByID struct {\n    PostID int\n    Result *entity.Post\n}\n\n// dto.* - Data transfer between packages\ntype dto.PostInfo struct {\n    Title     string\n    AuthorName string\n}\n```\n\n### CSS Conventions\n\nMost pages have a corresponding scss file. For example Home.Page.tsx imports Home.Page.scss which contains styles for various components in that page. These follow a BEM style:\n\n```scss\n// Page ID: p-<page_name>\n#p-home {\n  // Component: c-<component>\n  .c-post-list {\n    // Element: c-<component>__<element>\n    &__item {\n      padding: 1rem;\n    }\n\n    &__title {\n      font-size: 1.2rem;\n    }\n\n    // Modifier: c-<component>--<state>\n    &--loading {\n      opacity: 0.5;\n    }\n  }\n}\n```\n\nHowever, more recently, Utility classes were added to the codebase, to make it possible to apply classes in a utility style, similar to tailwind. If possible favour the utility classes over adding new styles for components and pages:\n\n```scss\n// Utility classes (no prefix) - defined in public/assets/styles/utility/\n.mt-2 {\n  margin-top: 0.5rem;\n}\n.flex {\n  display: flex;\n}\n```\n\nImportant: Do not just apply tailwind classes to new code, tailwind is not in use in this project. Check what is available in the utility scss files.\n\n## Common Tasks\n\n### Creating a Database Migration\n\n\"up migrations\" only.\n\n```bash\n# Create new migration file in migrations/ directory\n# Format: YYYYMMDDHHMMSS_description.sql\n# Example: migrations/202601041200_add_user_preferences.sql\n\nCREATE TABLE user_preferences (\n    id SERIAL PRIMARY KEY,\n    user_id INTEGER NOT NULL REFERENCES users(id),\n    theme VARCHAR(50),\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\n```\n\nRun with: `make migrate`\n\n### Adding a New Page Component\n\n```typescript\n// public/pages/MyNewPage/MyNewPage.page.tsx\nimport React from \"react\"\nimport { Page } from \"@fider/components\"\n\ninterface MyNewPageProps {\n  // Props here\n}\n\nconst MyNewPage: React.FC<MyNewPageProps> = (props) => {\n  return (\n    <Page id=\"p-my-new-page\">\n      <h1>My New Page</h1>\n    </Page>\n  )\n}\n\nexport default MyNewPage\n```\n\n```typescript\n// public/pages/MyNewPage/index.ts\nexport { default as MyNewPage } from \"./MyNewPage.page\"\n```\n\nRegister route in `app/handlers/` and lazy-load in `public/index.tsx`.\n\n### Using the Bus System\n\nThe bus handles service registration and dispatch:\n\n```go\n// Register a service\nbus.Register(MyService{})\n\n// Dispatch a query\nq := &query.GetUserByID{UserID: 123}\nif err := bus.Dispatch(ctx, q); err != nil {\n    return err\n}\nuser := q.Result\n\n// Dispatch a command\nc := &cmd.SendEmail{To: \"user@example.com\", Subject: \"Welcome\"}\nif err := bus.Dispatch(ctx, c); err != nil {\n    return err\n}\n```\n\n## Architecture Patterns\n\n**Backend (Go):**\n\n- CQRS: Separate commands (write) and queries (read)\n- Bus system: Dependency injection and service dispatch\n- Middleware chain: Auth, tenant resolution, CORS applied via routes\n- SQL-based data access: Direct SQL queries, no ORM\n\n**Frontend (React):**\n\n- SSR Support: Server-side rendering with React 18 hydration\n- i18n: LinguiJS for translations\n- Code splitting: Lazy-loaded page components\n- Type safety: Full TypeScript coverage\n\n## Troubleshooting\n\n**Database connection errors:**\n\n- Ensure Docker is running: `docker compose ps`\n- Check `.env` has correct `DATABASE_URL`\n- Run migrations: `make migrate`\n\n**Build failures:**\n\n- Clear build cache: `make clean && make build`\n- Check Go version: `go version` (need 1.26+; CI and the Dockerfile use 1.27)\n- Check Node version: `node --version` (need 21/22)\n\n**Tests failing:**\n\n- Ensure test database is migrated (happens automatically with `make test`)\n- Check `.test.env` configuration\n- Run specific test: `go test ./app/handlers -v -run TestName`\n\n**Port conflicts:**\n\n- Default ports: 3000 (app), 5432 (postgres), 8025 (mailhog)\n- Change in `.env` if needed\n\n## Development Tips\n\n- Use `make watch` for active development - it handles hot reload for both frontend and backend\n- MailHog captures all emails at http://localhost:8025\n- Frontend changes: Webpack rebuilds automatically\n- Backend changes: Air restarts server automatically\n- All routes are centralized in `app/cmd/routes.go` - start there when tracing request flow\n- Bus handlers are registered in service `Init()` methods\n- Utility CSS classes are in `public/assets/styles/utility/` - use these before adding custom styles\n"},"items":[{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/getfider/fider/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code when working with the Fider codebase.\n\n## Repository Structure\n\n**Backend (Go):**\n\n- `app/handlers/` - HTTP request handlers\n- `app/models/` - Data models (entity, cmd, query, action, dto)\n- `app/services/` - Business logic and external service integrations\n- `app/pkg/bus/` - Service registry and dispatch system\n- `app/cmd/routes.go` - All HTTP routes defined here\n- `migrations/` - Database migrations (numbered SQL files)\n\n**Frontend (React/TypeScript):**\n\n- `public/pages/` - Page components (lazy-loaded)\n- `public/components/` - Reusable UI components\n- `public/services/` - Client-side services and API calls\n- `public/hooks/` - Custom React hooks\n- `public/assets/styles/` - SCSS styles with utility classes\n\n**Configuration:**\n\n- `.env` - Local environment config (copy from `.example.env`)\n- `Makefile` - Build and development commands\n\n## Local Development\n\nAll commands are defined in the Makefile.\n\n**Development:**\n\n- `make watch` - Hot reload for both server and UI (use this for active development)\n- `make migrate` - Run database migrations\n\n**Testing:**\n\n- `make test` - Run all tests (both Go and Jest)\n- `make lint` - Lint both server and UI code\n\nEssential: Run \"make lint\" and \"make test\" when you've completed any changes, to check the formatting and tests.\n\n**Building:**\n\n- `make build` - Build production-ready binaries and assets\n\n## Code Patterns & Examples\n\n### Backend: Adding a New API Endpoint\n\n**1. Define the route** in `app/cmd/routes.go`:\n\n```go\n// Public API\nengine.Get(\"/api/v1/posts\", handlers.SearchPosts())\n\n// Authenticated API (requires login)\nengine.Get(\"/api/v1/user/settings\", middlewares.IsAuthenticated(), handlers.UserSettings())\n\n// Admin only\nengine.Post(\"/api/v1/admin/members\", middlewares.IsAuthenticated(), middlewares.IsAuthorized(enum.RoleAdministrator), handlers.CreateMember())\n```\n\n**2. Create the handler** in `app/handlers/`:\n\n```go\npackage handlers\n\nimport (\n\t\"github.com/getfider/fider/app/models/cmd\"\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/bus\"\n\t\"github.com/getfider/fider/app/pkg/web\"\n)\n\n// SearchPosts returns posts matching criteria\nfunc SearchPosts() web.HandlerFunc {\n\treturn func(c *web.Context) error {\n\t\tq := &query.SearchPosts{\n\t\t\tQuery: c.QueryParam(\"query\"),\n\t\t\tLimit: 10,\n\t\t}\n\n\t\tif err := bus.Dispatch(c, q); err != nil {\n\t\t\treturn c.Failure(err)\n\t\t}\n\n\t\treturn c.Ok(q.Result)\n\t}\n}\n```\n\n**3. Define the query** in `app/models/query/`:\n\n```go\npackage query\n\nimport \"github.com/getfider/fider/app/models/entity\"\n\ntype SearchPosts struct {\n\tQuery  string\n\tLimit  int\n\tResult []*entity.Post\n}\n```\n\n**4. Implement the service** in `app/services/`:\n\n```go\npackage postgres\n\nimport (\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/dbx\"\n)\n\nfunc searchPosts(ctx context.Context, q *query.SearchPosts) error {\n\treturn using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error {\n\t\tq.Result = []*entity.Post{}\n\t\treturn trx.Select(&q.Result,\n\t\t\t\"SELECT * FROM posts WHERE title ILIKE $1 LIMIT $2\",\n\t\t\t\"%\"+q.Query+\"%\", q.Limit,\n\t\t)\n\t})\n}\n\nfunc init() {\n\tbus.Register(Service{})\n}\n\nfunc (s Service) Name() string {\n\treturn \"Postgres\"\n}\n\nfunc (s Service) Category() string {\n\treturn \"sqlstore\"\n}\n\nfunc (s Service) Enabled() bool {\n\treturn true\n}\n\nfunc (s Service) Init() {\n\tbus.AddHandler(searchPosts)\n}\n```\n\n### Frontend: Calling the API from React\n\n```typescript\n// In a React component\nimport { http } from \"@fider/services\"\n\nexport const PostSearch: React.FC = () => {\n  const [posts, setPosts] = React.useState([])\n  const [query, setQuery] = React.useState(\"\")\n\n  const handleSearch = async () => {\n    const result = await http.get<Post[]>(`/api/v1/posts?query=${query}`)\n    if (result.ok) {\n      setPosts(result.data)\n    }\n  }\n\n  return (\n    <div className=\"c-post-search\">\n      <input className=\"c-post-search__input\" value={query} onChange={(e) => setQuery(e.target.value)} />\n      <Button onClick={handleSearch}>Search</Button>\n    </div>\n  )\n}\n```\n\n### Model Naming Conventions\n\nUse these strict prefixes in `app/models/`:\n\n```go\n// entity.* - Database tables\ntype entity.User struct {\n    ID    int\n    Name  string\n    Email string\n}\n\n// action.* - User input for POST/PUT/PATCH (maps 1:1 to commands)\ntype action.CreatePost struct {\n    Title       string\n    Description string\n}\n\n// cmd.* - Commands to execute (potentially return values)\ntype cmd.SendEmail struct {\n    To      string\n    Subject string\n    Body    string\n}\n\n// query.* - Queries to fetch data\ntype query.GetPostByID struct {\n    PostID int\n    Result *entity.Post\n}\n\n// dto.* - Data transfer between packages\ntype dto.PostInfo struct {\n    Title     string\n    AuthorName string\n}\n```\n\n### CSS Conventions\n\nMost pages have a corresponding scss file. For example Home.Page.tsx imports Home.Page.scss which contains styles for various components in that page. These follow a BEM style:\n\n```scss\n// Page ID: p-<page_name>\n#p-home {\n  // Component: c-<component>\n  .c-post-list {\n    // Element: c-<component>__<element>\n    &__item {\n      padding: 1rem;\n    }\n\n    &__title {\n      font-size: 1.2rem;\n    }\n\n    // Modifier: c-<component>--<state>\n    &--loading {\n      opacity: 0.5;\n    }\n  }\n}\n```\n\nHowever, more recently, Utility classes were added to the codebase, to make it possible to apply classes in a utility style, similar to tailwind. If possible favour the utility classes over adding new styles for components and pages:\n\n```scss\n// Utility classes (no prefix) - defined in public/assets/styles/utility/\n.mt-2 {\n  margin-top: 0.5rem;\n}\n.flex {\n  display: flex;\n}\n```\n\nImportant: Do not just apply tailwind classes to new code, tailwind is not in use in this project. Check what is available in the utility scss files.\n\n## Common Tasks\n\n### Creating a Database Migration\n\n\"up migrations\" only.\n\n```bash\n# Create new migration file in migrations/ directory\n# Format: YYYYMMDDHHMMSS_description.sql\n# Example: migrations/202601041200_add_user_preferences.sql\n\nCREATE TABLE user_preferences (\n    id SERIAL PRIMARY KEY,\n    user_id INTEGER NOT NULL REFERENCES users(id),\n    theme VARCHAR(50),\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\n```\n\nRun with: `make migrate`\n\n### Adding a New Page Component\n\n```typescript\n// public/pages/MyNewPage/MyNewPage.page.tsx\nimport React from \"react\"\nimport { Page } from \"@fider/components\"\n\ninterface MyNewPageProps {\n  // Props here\n}\n\nconst MyNewPage: React.FC<MyNewPageProps> = (props) => {\n  return (\n    <Page id=\"p-my-new-page\">\n      <h1>My New Page</h1>\n    </Page>\n  )\n}\n\nexport default MyNewPage\n```\n\n```typescript\n// public/pages/MyNewPage/index.ts\nexport { default as MyNewPage } from \"./MyNewPage.page\"\n```\n\nRegister route in `app/handlers/` and lazy-load in `public/index.tsx`.\n\n### Using the Bus System\n\nThe bus handles service registration and dispatch:\n\n```go\n// Register a service\nbus.Register(MyService{})\n\n// Dispatch a query\nq := &query.GetUserByID{UserID: 123}\nif err := bus.Dispatch(ctx, q); err != nil {\n    return err\n}\nuser := q.Result\n\n// Dispatch a command\nc := &cmd.SendEmail{To: \"user@example.com\", Subject: \"Welcome\"}\nif err := bus.Dispatch(ctx, c); err != nil {\n    return err\n}\n```\n\n## Architecture Patterns\n\n**Backend (Go):**\n\n- CQRS: Separate commands (write) and queries (read)\n- Bus system: Dependency injection and service dispatch\n- Middleware chain: Auth, tenant resolution, CORS applied via routes\n- SQL-based data access: Direct SQL queries, no ORM\n\n**Frontend (React):**\n\n- SSR Support: Server-side rendering with React 18 hydration\n- i18n: LinguiJS for translations\n- Code splitting: Lazy-loaded page components\n- Type safety: Full TypeScript coverage\n\n## Troubleshooting\n\n**Database connection errors:**\n\n- Ensure Docker is running: `docker compose ps`\n- Check `.env` has correct `DATABASE_URL`\n- Run migrations: `make migrate`\n\n**Build failures:**\n\n- Clear build cache: `make clean && make build`\n- Check Go version: `go version` (need 1.26+; CI and the Dockerfile use 1.27)\n- Check Node version: `node --version` (need 21/22)\n\n**Tests failing:**\n\n- Ensure test database is migrated (happens automatically with `make test`)\n- Check `.test.env` configuration\n- Run specific test: `go test ./app/handlers -v -run TestName`\n\n**Port conflicts:**\n\n- Default ports: 3000 (app), 5432 (postgres), 8025 (mailhog)\n- Change in `.env` if needed\n\n## Development Tips\n\n- Use `make watch` for active development - it handles hot reload for both frontend and backend\n- MailHog captures all emails at http://localhost:8025\n- Frontend changes: Webpack rebuilds automatically\n- Backend changes: Air restarts server automatically\n- All routes are centralized in `app/cmd/routes.go` - start there when tracing request flow\n- Bus handlers are registered in service `Init()` methods\n- Utility CSS classes are in `public/assets/styles/utility/` - use these before adding custom styles\n","isInternal":false,"tokens":2291,"sizeBytes":8971}],"systemPromptSnippet":"<yakaai_skills repo=\"getfider/fider\">\n<!-- File: CLAUDE.md (Tokens: ~2291 | Category: claude-rule) -->\n# CLAUDE.md\n\nThis file provides guidance to Claude Code when working with the Fider codebase.\n\n## Repository Structure\n\n**Backend (Go):**\n\n- `app/handlers/` - HTTP request handlers\n- `app/models/` - Data models (entity, cmd, query, action, dto)\n- `app/services/` - Business logic and external service integrations\n- `app/pkg/bus/` - Service registry and dispatch system\n- `app/cmd/routes.go` - All HTTP routes defined here\n- `migrations/` - Database migrations (numbered SQL files)\n\n**Frontend (React/TypeScript):**\n\n- `public/pages/` - Page components (lazy-loaded)\n- `public/components/` - Reusable UI components\n- `public/services/` - Client-side services and API calls\n- `public/hooks/` - Custom React hooks\n- `public/assets/styles/` - SCSS styles with utility classes\n\n**Configuration:**\n\n- `.env` - Local environment config (copy from `.example.env`)\n- `Makefile` - Build and development commands\n\n## Local Development\n\nAll commands are defined in the Makefile.\n\n**Development:**\n\n- `make watch` - Hot reload for both server and UI (use this for active development)\n- `make migrate` - Run database migrations\n\n**Testing:**\n\n- `make test` - Run all tests (both Go and Jest)\n- `make lint` - Lint both server and UI code\n\nEssential: Run \"make lint\" and \"make test\" when you've completed any changes, to check the formatting and tests.\n\n**Building:**\n\n- `make build` - Build production-ready binaries and assets\n\n## Code Patterns & Examples\n\n### Backend: Adding a New API Endpoint\n\n**1. Define the route** in `app/cmd/routes.go`:\n\n```go\n// Public API\nengine.Get(\"/api/v1/posts\", handlers.SearchPosts())\n\n// Authenticated API (requires login)\nengine.Get(\"/api/v1/user/settings\", middlewares.IsAuthenticated(), handlers.UserSettings())\n\n// Admin only\nengine.Post(\"/api/v1/admin/members\", middlewares.IsAuthenticated(), middlewares.IsAuthorized(enum.RoleAdministrator), handlers.CreateMember())\n```\n\n**2. Create the handler** in `app/handlers/`:\n\n```go\npackage handlers\n\nimport (\n\t\"github.com/getfider/fider/app/models/cmd\"\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/bus\"\n\t\"github.com/getfider/fider/app/pkg/web\"\n)\n\n// SearchPosts returns posts matching criteria\nfunc SearchPosts() web.HandlerFunc {\n\treturn func(c *web.Context) error {\n\t\tq := &query.SearchPosts{\n\t\t\tQuery: c.QueryParam(\"query\"),\n\t\t\tLimit: 10,\n\t\t}\n\n\t\tif err := bus.Dispatch(c, q); err != nil {\n\t\t\treturn c.Failure(err)\n\t\t}\n\n\t\treturn c.Ok(q.Result)\n\t}\n}\n```\n\n**3. Define the query** in `app/models/query/`:\n\n```go\npackage query\n\nimport \"github.com/getfider/fider/app/models/entity\"\n\ntype SearchPosts struct {\n\tQuery  string\n\tLimit  int\n\tResult []*entity.Post\n}\n```\n\n**4. Implement the service** in `app/services/`:\n\n```go\npackage postgres\n\nimport (\n\t\"github.com/getfider/fider/app/models/query\"\n\t\"github.com/getfider/fider/app/pkg/dbx\"\n)\n\nfunc searchPosts(ctx context.Context, q *query.SearchPosts) error {\n\treturn using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error {\n\t\tq.Result = []*entity.Post{}\n\t\treturn trx.Select(&q.Result,\n\t\t\t\"SELECT * FROM posts WHERE title ILIKE $1 LIMIT $2\",\n\t\t\t\"%\"+q.Query+\"%\", q.Limit,\n\t\t)\n\t})\n}\n\nfunc init() {\n\tbus.Register(Service{})\n}\n\nfunc (s Service) Name() string {\n\treturn \"Postgres\"\n}\n\nfunc (s Service) Category() string {\n\treturn \"sqlstore\"\n}\n\nfunc (s Service) Enabled() bool {\n\treturn true\n}\n\nfunc (s Service) Init() {\n\tbus.AddHandler(searchPosts)\n}\n```\n\n### Frontend: Calling the API from React\n\n```typescript\n// In a React component\nimport { http } from \"@fider/services\"\n\nexport const PostSearch: React.FC = () => {\n  const [posts, setPosts] = React.useState([])\n  const [query, setQuery] = React.useState(\"\")\n\n  const handleSearch = async () => {\n    const result = await http.get<Post[]>(`/api/v1/posts?query=${query}`)\n    if (result.ok) {\n      setPosts(result.data)\n    }\n  }\n\n  return (\n    <div className=\"c-post-search\">\n      <input className=\"c-post-search__input\" value={query} onChange={(e) => setQuery(e.target.value)} />\n      <Button onClick={handleSearch}>Search</Button>\n    </div>\n  )\n}\n```\n\n### Model Naming Conventions\n\nUse these strict prefixes in `app/models/`:\n\n```go\n// entity.* - Database tables\ntype entity.User struct {\n    ID    int\n    Name  string\n    Email string\n}\n\n// action.* - User input for POST/PUT/PATCH (maps 1:1 to commands)\ntype action.CreatePost struct {\n    Title       string\n    Description string\n}\n\n// cmd.* - Commands to execute (potentially return values)\ntype cmd.SendEmail struct {\n    To      string\n    Subject string\n    Body    string\n}\n\n// query.* - Queries to fetch data\ntype query.GetPostByID struct {\n    PostID int\n    Result *entity.Post\n}\n\n// dto.* - Data transfer between packages\ntype dto.PostInfo struct {\n    Title     string\n    AuthorName string\n}\n```\n\n### CSS Conventions\n\nMost pages have a corresponding scss file. For example Home.Page.tsx imports Home.Page.scss which contains styles for various components in that page. These follow a BEM style:\n\n```scss\n// Page ID: p-<page_name>\n#p-home {\n  // Component: c-<component>\n  .c-post-list {\n    // Element: c-<component>__<element>\n    &__item {\n      padding: 1rem;\n    }\n\n    &__title {\n      font-size: 1.2rem;\n    }\n\n    // Modifier: c-<component>--<state>\n    &--loading {\n      opacity: 0.5;\n    }\n  }\n}\n```\n\nHowever, more recently, Utility classes were added to the codebase, to make it possible to apply classes in a utility style, similar to tailwind. If possible favour the utility classes over adding new styles for components and pages:\n\n```scss\n// Utility classes (no prefix) - defined in public/assets/styles/utility/\n.mt-2 {\n  margin-top: 0.5rem;\n}\n.flex {\n  display: flex;\n}\n```\n\nImportant: Do not just apply tailwind classes to new code, tailwind is not in use in this project. Check what is available in the utility scss files.\n\n## Common Tasks\n\n### Creating a Database Migration\n\n\"up migrations\" only.\n\n```bash\n# Create new migration file in migrations/ directory\n# Format: YYYYMMDDHHMMSS_description.sql\n# Example: migrations/202601041200_add_user_preferences.sql\n\nCREATE TABLE user_preferences (\n    id SERIAL PRIMARY KEY,\n    user_id INTEGER NOT NULL REFERENCES users(id),\n    theme VARCHAR(50),\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\n```\n\nRun with: `make migrate`\n\n### Adding a New Page Component\n\n```typescript\n// public/pages/MyNewPage/MyNewPage.page.tsx\nimport React from \"react\"\nimport { Page } from \"@fider/components\"\n\ninterface MyNewPageProps {\n  // Props here\n}\n\nconst MyNewPage: React.FC<MyNewPageProps> = (props) => {\n  return (\n    <Page id=\"p-my-new-page\">\n      <h1>My New Page</h1>\n    </Page>\n  )\n}\n\nexport default MyNewPage\n```\n\n```typescript\n// public/pages/MyNewPage/index.ts\nexport { default as MyNewPage } from \"./MyNewPage.page\"\n```\n\nRegister route in `app/handlers/` and lazy-load in `public/index.tsx`.\n\n### Using the Bus System\n\nThe bus handles service registration and dispatch:\n\n```go\n// Register a service\nbus.Register(MyService{})\n\n// Dispatch a query\nq := &query.GetUserByID{UserID: 123}\nif err := bus.Dispatch(ctx, q); err != nil {\n    return err\n}\nuser := q.Result\n\n// Dispatch a command\nc := &cmd.SendEmail{To: \"user@example.com\", Subject: \"Welcome\"}\nif err := bus.Dispatch(ctx, c); err != nil {\n    return err\n}\n```\n\n## Architecture Patterns\n\n**Backend (Go):**\n\n- CQRS: Separate commands (write) and queries (read)\n- Bus system: Dependency injection and service dispatch\n- Middleware chain: Auth, tenant resolution, CORS applied via routes\n- SQL-based data access: Direct SQL queries, no ORM\n\n**Frontend (React):**\n\n- SSR Support: Server-side rendering with React 18 hydration\n- i18n: LinguiJS for translations\n- Code splitting: Lazy-loaded page components\n- Type safety: Full TypeScript coverage\n\n## Troubleshooting\n\n**Database connection errors:**\n\n- Ensure Docker is running: `docker compose ps`\n- Check `.env` has correct `DATABASE_URL`\n- Run migrations: `make migrate`\n\n**Build failures:**\n\n- Clear build cache: `make clean && make build`\n- Check Go version: `go version` (need 1.26+; CI and the Dockerfile use 1.27)\n- Check Node version: `node --version` (need 21/22)\n\n**Tests failing:**\n\n- Ensure test database is migrated (happens automatically with `make test`)\n- Check `.test.env` configuration\n- Run specific test: `go test ./app/handlers -v -run TestName`\n\n**Port conflicts:**\n\n- Default ports: 3000 (app), 5432 (postgres), 8025 (mailhog)\n- Change in `.env` if needed\n\n## Development Tips\n\n- Use `make watch` for active development - it handles hot reload for both frontend and backend\n- MailHog captures all emails at http://localhost:8025\n- Frontend changes: Webpack rebuilds automatically\n- Backend changes: Air restarts server automatically\n- All routes are centralized in `app/cmd/routes.go` - start there when tracing request flow\n- Bus handlers are registered in service `Init()` methods\n- Utility CSS classes are in `public/assets/styles/utility/` - use these before adding custom styles\n</yakaai_skills>"}