Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.git
.vs
**/.vs
**/bin
**/obj
**/*.user
**/*.suo
tests
benchmarks
docs
web
node_modules
artifacts
*.binlog
12 changes: 9 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ WORKDIR /build
COPY src/BuildingBlocks/Mediator/*.csproj ./src/BuildingBlocks/Mediator/
COPY src/BuildingBlocks/Mediator.Analyzers/*.csproj ./src/BuildingBlocks/Mediator.Analyzers/
COPY src/BuildingBlocks/Telemetry/*.csproj ./src/BuildingBlocks/Telemetry/
COPY src/BuildingBlocks/Domain/*.csproj ./src/BuildingBlocks/Domain/
COPY src/BuildingBlocks/Domain.EntityFrameworkCore/*.csproj ./src/BuildingBlocks/Domain.EntityFrameworkCore/
COPY src/BuildingBlocks/Idempotency/*.csproj ./src/BuildingBlocks/Idempotency/
COPY src/BuildingBlocks/Mcp/*.csproj ./src/BuildingBlocks/Mcp/
COPY src/BuildingBlocks/Mcp.Analyzers/*.csproj ./src/BuildingBlocks/Mcp.Analyzers/
COPY src/BuildingBlocks/Pagination/*.csproj ./src/BuildingBlocks/Pagination/
COPY src/BuildingBlocks/Pagination.EntityFrameworkCore/*.csproj ./src/BuildingBlocks/Pagination.EntityFrameworkCore/
COPY src/BuildingBlocks/Pagination.Dapper/*.csproj ./src/BuildingBlocks/Pagination.Dapper/
COPY src/Lab/EventBus/*.csproj ./src/Lab/EventBus/
COPY src/Lab/FeatureFusion.ServiceDefaults/*.csproj ./src/Lab/FeatureFusion.ServiceDefaults/
COPY src/Lab/FeatureFusion/*.csproj ./src/Lab/FeatureFusion/
Expand All @@ -16,13 +24,11 @@ COPY src/Lab/FeatureFusion.ServiceDefaults/ ./src/Lab/FeatureFusion.ServiceDefau
COPY src/Lab/FeatureFusion/ ./src/Lab/FeatureFusion/

WORKDIR /build/src/Lab/FeatureFusion
RUN dotnet publish FeatureFusion.csproj -c Release -o /out --no-restore
RUN dotnet publish FeatureFusion.csproj -c Release -f net10.0 -o /out --no-restore /p:EnableSourceControlManagerQueries=false

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
COPY --from=build /out ./
EXPOSE 5004
ENV ASPNETCORE_URLS=http://+:5004
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD curl -f http://localhost:5004/health || exit 1
ENTRYPOINT ["dotnet", "FeatureFusion.dll"]
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -895,22 +895,29 @@ The SigNoz UI always shows a **login** page. Root-user env vars skip the first-r

Those custom credentials are **not** shown on the Aspire resource panel (only package-default `WithUi()` creds are). Package defaults, if you call `WithUi()` with no overrides, are `admin@localhost.local` / `Admin@Signoz1`. If login fails after changing email, delete the persistent SigNoz sqlite volume and restart AppHost.

### Option B — Docker Compose
### Option B — Docker Compose (full stack)

From the repository root:

```bash
docker compose up -d --build
```

Uses SDK / ASP.NET **10.0** images plus supporting services.
Starts Postgres (`catalogdb`, ephemeral), Redis, RabbitMQ, Memcached, and FeatureFusion. Compose waits until those four services are **healthy** before starting the API (same idea as AppHost `WaitFor`). The API is on `http://localhost:5141`. Postgres data is not persisted; a new compose project gets an empty DB, then migrate + seed.

The FeatureFusion image still needs those four services. Do not `docker run` it alone.

### Option C — API only (infra already running)

### Option C — API only
Start backing services, then the API:

```bash
docker compose up -d postgres redis eventbus memcached
dotnet restore FeatureFusion.sln
dotnet run --project src/Lab/FeatureFusion --launch-profile https
```

Point connection strings in `appsettings.*.json` (or user secrets) at your local infra.
`appsettings.Development.json` expects Postgres/Redis/Rabbit/Memcached on localhost (database name `catalogdb`). FeatureFusion does not create Postgres itself. AppHost is an alternative to Compose for the same infra.

<details>
<summary>Feature-flag greeting smoke</summary>
Expand Down
65 changes: 26 additions & 39 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,43 @@ services:
ports:
- "11211:11211"
healthcheck:
test: ["CMD", "nc", "-z", "memcached", "11211"]
test: ["CMD", "nc", "-z", "127.0.0.1", "11211"]
interval: 5s
timeout: 3s
retries: 5

redis:
image: redis:latest
image: redis:8.6
ports:
- "6379:6379"
command: "redis-server"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-h", "redis", "ping"]
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5

eventbus:
image: rabbitmq:management
hostname: eventbus
container_name: eventbus
image: rabbitmq:4.3
hostname: eventbus
container_name: eventbus
networks:
default:
aliases:
- rabbitmq
- eventbus
- rabbitmq
- eventbus
ports:
- "5672:5672"
- "15672:15672"
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
RABBITMQ_DEFAULT_VHOST: /
RABBITMQ_NODENAME: rabbit@eventbus
RABBITMQ_NODENAME: rabbit@eventbus
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: "-proto_dist inet_tcp"
RABBITMQ_DEFAULT_PERMISSIONS: "guest . \".*\" \".*\""

healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 10s
Expand All @@ -50,26 +49,17 @@ services:
volumes:
- rabbitmq-data:/var/lib/rabbitmq


postgres:
image: postgres:15-alpine
image: postgres:16-alpine
hostname: postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: username
POSTGRES_PASSWORD: password
POSTGRES_DB: eventstore
POSTGRES_HOST_AUTH_METHOD: scram-sha-256
POSTGRES_INITDB_ARGS: >-
--username=username
--pwfile=<(echo "password")
--auth-host=scram-sha-256
--auth-local=scram-sha-256
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U username -d eventstore"]
POSTGRES_PASSWORD: password
POSTGRES_DB: catalogdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U username -d catalogdb"]
interval: 5s
timeout: 5s
retries: 10
Expand All @@ -87,7 +77,10 @@ services:
condition: service_healthy

featurefusion-app:
image: featurefusion-app
build: .
ports:
- "5141:5004"
depends_on:
postgres:
condition: service_healthy
Expand All @@ -98,19 +91,13 @@ services:
memcached:
condition: service_healthy
environment:
- ASPNETCORE_ENVIRONMENT=Production
- MEMCACHED__SERVER=memcached:11211
command: >
sh -c "
while ! nc -z postgres 5432; do sleep 1; done &&
while ! nc -z redis 6379; do sleep 1; done &&
while ! nc -z eventbus 5672;do sleep 1; done &&
while ! nc -z memcached 11211; do sleep 1; done &&
echo 'All dependencies ready' &&
dotnet FeatureFusion.dll
"
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__catalogdb: Host=postgres;Port=5432;Username=username;Password=password;Database=catalogdb
ConnectionStrings__eventbus: amqp://guest:guest@eventbus:5672/
Redis__ConnectionString: redis:6379
Memcached__Servers__0__Address: memcached
Memcached__Servers__0__Port: "11211"

volumes:
redis_data:
postgres_data:
rabbitmq-data:
rabbitmq-data:
2 changes: 1 addition & 1 deletion docs/building-blocks/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Development only (`http://localhost:5141/mcp`):
| `products.list` | Scan + `ISender` (query) | products query |
| `lab.ping` | `[McpTool]` + `.WithMcp(app)` on `LabPing` | `GET /api/v1/lab-ping` |

Production (`docker-compose` sets `ASPNETCORE_ENVIRONMENT=Production`) does not register or map MCP.
Lab Compose sets `ASPNETCORE_ENVIRONMENT=Development` so MCP is registered (map at `/mcp`). A Production-environment host does not register or map MCP.

Workspace root for this Cursor window is `src/`. Put this in `src/.cursor/mcp.json` (gitignored; copy locally):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BuildingBlocks/Domain/BuildingBlocks.Domain.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
<ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
<PackageReference Include="Ulid" Version="1.3.4" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BuildingBlocks/Mcp/BuildingBlocks.Mcp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<ItemGroup>
<PackageReference Include="ModelContextProtocol" Version="2.2.0" />
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BuildingBlocks/Mediator/BuildingBlocks.Mediator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.22" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 0 additions & 2 deletions src/Lab/FeatureFusion.AppHost/InfrastructureExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,11 @@ public static InfrastructureResources AddInfrastructure(this IDistributedApplica
// pgAdmin is dashboard-only tooling; FeatureFusion WaitFor(catalogDb), not pgAdmin.
// Brief "Unhealthy" in the dashboard while the UI container boots is expected.
var postgres = builder.AddPostgres("postgres", userName: username, password: password)
.WithDataVolume("postgres_data")
.WithPgAdmin(container =>
{
container.WithEnvironment("PGADMIN_DEFAULT_EMAIL", "guest@admin.com");
container.WithEnvironment("PGADMIN_DEFAULT_PASSWORD", "guest");
})
.WithLifetime(ContainerLifetime.Persistent)
.WithEndpoint("tcp", endpoint =>
{
endpoint.Port = 5432;
Expand Down
Loading
Loading