diff --git a/deployments/local/docker-compose.yml b/deployments/local/docker-compose.yml
index 316eb663..5495097f 100644
--- a/deployments/local/docker-compose.yml
+++ b/deployments/local/docker-compose.yml
@@ -1012,6 +1012,64 @@ services:
- "traefik.http.routers.ads-serving-admin.entrypoints=web"
- "traefik.http.routers.ads-serving-admin.service=ads-serving-service"
+ # Ads Billing Service .NET - Billing, Invoicing & Payment Management
+ ads-billing-service-net:
+ build:
+ context: ../../services/ads-billing-service-net
+ dockerfile: Dockerfile
+ image: goodgo/ads-billing-service-net:latest
+ container_name: ads-billing-service-net-local
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_URLS=http://+:8080
+ # EN: Database - Neon PostgreSQL
+ # VI: Cơ sở dữ liệu - Neon PostgreSQL
+ - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=ads_billing_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require
+ # EN: IAM Service Communication
+ # VI: Giao tiếp IAM Service
+ - IamService__BaseUrl=http://iam-service-net:8080
+ - IamService__ServiceName=ads-billing-service
+ # EN: Wallet Service Communication
+ # VI: Giao tiếp Wallet Service
+ - WalletService__BaseUrl=http://wallet-service-net:8080
+ # EN: JWT Configuration
+ # VI: Cấu hình JWT
+ - Jwt__Authority=http://iam-service-net:8080
+ - Jwt__Audience=goodgo-api
+ - Jwt__RequireHttpsMetadata=false
+ ports:
+ - "5023:8080"
+ depends_on:
+ iam-service-net:
+ condition: service_healthy
+ wallet-service-net:
+ condition: service_healthy
+ traefik:
+ condition: service_started
+ networks:
+ - microservices-network
+ restart: unless-stopped
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+ labels:
+ - "traefik.enable=true"
+ # EN: Public API routes for billing, invoices, credit lines
+ # VI: Routes API công khai cho billing, hóa đơn, tín dụng
+ - "traefik.http.routers.ads-billing-service.rule=PathPrefix(`/api/v1/ads-billing/accounts`) || PathPrefix(`/api/v1/ads-billing/invoices`) || PathPrefix(`/api/v1/ads-billing/credit-lines`)"
+ - "traefik.http.routers.ads-billing-service.entrypoints=web"
+ - "traefik.http.services.ads-billing-service.loadbalancer.server.port=8080"
+ - "traefik.http.services.ads-billing-service.loadbalancer.healthcheck.path=/health/live"
+ - "traefik.http.services.ads-billing-service.loadbalancer.healthcheck.interval=10s"
+ # EN: Admin API routes for billing management
+ # VI: Routes API Admin để quản lý billing
+ - "traefik.http.routers.ads-billing-admin.rule=PathPrefix(`/api/v1/admin/ads-billing`)"
+ - "traefik.http.routers.ads-billing-admin.entrypoints=web"
+ - "traefik.http.routers.ads-billing-admin.service=ads-billing-service"
+
# Jaeger - Distributed Tracing
# jaeger:
# image: jaegertracing/all-in-one:1.47
diff --git a/services/ads-manager-service-net/src/AdsManagerService.API/Controllers/AdminCampaignsController.cs b/services/ads-manager-service-net/src/AdsManagerService.API/Controllers/AdminCampaignsController.cs
new file mode 100644
index 00000000..737c1818
--- /dev/null
+++ b/services/ads-manager-service-net/src/AdsManagerService.API/Controllers/AdminCampaignsController.cs
@@ -0,0 +1,79 @@
+using AdsManagerService.API.Application.Queries;
+using MediatR;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AdsManagerService.API.Controllers;
+
+///
+/// EN: Admin API Controller for campaign management and oversight.
+/// VI: API Controller Admin cho quản lý và giám sát chiến dịch.
+///
+[ApiController]
+[Route("api/v1/admin/ads-manager/campaigns")]
+[Produces("application/json")]
+public class AdminCampaignsController : ControllerBase
+{
+ private readonly IMediator _mediator;
+ private readonly ILogger _logger;
+
+ public AdminCampaignsController(IMediator mediator, ILogger logger)
+ {
+ _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ ///
+ /// EN: List all campaigns across all advertisers (Admin only).
+ /// VI: Liệt kê tất cả chiến dịch của tất cả advertisers (Admin only).
+ ///
+ [HttpGet]
+ [ProducesResponseType(typeof(ListCampaignsResult), StatusCodes.Status200OK)]
+ public async Task> ListAllCampaigns(
+ [FromQuery] string? status,
+ [FromQuery] int page = 1,
+ [FromQuery] int pageSize = 50)
+ {
+ var query = new ListCampaignsQuery
+ {
+ Status = status,
+ Page = page,
+ PageSize = pageSize
+ };
+
+ var result = await _mediator.Send(query);
+ return Ok(result);
+ }
+
+ ///
+ /// EN: Get campaign statistics.
+ /// VI: Lấy thống kê chiến dịch.
+ ///
+ [HttpGet("stats")]
+ [ProducesResponseType(typeof(CampaignStatsDto), StatusCodes.Status200OK)]
+ public async Task> GetCampaignStats()
+ {
+ var stats = await _mediator.Send(new GetCampaignStatsQuery());
+ return Ok(stats);
+ }
+}
+
+///
+/// EN: Campaign statistics DTO.
+/// VI: DTO thống kê chiến dịch.
+///
+public record CampaignStatsDto
+{
+ public int TotalCampaigns { get; init; }
+ public int ActiveCampaigns { get; init; }
+ public int PausedCampaigns { get; init; }
+ public int DraftCampaigns { get; init; }
+ public int CompletedCampaigns { get; init; }
+ public decimal TotalSpend { get; init; }
+ public decimal TotalBudget { get; init; }
+}
+
+///
+/// EN: Query to get campaign statistics.
+/// VI: Query lấy thống kê chiến dịch.
+///
+public record GetCampaignStatsQuery : IRequest;