# Ads Service

[![Go Version](https://img.shields.io/badge/Go-1.25.1-blue.svg)](https://golang.org/)
[![License](https://img.shields.io/badge/License-Internal-red.svg)](LICENSE)
[![Build Status](https://img.shields.io/badge/Build-Passing-green.svg)](https://bsm/full/module/base/ads)

一个高性能、可扩展的广告管理微服务，基于 gRPC 和 HTTP Gateway 架构，提供广告位管理、广告内容分发等核心功能。

## 🚀 特性

- **📢 广告管理**: 多类型广告内容管理（文本、图片、视频、音频、链接、附件）
- **📍 广告位管理**: 灵活的广告位配置和分类管理
- **⚡ 高性能**: Redis缓存 + 数据库优化，支持高并发访问
- **🔄 智能缓存**: 10分钟缓存策略，提升响应速度
- **🐳 容器化**: 完整的Docker支持
- **📊 监控**: 健康检查和APM集成
- **🔒 安全**: 完善的错误处理和输入验证
- **🌐 多协议**: 支持gRPC和HTTP Gateway双重访问方式

## 📋 目录

- [快速开始](#-快速开始)
- [项目结构](#-项目结构)
- [核心功能](#-核心功能)
- [API文档](#-api文档)
- [开发指南](#-开发指南)
- [部署说明](#-部署说明)
- [性能优化](#-性能优化)
- [故障排除](#-故障排除)

## 🚀 快速开始

### 环境要求

- **Go**: 1.25.1+
- **PostgreSQL**: 12+
- **Redis**: 6+
- **Docker**: 20.10+ (可选)
- **Protocol Buffers**: 3.15+ (开发需要)

### 快速安装

```bash
# 克隆项目
git clone bsm/full/module/base/ads.git
cd ads

# 安装依赖
go mod tidy

# 生成代码
make proto

# 构建应用
go build -o bin/ads cmd/main/main.go

# 运行服务
./bin/ads
```

### Docker 快速启动

```bash
# 构建镜像
docker build -t ads-service .

# 运行容器
docker run -d --name ads-service \
  -p 12216:12216 \
  -p 12102:12102 \
  -e SERVICE_ENV=development \
  ads-service
```

## 📁 项目结构

```
ads/
├── 📁 cmd/                     # 应用程序入口
│   ├── 📁 main/               # 主服务入口
│   └── 📁 cli/                # 命令行工具
├── 📁 internal/               # 内部包
│   ├── 📁 config/             # 配置管理
│   ├── 📁 impl/               # 实现层
│   ├── 📁 logic/              # 业务逻辑
│   │   └── 📁 fetch/          # 广告获取逻辑
│   ├── 📁 models/             # 数据模型
│   └── 📁 server/             # 服务器实现
├── 📁 pb/                     # Protocol Buffers 生成代码
├── 📁 proto/                  # Protocol Buffers 定义文件
├── 📁 swagger/                # API 文档
├── 📁 scripts/                # 脚本文件
├── 📁 etc/                    # 配置文件
├── 🐳 Dockerfile              # Docker 镜像构建
├── 🔧 Makefile               # 构建脚本
└── 📖 README.md              # 项目文档
```

## 🔧 核心功能

### 1. 广告获取服务 (Fetch Service)

#### 📍 按广告位获取广告 (ByPos)
```protobuf
rpc ByPos(ByPosRequest) returns (ByPosReply)
```
- **功能**: 根据广告位标识获取对应的广告内容
- **特性**: 
  - 支持多种广告类型（文本、图片、视频、音频、链接、附件）
  - Redis缓存加速，缓存时间10分钟
  - 只返回启用状态的广告
  - 完整的错误处理和日志记录
- **用途**: 前端页面广告展示、移动端广告投放

### 2. 广告类型支持

| 类型 | 值 | 描述 | 用途 |
|------|----|----|----|
| 文本 | 1 | 纯文本广告 | 文字推广、通知公告 |
| 图片 | 2 | 图片广告 | 横幅广告、图片推广 |
| 视频 | 3 | 视频广告 | 视频推广、宣传片 |
| 音频 | 4 | 音频广告 | 音频推广、语音广告 |
| 链接 | 5 | 链接广告 | 跳转链接、外部推广 |
| 附件 | 6 | 附件广告 | 文件下载、文档推广 |

## 📚 API文档

### gRPC 服务

| 服务 | 方法 | 描述 | 端口 |
|------|------|------|------|
| Fetch | ByPos | 按广告位获取广告 | 12216 |

### HTTP Gateway

| 端点 | 方法 | 描述 |
|------|------|------|
| `/ads.Fetch/ByPos` | POST | 按广告位获取广告 |

### Swagger 文档

- **本地**: http://localhost:12102/ads.swagger.json
- **在线**: 通过 HTTP Gateway 访问完整的 API 文档

### 请求示例

#### gRPC 请求
```protobuf
// 请求
{
  "key": "homepage_banner"
}

// 响应
{
  "data": [
    {
      "id": 1,
      "title": "首页横幅广告",
      "content": "欢迎使用我们的服务",
      "type": 2,
      "toUrl": "https://example.com",
      "created": "2024-01-01 12:00:00"
    }
  ]
}
```

#### HTTP 请求
```bash
curl -X POST http://localhost:12102/ads.Fetch/ByPos \
  -H "Content-Type: application/json" \
  -d '{"key": "homepage_banner"}'
```

## 🛠️ 开发指南

### 开发环境设置

```bash
# 安装开发工具
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest

# 启动开发模式
go run cmd/main/main.go
```

### 代码生成

```bash
# 生成 protobuf 代码
protoc --go_out=. --go-grpc_out=. proto/ads.proto

# 生成 Swagger 文档
protoc --grpc-gateway_out=. --openapiv2_out=swagger proto/ads.proto
```

### 测试

```bash
# 运行所有测试
go test ./...

# 测试覆盖率
go test -cover ./...

# 代码检查
go vet ./...
gofmt -s -w .
```

### 数据库管理

```bash
# 初始化数据库表
go run cmd/main/main.go --init-db

# 数据库迁移
gorm migrate
```

## 🚀 部署说明

### Docker 部署

```bash
# 构建镜像
docker build -t ads-service:latest .

# 启动服务栈
docker run -d --name ads-service \
  -p 12216:12216 \
  -p 12102:12102 \
  -e SERVICE_ENV=production \
  -e CONFIG_FILE=etc/ads_prod.yaml \
  ads-service:latest
```

### 生产环境部署

1. **环境准备**
   ```bash
   # 创建生产配置
   cp etc/ads_dev.yaml etc/ads_prod.yaml
   # 编辑生产配置...
   ```

2. **数据库初始化**
   ```bash
   # 创建数据库表
   psql -h your-db-host -U postgres -d ads_db -c "
   CREATE TABLE IF NOT EXISTS ads_pos (
     id SERIAL PRIMARY KEY,
     key VARCHAR(255) NOT NULL,
     name VARCHAR(255) NOT NULL,
     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
   );
   
   CREATE TABLE IF NOT EXISTS ads_item (
     id SERIAL PRIMARY KEY,
     title VARCHAR(255) NOT NULL,
     pos_key VARCHAR(255) NOT NULL,
     content VARCHAR(255) DEFAULT '',
     type INTEGER DEFAULT 0,
     to_url VARCHAR(255) DEFAULT '',
     status INTEGER DEFAULT 1,
     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
   );
   "
   ```

3. **服务启动**
   ```bash
   # 构建生产版本
   CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/ads-linux cmd/main/main.go
   
   # 启动服务
   ./bin/ads-linux
   ```

### Kubernetes 部署

```yaml
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ads-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ads-service
  template:
    metadata:
      labels:
        app: ads-service
    spec:
      containers:
      - name: ads-service
        image: ads-service:latest
        ports:
        - containerPort: 12216
        - containerPort: 12102
        env:
        - name: SERVICE_ENV
          value: "production"
        - name: CONFIG_FILE
          value: "etc/ads_prod.yaml"
```

## ⚡ 性能优化

### 缓存策略

| 数据类型 | 缓存时间 | 策略 | 说明 |
|----------|----------|------|------|
| 广告数据 | 10分钟 | 按广告位缓存 | 提升查询性能 |
| 广告位信息 | 30分钟 | 全量缓存 | 减少数据库查询 |

### 数据库优化

- **索引优化**: 在 `pos_key` 和 `status` 字段建立复合索引
- **查询优化**: 只查询启用状态的广告
- **连接池**: 配置合适的连接池大小
- **读写分离**: 支持主从数据库配置

### 监控指标

```bash
# 服务健康检查
curl http://localhost:12102/health

# 性能指标
curl http://localhost:12102/metrics
```

## 🔧 配置说明

### 环境配置文件

```yaml
# etc/ads_prod.yaml
Service: ads
Port: 12216

# 数据库配置
Databases:
  Driver: postgres
  Source:
    - host=db-host user=postgres password=*** dbname=ads_db port=5432 sslmode=require

# 缓存配置
Cache: redis://username:password@redis-host:6379/0

# 网关配置
Gateway:
  Enable: true
  Port: 12102

# 微服务配置
MicroService:
  Enable: true
  Registry: etcd://etcd-cluster:2379

# APM监控
APM:
  Platform: elasticAPM
  Endpoint: http://apm-server:8200
```

### 环境变量

| 变量名 | 描述 | 默认值 |
|--------|------|--------|
| `SERVICE_ENV` | 运行环境 | `development` |
| `CONFIG_FILE` | 配置文件路径 | `etc/ads_dev.yaml` |
| `LOG_LEVEL` | 日志级别 | `info` |
| `TZ` | 时区设置 | `Asia/Shanghai` |

## 🐛 故障排除

### 常见问题

1. **服务启动失败**
   ```bash
   # 检查端口占用
   netstat -tlnp | grep :12216
   
   # 检查配置文件
   go run cmd/main/main.go --check-config
   ```

2. **数据库连接失败**
   ```bash
   # 测试数据库连接
   psql -h your-db-host -U postgres -d ads_db -c "SELECT 1;"
   ```

3. **Redis连接失败**
   ```bash
   # 测试Redis连接
   redis-cli -h your-redis-host ping
   ```

### 日志分析

```bash
# 查看服务日志
tail -f logs/ads.log

# 查看错误日志
grep ERROR logs/ads.log

# 查看性能日志
grep "slow query" logs/ads.log
```

### 性能调优

1. **内存优化**
   ```bash
   # 监控内存使用
   go tool pprof http://localhost:6060/debug/pprof/heap
   ```

2. **CPU优化**
   ```bash
   # CPU性能分析
   go tool pprof http://localhost:6060/debug/pprof/profile
   ```

## 📊 数据模型

### 核心表结构

#### ads_pos - 广告位表
```sql
CREATE TABLE ads_pos (
    id SERIAL PRIMARY KEY,
    key VARCHAR(255) NOT NULL,        -- 广告位标识
    name VARCHAR(255) NOT NULL,       -- 广告位名称
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

#### ads_item - 广告内容表
```sql
CREATE TABLE ads_item (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,      -- 广告标题
    pos_key VARCHAR(255) NOT NULL,    -- 广告位标识
    content VARCHAR(255) DEFAULT '',  -- 广告内容
    type INTEGER DEFAULT 0,           -- 广告类型
    to_url VARCHAR(255) DEFAULT '',   -- 跳转链接
    status INTEGER DEFAULT 1,         -- 状态（1:启用 0:禁用）
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

## 🤝 贡献指南

### 开发流程

1. **Fork 项目**
2. **创建特性分支**: `git checkout -b feature/amazing-feature`
3. **提交更改**: `git commit -m 'Add amazing feature'`
4. **推送分支**: `git push origin feature/amazing-feature`
5. **创建 Pull Request**

### 代码规范

- 遵循 Go 官方代码规范
- 使用 `gofmt` 格式化代码
- 添加必要的注释和文档
- 编写单元测试

### 提交规范

```
type(scope): description

[optional body]

[optional footer]
```

类型:
- `feat`: 新功能
- `fix`: 修复bug
- `docs`: 文档更新
- `style`: 代码格式
- `refactor`: 重构
- `test`: 测试
- `chore`: 构建过程或辅助工具的变动

## 📄 许可证

本项目采用内部许可证，仅供 BSM 内部使用。

## 👥 团队

- **作者**: David Yan (david.yan@qq.com)
- **维护者**: BSM 开发团队
- **项目地址**: [bsm/full/module/base/ads](https://bsm/full/module/base/ads)

## 🔗 相关链接

- [BSM SDK](https://git.apinb.com/bsm-sdk)
- [API 文档](https://docs.apinb.com/ads)
- [问题反馈](https://bsm/full/module/base/ads/issues)

---

<div align="center">

**⭐ 如果这个项目对你有帮助，请给它一个星标！**

Made with ❤️ by BSM Team

</div>