{"owner":"Unleash","repo":"unleash","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# Agent Instructions for Unleash\n\nThis document provides AI coding assistants with context about the Unleash codebase. It is tool-agnostic and can be referenced by any AI assistant configuration.\n\n## Project Overview\n\nUnleash is an open-source feature flagging platform. This repository (OSS) is a monorepo containing:\n\n- **Backend**: Node.js/TypeScript REST API (`/src`)\n- **Frontend**: React/TypeScript single-page application (`/frontend`)\n\n**Enterprise** extends OSS via a separate repository (`unleash-enterprise`) using a hook-based architecture. Enterprise does not fork OSS; it injects additional functionality through `preRouterHook`. If the user says that this is an enterprise feature, you need to ask where the enterprise repository is located and work across both this repository and the enterprise repository. \n\n## Architecture\n\n### Backend (`/src`)\n\nThe backend follows a **CSR (Controller, Service, Repository/Store)** pattern. We promote packages by feature, not by layer (see feature-based modules below), although the legacy components are still packed by layer:\n\n- **Controllers** (`/src/lib/routes/`): Handle HTTP requests, validate input, delegate business logic to services, and demarcate transactions.\n- **Services** (`/src/lib/services/`): Business logic layer, emit events, manage transactions\n- **Stores** (`/src/lib/db/`): Data access layer using Knex query builder\n\n**Feature-based modules** live in `/src/lib/features/` where each domain contains its own controller, service, store, and types. Examples: `feature-toggle`, `project`, `segment`, `change-request`, `release-plans`.\n\n**Key Patterns**:\n- **Audit-log**: Services emit typed events (`FeatureCreatedEvent`, etc.) for audit trails and read model updates\n- **Transaction wrapper**: Use `withTransactional()` for atomic operations across services. The common pattern is initiating transactions at the controller level.\n- **Fake implementations**: Every store/service has a Fake variant for testing (prefer over mocking)\n- **Internal feature flags**: `flagResolver.isEnabled()` controls operational features\n\n**Stack**: Express, PostgreSQL with Knex, TypeScript with ES modules\n\n### Frontend (`/frontend/src`)\n\nThe frontend is a React SPA communicating with the backend via REST API.\n\n- **Components**: `/frontend/src/component/` - React components organized by feature domain\n- **Hooks**: `/frontend/src/hooks/` - 71+ custom hooks for data fetching and mutations\n- **Contexts**: `AccessContext` (permissions), `UIContext` (toasts, theme)\n\n**Key Patterns**:\n- **Data fetching**: SWR-based `useApiGetter` hooks for GET requests with caching\n- **Mutations**: `useApi` hook for POST/PUT/DELETE with error handling\n- **Route gating**: Routes support `flag`, `enterprise`, and `configFlag` properties\n- **Styling**: MUI `styled()` components with emotion, use `sx` for one-offs\n\n**Stack**: React 18+, Vite, Material-UI (MUI), SWR for server state\n\n## Enterprise Integration\n\nEnterprise extends OSS through hooks without forking:\n\n1. **Entry**: `unleash-enterprise/src/index.ts` wraps OSS `start()`/`create()`\n2. **Hook**: `preRouterHook` runs after OSS init, before route binding\n3. **Extension**: Adds 50+ services, 30+ stores, 50+ controllers\n4. **Gating**: License middleware restricts enterprise features\n\n**Enterprise-Only Features**: Change Requests, SSO (SAML/OIDC), Service Accounts, Signals & Actions, Insights, SCIM, Private Projects, Release Plans, Safeguards\n\n**Combined Interfaces**: `IEnterpriseServices extends IUnleashServices`, `IUnleashEnterpriseStores extends IUnleashStores`\n\n## Composition Root Pattern\n\nAll dependencies are wired at application startup, not scattered throughout the codebase. All services have a dedicated composition root function to stand up the service.:\n\n**OSS Composition**:\n- `/src/lib/db/index.ts` → `createStores()` instantiates all stores with Knex connection\n- `/src/lib/services/index.ts` → `createServices()` instantiates all services with stores + config\n- `/src/lib/server-impl.ts` → Orchestrates: DB → Stores → Services → App\n\n**Enterprise Composition**:\n- `enterprise/src/util/setup-stores.ts` → Creates enterprise stores, merges with OSS stores\n- `enterprise/src/util/setup-services.ts` → Creates enterprise services with combined stores\n- `enterprise/src/create-enterprise-routes.ts` → Wires everything in `preRouterHook`\n\n**Why this matters**: Never `new` a service/store inline. Always receive dependencies through constructor injection. This enables testing with fakes and keeps the dependency graph explicit.\n\n## Read Models vs Write Models\n\nTo avoid overloading stores with complex queries, we separate read and write concerns:\n\n**Write Models (Stores)**: Handle CRUD operations on single entities\n- Keep queries simple: insert, update, delete, getById\n- Located in `/src/lib/db/` or feature directories\n- Example: `FeatureToggleStore` handles basic feature CRUD\n\n**Read Models**: Handle complex queries, aggregations, cross-domain queries and denormalized views\n- Optimized for specific read use cases (dashboards, lists, reports)\n- Located in feature `/read-models/` directories\n- Example: `FeatureStrategiesReadModel`, `ProjectOwnersReadModel`, `FeatureSearchReadModel`\n\n**When to use Read Models**:\n- Query spans multiple tables with complex joins\n- Need denormalized data for performance\n- Building dashboard/overview endpoints\n- Query doesn't map to a single entity's lifecycle\n- You don't want to expose the entire write model and only need one value from another module\n\n**Pattern**: Services coordinate between stores (writes) and read models (reads). Controllers call services or read models, never stores directly.\n\n## Development Philosophy\n\nWe follow three core principles:\n\n1. **Test code always** - We test our code and prefer automation over manual testing\n2. **Write maintainable code** - Code is communication; clarity and readability are paramount\n3. **Think before committing** \n\n## Coding Standards\n\nDetailed standards are documented as Architectural Decision Records (ADRs). They can be located:\n- /contributing/ADRs/back-end/\n- /contributing/ADRs/front-end/\n- /contributing/ADRs/overarching/\n\nInstead of `!!someVariable` prefer `Boolean(someVariable)`. \n\n## Database Migrations\n\n- Migrations live in `/src/migrations/`\n- Never modify a merged migration; create a new one instead\n- Each migration needs `up` and `down` methods\n- Use `pnpm db-migrate create <name>` to create new migrations\n\n## Testing\n\n- **Backend**: Vitest + Supertest for API testing; fake stores for isolation\n- **Frontend**: Vitest + Testing Library\n- **E2E**: Cypress (`/frontend/cypress/`)\n\nRun tests with:\n```bash\npnpm test          # All tests\npnpm test:frontend # Frontend only\npnpm test:backend  # Backend only\n```\n\n## Critical Files Reference\n\n### OSS Entry Points\n| File | Purpose |\n|------|---------|\n| `/src/server.ts` | Main entry point |\n| `/src/lib/app.ts` | Express app setup, middleware stack |\n| `/src/lib/routes/index.ts` | Route registration |\n| `/src/lib/services/index.ts` | Service factory |\n| `/src/lib/db/index.ts` | Store factory |\n| `/src/lib/types/index.js` | Importing types | \n\n### Pattern References\n| Pattern | Example Location |\n|---------|-----------------|\n| Controller | `/src/lib/features/feature-toggle/feature-toggle-controller.ts` |\n| Service | `/src/lib/features/feature-toggle/feature-toggle-service.ts` |\n| Store (write model) | `/src/lib/features/feature-toggle/feature-toggle-store.ts` |\n| Read Model | `/src/lib/features/feature-search/feature-search-read-model.ts` |\n| Composition Root | `/src/lib/services/index.ts` |\n| API Hook (GET) | `/frontend/src/hooks/api/getters/useFeature/useFeature.ts` |\n| API Hook (mutation) | `/frontend/src/hooks/api/actions/useFeatureApi.ts` |\n| Fake Store | `/src/test/fixtures/fake-feature-toggle-store.ts` |\n\n"},"files":{"AGENTS.md":"# Agent Instructions for Unleash\n\nThis document provides AI coding assistants with context about the Unleash codebase. It is tool-agnostic and can be referenced by any AI assistant configuration.\n\n## Project Overview\n\nUnleash is an open-source feature flagging platform. This repository (OSS) is a monorepo containing:\n\n- **Backend**: Node.js/TypeScript REST API (`/src`)\n- **Frontend**: React/TypeScript single-page application (`/frontend`)\n\n**Enterprise** extends OSS via a separate repository (`unleash-enterprise`) using a hook-based architecture. Enterprise does not fork OSS; it injects additional functionality through `preRouterHook`. If the user says that this is an enterprise feature, you need to ask where the enterprise repository is located and work across both this repository and the enterprise repository. \n\n## Architecture\n\n### Backend (`/src`)\n\nThe backend follows a **CSR (Controller, Service, Repository/Store)** pattern. We promote packages by feature, not by layer (see feature-based modules below), although the legacy components are still packed by layer:\n\n- **Controllers** (`/src/lib/routes/`): Handle HTTP requests, validate input, delegate business logic to services, and demarcate transactions.\n- **Services** (`/src/lib/services/`): Business logic layer, emit events, manage transactions\n- **Stores** (`/src/lib/db/`): Data access layer using Knex query builder\n\n**Feature-based modules** live in `/src/lib/features/` where each domain contains its own controller, service, store, and types. Examples: `feature-toggle`, `project`, `segment`, `change-request`, `release-plans`.\n\n**Key Patterns**:\n- **Audit-log**: Services emit typed events (`FeatureCreatedEvent`, etc.) for audit trails and read model updates\n- **Transaction wrapper**: Use `withTransactional()` for atomic operations across services. The common pattern is initiating transactions at the controller level.\n- **Fake implementations**: Every store/service has a Fake variant for testing (prefer over mocking)\n- **Internal feature flags**: `flagResolver.isEnabled()` controls operational features\n\n**Stack**: Express, PostgreSQL with Knex, TypeScript with ES modules\n\n### Frontend (`/frontend/src`)\n\nThe frontend is a React SPA communicating with the backend via REST API.\n\n- **Components**: `/frontend/src/component/` - React components organized by feature domain\n- **Hooks**: `/frontend/src/hooks/` - 71+ custom hooks for data fetching and mutations\n- **Contexts**: `AccessContext` (permissions), `UIContext` (toasts, theme)\n\n**Key Patterns**:\n- **Data fetching**: SWR-based `useApiGetter` hooks for GET requests with caching\n- **Mutations**: `useApi` hook for POST/PUT/DELETE with error handling\n- **Route gating**: Routes support `flag`, `enterprise`, and `configFlag` properties\n- **Styling**: MUI `styled()` components with emotion, use `sx` for one-offs\n\n**Stack**: React 18+, Vite, Material-UI (MUI), SWR for server state\n\n## Enterprise Integration\n\nEnterprise extends OSS through hooks without forking:\n\n1. **Entry**: `unleash-enterprise/src/index.ts` wraps OSS `start()`/`create()`\n2. **Hook**: `preRouterHook` runs after OSS init, before route binding\n3. **Extension**: Adds 50+ services, 30+ stores, 50+ controllers\n4. **Gating**: License middleware restricts enterprise features\n\n**Enterprise-Only Features**: Change Requests, SSO (SAML/OIDC), Service Accounts, Signals & Actions, Insights, SCIM, Private Projects, Release Plans, Safeguards\n\n**Combined Interfaces**: `IEnterpriseServices extends IUnleashServices`, `IUnleashEnterpriseStores extends IUnleashStores`\n\n## Composition Root Pattern\n\nAll dependencies are wired at application startup, not scattered throughout the codebase. All services have a dedicated composition root function to stand up the service.:\n\n**OSS Composition**:\n- `/src/lib/db/index.ts` → `createStores()` instantiates all stores with Knex connection\n- `/src/lib/services/index.ts` → `createServices()` instantiates all services with stores + config\n- `/src/lib/server-impl.ts` → Orchestrates: DB → Stores → Services → App\n\n**Enterprise Composition**:\n- `enterprise/src/util/setup-stores.ts` → Creates enterprise stores, merges with OSS stores\n- `enterprise/src/util/setup-services.ts` → Creates enterprise services with combined stores\n- `enterprise/src/create-enterprise-routes.ts` → Wires everything in `preRouterHook`\n\n**Why this matters**: Never `new` a service/store inline. Always receive dependencies through constructor injection. This enables testing with fakes and keeps the dependency graph explicit.\n\n## Read Models vs Write Models\n\nTo avoid overloading stores with complex queries, we separate read and write concerns:\n\n**Write Models (Stores)**: Handle CRUD operations on single entities\n- Keep queries simple: insert, update, delete, getById\n- Located in `/src/lib/db/` or feature directories\n- Example: `FeatureToggleStore` handles basic feature CRUD\n\n**Read Models**: Handle complex queries, aggregations, cross-domain queries and denormalized views\n- Optimized for specific read use cases (dashboards, lists, reports)\n- Located in feature `/read-models/` directories\n- Example: `FeatureStrategiesReadModel`, `ProjectOwnersReadModel`, `FeatureSearchReadModel`\n\n**When to use Read Models**:\n- Query spans multiple tables with complex joins\n- Need denormalized data for performance\n- Building dashboard/overview endpoints\n- Query doesn't map to a single entity's lifecycle\n- You don't want to expose the entire write model and only need one value from another module\n\n**Pattern**: Services coordinate between stores (writes) and read models (reads). Controllers call services or read models, never stores directly.\n\n## Development Philosophy\n\nWe follow three core principles:\n\n1. **Test code always** - We test our code and prefer automation over manual testing\n2. **Write maintainable code** - Code is communication; clarity and readability are paramount\n3. **Think before committing** \n\n## Coding Standards\n\nDetailed standards are documented as Architectural Decision Records (ADRs). They can be located:\n- /contributing/ADRs/back-end/\n- /contributing/ADRs/front-end/\n- /contributing/ADRs/overarching/\n\nInstead of `!!someVariable` prefer `Boolean(someVariable)`. \n\n## Database Migrations\n\n- Migrations live in `/src/migrations/`\n- Never modify a merged migration; create a new one instead\n- Each migration needs `up` and `down` methods\n- Use `pnpm db-migrate create <name>` to create new migrations\n\n## Testing\n\n- **Backend**: Vitest + Supertest for API testing; fake stores for isolation\n- **Frontend**: Vitest + Testing Library\n- **E2E**: Cypress (`/frontend/cypress/`)\n\nRun tests with:\n```bash\npnpm test          # All tests\npnpm test:frontend # Frontend only\npnpm test:backend  # Backend only\n```\n\n## Critical Files Reference\n\n### OSS Entry Points\n| File | Purpose |\n|------|---------|\n| `/src/server.ts` | Main entry point |\n| `/src/lib/app.ts` | Express app setup, middleware stack |\n| `/src/lib/routes/index.ts` | Route registration |\n| `/src/lib/services/index.ts` | Service factory |\n| `/src/lib/db/index.ts` | Store factory |\n| `/src/lib/types/index.js` | Importing types | \n\n### Pattern References\n| Pattern | Example Location |\n|---------|-----------------|\n| Controller | `/src/lib/features/feature-toggle/feature-toggle-controller.ts` |\n| Service | `/src/lib/features/feature-toggle/feature-toggle-service.ts` |\n| Store (write model) | `/src/lib/features/feature-toggle/feature-toggle-store.ts` |\n| Read Model | `/src/lib/features/feature-search/feature-search-read-model.ts` |\n| Composition Root | `/src/lib/services/index.ts` |\n| API Hook (GET) | `/frontend/src/hooks/api/getters/useFeature/useFeature.ts` |\n| API Hook (mutation) | `/frontend/src/hooks/api/actions/useFeatureApi.ts` |\n| Fake Store | `/src/test/fixtures/fake-feature-toggle-store.ts` |\n\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Agent Instructions for Unleash\n\nThis document provides AI coding assistants with context about the Unleash codebase. It is tool-agnostic and can be referenced by any AI assistant configuration.\n\n## Project Overview\n\nUnleash is an open-source feature flagging platform. This repository (OSS) is a monorepo containing:\n\n- **Backend**: Node.js/TypeScript REST API (`/src`)\n- **Frontend**: React/TypeScript single-page application (`/frontend`)\n\n**Enterprise** extends OSS via a separate repository (`unleash-enterprise`) using a hook-based architecture. Enterprise does not fork OSS; it injects additional functionality through `preRouterHook`. If the user says that this is an enterprise feature, you need to ask where the enterprise repository is located and work across both this repository and the enterprise repository. \n\n## Architecture\n\n### Backend (`/src`)\n\nThe backend follows a **CSR (Controller, Service, Repository/Store)** pattern. We promote packages by feature, not by layer (see feature-based modules below), although the legacy components are still packed by layer:\n\n- **Controllers** (`/src/lib/routes/`): Handle HTTP requests, validate input, delegate business logic to services, and demarcate transactions.\n- **Services** (`/src/lib/services/`): Business logic layer, emit events, manage transactions\n- **Stores** (`/src/lib/db/`): Data access layer using Knex query builder\n\n**Feature-based modules** live in `/src/lib/features/` where each domain contains its own controller, service, store, and types. Examples: `feature-toggle`, `project`, `segment`, `change-request`, `release-plans`.\n\n**Key Patterns**:\n- **Audit-log**: Services emit typed events (`FeatureCreatedEvent`, etc.) for audit trails and read model updates\n- **Transaction wrapper**: Use `withTransactional()` for atomic operations across services. The common pattern is initiating transactions at the controller level.\n- **Fake implementations**: Every store/service has a Fake variant for testing (prefer over mocking)\n- **Internal feature flags**: `flagResolver.isEnabled()` controls operational features\n\n**Stack**: Express, PostgreSQL with Knex, TypeScript with ES modules\n\n### Frontend (`/frontend/src`)\n\nThe frontend is a React SPA communicating with the backend via REST API.\n\n- **Components**: `/frontend/src/component/` - React components organized by feature domain\n- **Hooks**: `/frontend/src/hooks/` - 71+ custom hooks for data fetching and mutations\n- **Contexts**: `AccessContext` (permissions), `UIContext` (toasts, theme)\n\n**Key Patterns**:\n- **Data fetching**: SWR-based `useApiGetter` hooks for GET requests with caching\n- **Mutations**: `useApi` hook for POST/PUT/DELETE with error handling\n- **Route gating**: Routes support `flag`, `enterprise`, and `configFlag` properties\n- **Styling**: MUI `styled()` components with emotion, use `sx` for one-offs\n\n**Stack**: React 18+, Vite, Material-UI (MUI), SWR for server state\n\n## Enterprise Integration\n\nEnterprise extends OSS through hooks without forking:\n\n1. **Entry**: `unleash-enterprise/src/index.ts` wraps OSS `start()`/`create()`\n2. **Hook**: `preRouterHook` runs after OSS init, before route binding\n3. **Extension**: Adds 50+ services, 30+ stores, 50+ controllers\n4. **Gating**: License middleware restricts enterprise features\n\n**Enterprise-Only Features**: Change Requests, SSO (SAML/OIDC), Service Accounts, Signals & Actions, Insights, SCIM, Private Projects, Release Plans, Safeguards\n\n**Combined Interfaces**: `IEnterpriseServices extends IUnleashServices`, `IUnleashEnterpriseStores extends IUnleashStores`\n\n## Composition Root Pattern\n\nAll dependencies are wired at application startup, not scattered throughout the codebase. All services have a dedicated composition root function to stand up the service.:\n\n**OSS Composition**:\n- `/src/lib/db/index.ts` → `createStores()` instantiates all stores with Knex connection\n- `/src/lib/services/index.ts` → `createServices()` instantiates all services with stores + config\n- `/src/lib/server-impl.ts` → Orchestrates: DB → Stores → Services → App\n\n**Enterprise Composition**:\n- `enterprise/src/util/setup-stores.ts` → Creates enterprise stores, merges with OSS stores\n- `enterprise/src/util/setup-services.ts` → Creates enterprise services with combined stores\n- `enterprise/src/create-enterprise-routes.ts` → Wires everything in `preRouterHook`\n\n**Why this matters**: Never `new` a service/store inline. Always receive dependencies through constructor injection. This enables testing with fakes and keeps the dependency graph explicit.\n\n## Read Models vs Write Models\n\nTo avoid overloading stores with complex queries, we separate read and write concerns:\n\n**Write Models (Stores)**: Handle CRUD operations on single entities\n- Keep queries simple: insert, update, delete, getById\n- Located in `/src/lib/db/` or feature directories\n- Example: `FeatureToggleStore` handles basic feature CRUD\n\n**Read Models**: Handle complex queries, aggregations, cross-domain queries and denormalized views\n- Optimized for specific read use cases (dashboards, lists, reports)\n- Located in feature `/read-models/` directories\n- Example: `FeatureStrategiesReadModel`, `ProjectOwnersReadModel`, `FeatureSearchReadModel`\n\n**When to use Read Models**:\n- Query spans multiple tables with complex joins\n- Need denormalized data for performance\n- Building dashboard/overview endpoints\n- Query doesn't map to a single entity's lifecycle\n- You don't want to expose the entire write model and only need one value from another module\n\n**Pattern**: Services coordinate between stores (writes) and read models (reads). Controllers call services or read models, never stores directly.\n\n## Development Philosophy\n\nWe follow three core principles:\n\n1. **Test code always** - We test our code and prefer automation over manual testing\n2. **Write maintainable code** - Code is communication; clarity and readability are paramount\n3. **Think before committing** \n\n## Coding Standards\n\nDetailed standards are documented as Architectural Decision Records (ADRs). They can be located:\n- /contributing/ADRs/back-end/\n- /contributing/ADRs/front-end/\n- /contributing/ADRs/overarching/\n\nInstead of `!!someVariable` prefer `Boolean(someVariable)`. \n\n## Database Migrations\n\n- Migrations live in `/src/migrations/`\n- Never modify a merged migration; create a new one instead\n- Each migration needs `up` and `down` methods\n- Use `pnpm db-migrate create <name>` to create new migrations\n\n## Testing\n\n- **Backend**: Vitest + Supertest for API testing; fake stores for isolation\n- **Frontend**: Vitest + Testing Library\n- **E2E**: Cypress (`/frontend/cypress/`)\n\nRun tests with:\n```bash\npnpm test          # All tests\npnpm test:frontend # Frontend only\npnpm test:backend  # Backend only\n```\n\n## Critical Files Reference\n\n### OSS Entry Points\n| File | Purpose |\n|------|---------|\n| `/src/server.ts` | Main entry point |\n| `/src/lib/app.ts` | Express app setup, middleware stack |\n| `/src/lib/routes/index.ts` | Route registration |\n| `/src/lib/services/index.ts` | Service factory |\n| `/src/lib/db/index.ts` | Store factory |\n| `/src/lib/types/index.js` | Importing types | \n\n### Pattern References\n| Pattern | Example Location |\n|---------|-----------------|\n| Controller | `/src/lib/features/feature-toggle/feature-toggle-controller.ts` |\n| Service | `/src/lib/features/feature-toggle/feature-toggle-service.ts` |\n| Store (write model) | `/src/lib/features/feature-toggle/feature-toggle-store.ts` |\n| Read Model | `/src/lib/features/feature-search/feature-search-read-model.ts` |\n| Composition Root | `/src/lib/services/index.ts` |\n| API Hook (GET) | `/frontend/src/hooks/api/getters/useFeature/useFeature.ts` |\n| API Hook (mutation) | `/frontend/src/hooks/api/actions/useFeatureApi.ts` |\n| Fake Store | `/src/test/fixtures/fake-feature-toggle-store.ts` |\n\n","category":"root","tokens":1956}]}