# Mall — Administrator & Developer Guide

## 1. Architecture Overview

Mall is a multi-module Spring Boot 2.7.5 e-commerce backend platform structured as a monolithic application with clear module boundaries. It provides REST APIs for both back-office administration and customer-facing shopping operations, backed by MySQL, Redis, MongoDB, Elasticsearch, and RabbitMQ.

The system follows a layered architecture within each module: Controller → Service → DAO/Mapper, with a shared security module providing JWT-based authentication and dynamic URL-level authorization across all deployable modules.

```
┌─────────────────────────────────────────────────────────────────┐
│                        Client Applications                       │
│              (Admin SPA, Mobile App, Web Storefront)             │
└──────────┬──────────────────┬──────────────────┬────────────────┘
           │                  │                  │
     ┌─────▼─────┐    ┌──────▼──────┐    ┌─────▼─────┐
     │ mall-admin │    │ mall-portal │    │mall-search│
     │  :8080    │    │   :8085     │    │  :8081    │
     └─────┬─────┘    └──────┬──────┘    └─────┬─────┘
           │                  │                  │
     ┌─────▼──────────────────▼──────────────────▼─────┐
     │              mall-security (JWT + RBAC)          │
     └─────────────────────┬───────────────────────────┘
                           │
     ┌─────────────────────▼───────────────────────────┐
     │                   mall-mbg                       │
     │        (MyBatis Generated Mappers/Models)        │
     └─────────────────────┬───────────────────────────┘
                           │
     ┌─────────────────────▼───────────────────────────┐
     │                  mall-common                     │
     │    (Redis, Swagger, Pagination, Error Handling)  │
     └──┬──────────┬──────────┬──────────┬─────────────┘
        │          │          │          │
   ┌────▼───┐ ┌───▼───┐ ┌───▼────┐ ┌───▼─────┐
   │ MySQL  │ │ Redis │ │MongoDB │ │RabbitMQ │
   │  5.7   │ │   7   │ │   4    │ │  3.9    │
   └────────┘ └───────┘ └────────┘ └─────────┘
                                          │
                              ┌────────────▼────────────┐
                              │    Elasticsearch 7.17   │
                              └─────────────────────────┘
```

### Component Inventory

| Component | Module | Port | Role |
|-----------|--------|------|------|
| Admin API | `mall-admin` | 8080 | Back-office management (products, orders, promotions, users) |
| Portal API | `mall-portal` | 8085 | Customer-facing (cart, orders, member, payments) |
| Search API | `mall-search` | 8081 | Elasticsearch-backed product search |
| Security | `mall-security` | — | Shared JWT auth + dynamic authorization library |
| MBG | `mall-mbg` | — | MyBatis Generator output (mappers, models, examples) |
| Common | `mall-common` | — | Shared utilities (Redis, Swagger, pagination, exceptions) |
| Demo | `mall-demo` | 8082 | Learning/demo module (not production) |

### Technology Stack

| Layer | Technology | Version |
|-------|-----------|---------|
| Framework | Spring Boot | 2.7.5 |
| Security | Spring Security + JWT (jjwt) | 5.7.x / 0.9.1 |
| ORM | MyBatis + PageHelper | 3.5.10 / 5.3.2 |
| Database | MySQL | 5.7+ (via mysql-connector 8.0.29) |
| Connection Pool | Druid | 1.2.14 |
| Cache | Redis (Spring Data Redis) | 7 |
| Document Store | MongoDB (Spring Data MongoDB) | 4 |
| Search | Elasticsearch (Spring Data ES) | 7.17.x |
| Message Queue | RabbitMQ (Spring AMQP) | 3.9 |
| Object Storage | MinIO / Aliyun OSS | 8.4.5 / 2.5.0 |
| Payment | Alipay SDK | 4.38.61 |
| API Docs | Springfox (Swagger 2) | 3.0.0 |
| Utilities | Hutool | 5.8.9 |
| Code Gen | Lombok | Latest |
| Logging | Logstash Logback Encoder | 7.2 |
| Build | Maven + fabric8 Docker plugin | — / 0.40.2 |
| Java | JDK | 8 (source/target) |

> [!NOTE]
> The project targets Java 8 but includes `javax.xml.bind:jaxb-api:2.3.1` for JDK 11+ compatibility. The codebase uses Spring Security's pre-6.0 API style (imperative `HttpSecurity` chain, not the newer Lambda DSL).

### Data Flow: Order Placement

1. Customer calls `POST /order/generateOrder` with address, coupon, payment type
2. `OmsPortalOrderServiceImpl` validates cart, calculates promotions, deducts stock
3. Order record inserted into MySQL with status `0` (pending payment)
4. `CancelOrderSender` sends order ID to RabbitMQ TTL queue (`mall.order.cancel.ttl`)
5. If paid: `POST /order/paySuccess` updates status to `1`
6. If TTL expires: message routed to dead-letter queue → `CancelOrderReceiver` cancels order, restores stock

---

## 2. System Requirements

### Hardware (Minimum for Development)

| Resource | Minimum | Recommended |
|----------|---------|-------------|
| RAM | 8 GB | 16 GB |
| CPU | 4 cores | 8 cores |
| Disk | 20 GB | 50 GB (Elasticsearch data) |

### Software Dependencies

| Software | Required Version | Notes |
|----------|-----------------|-------|
| JDK | 8+ (8 preferred) | Source level 1.8 |
| Maven | 3.6+ | For building |
| Docker + Compose | Latest | For infrastructure |
| MySQL | 5.7+ | `utf8mb4` charset |
| Redis | 7+ | AOF persistence recommended |
| MongoDB | 4+ | For member data (collections, history) |
| RabbitMQ | 3.9+ | Management plugin required |
| Elasticsearch | 7.17.x | Single-node mode for dev |
| Kibana | 7.17.x | Optional log visualization |
| Logstash | 7.17.x | Optional log aggregation |
| MinIO | Latest | Object storage |
| Nginx | 1.22+ | Frontend proxy |

---

## 3. Configuration Reference

### Configuration Files

| File | Module | Format | Purpose |
|------|--------|--------|---------|
| `application.yml` | Each module | YAML | Shared Spring config |
| `application-dev.yml` | Each module | YAML | Development overrides |
| `application-prod.yml` | Each module | YAML | Production overrides |
| `generatorConfig.xml` | mall-mbg | XML | MyBatis Generator config |
| `generator.properties` | mall-mbg | Properties | DB connection for codegen |
| `logback-spring.xml` | mall-common | XML | Logging configuration |

### Spring Configuration Keys

#### Database (all modules)

| Key | Type | Example | Description |
|-----|------|---------|-------------|
| `spring.datasource.url` | String | `jdbc:mysql://localhost:3306/mall?...` | JDBC connection URL |
| `spring.datasource.username` | String | `root` | DB username |
| `spring.datasource.password` | String | `root` | DB password |
| `spring.datasource.druid.*` | — | — | Druid pool settings (initial/min/max size, etc.) |

#### Redis

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `spring.redis.host` | String | `localhost` | Redis host |
| `spring.redis.port` | Integer | `6379` | Redis port |
| `spring.redis.database` | Integer | `0` | Redis DB index |
| `spring.redis.password` | String | — | Redis password (if set) |
| `spring.redis.timeout` | Duration | `3000ms` | Connection timeout |

#### MongoDB (mall-portal)

| Key | Type | Example | Description |
|-----|------|---------|-------------|
| `spring.data.mongodb.host` | String | `localhost` | MongoDB host |
| `spring.data.mongodb.port` | Integer | `27017` | MongoDB port |
| `spring.data.mongodb.database` | String | `mall-port` | Database name |

#### RabbitMQ (mall-portal)

| Key | Type | Example | Description |
|-----|------|---------|-------------|
| `spring.rabbitmq.host` | String | `localhost` | Broker host |
| `spring.rabbitmq.port` | Integer | `5672` | AMQP port |
| `spring.rabbitmq.virtual-host` | String | `/` | Virtual host |
| `spring.rabbitmq.username` | String | `guest` | Username |
| `spring.rabbitmq.password` | String | `guest` | Password |

#### Elasticsearch (mall-search)

| Key | Type | Example | Description |
|-----|------|---------|-------------|
| `spring.elasticsearch.uris` | String | `http://localhost:9200` | ES cluster URL |

#### JWT Security

| Key | Type | Example | Description |
|-----|------|---------|-------------|
| `jwt.tokenHeader` | String | `Authorization` | Header name |
| `jwt.secret` | String | — | HMAC signing key (HS512) |
| `jwt.expiration` | Integer | `604800` | Token TTL in seconds |
| `jwt.tokenHead` | String | `Bearer ` | Token prefix |

> [!IMPORTANT]
> The `jwt.secret` value MUST be changed from any default in production. Issue #948 demonstrates that a weak default enables authentication bypass. Use a cryptographically random string of at least 64 characters.

#### Security Whitelist

| Key | Type | Description |
|-----|------|-------------|
| `secure.ignored.urls` | List | URL patterns that bypass JWT auth |

Typical whitelist entries:
```yaml
secure:
  ignored:
    urls:
      - /swagger-ui/**
      - /swagger-resources/**
      - /v2/api-docs
      - /**/admin/login
      - /**/sso/login
      - /**/sso/register
      - /actuator/**
```

#### Aliyun OSS (mall-admin)

| Key | Type | Description |
|-----|------|-------------|
| `aliyun.oss.endpoint` | String | OSS endpoint URL |
| `aliyun.oss.accessKeyId` | String | Access key |
| `aliyun.oss.accessKeySecret` | String | Secret key |
| `aliyun.oss.bucketName` | String | Bucket name |
| `aliyun.oss.policy.expire` | Integer | Policy expiration (seconds) |
| `aliyun.oss.maxSize` | Integer | Max upload size (MB) |
| `aliyun.oss.callback` | String | Callback URL |
| `aliyun.oss.dir.prefix` | String | Upload path prefix |

#### MinIO (mall-admin)

| Key | Type | Description |
|-----|------|-------------|
| `minio.endpoint` | String | MinIO API endpoint |
| `minio.bucketName` | String | Bucket name |
| `minio.accessKey` | String | Access key |
| `minio.secretKey` | String | Secret key |

#### Alipay (mall-portal)

| Key | Type | Description |
|-----|------|-------------|
| `alipay.gatewayUrl` | String | Alipay gateway URL |
| `alipay.appId` | String | Application ID |
| `alipay.appPrivateKey` | String | App RSA private key |
| `alipay.alipayPublicKey` | String | Alipay RSA public key |
| `alipay.returnUrl` | String | Sync return URL |
| `alipay.notifyUrl` | String | Async notification URL |

> [!CAUTION]
> Never commit Alipay private keys or OSS secrets to source control. Use environment variables or external secret management in production.

#### Spring MVC / Swagger Compatibility

| Key | Value | Required By |
|-----|-------|-------------|
| `spring.mvc.pathmatch.matching-strategy` | `ant_path_matcher` | Springfox 3.0 |

---

## 4. Deployment & Scaling

### Docker Image Build

The project uses the fabric8 Docker Maven plugin configured in the parent POM:

```bash
# Build all modules + Docker images
mvn clean package -DskipTests
```

Image naming convention: `mall/{module-name}:1.0-SNAPSHOT`

The Docker build base image is `openjdk:8` with entrypoint:
```
java -jar -Dspring.profiles.active=prod /${module}.jar
```

Remote Docker host is configured at `${docker.host}` (default: `http://192.168.3.101:2375`).

### Infrastructure Deployment

**Environment services** (`document/docker/docker-compose-env.yml`):

```bash
docker compose -f document/docker/docker-compose-env.yml up -d
```

This deploys: MySQL, Redis, Nginx, RabbitMQ, Elasticsearch, Logstash, Kibana, MongoDB, MinIO.

**Application services** (`document/docker/docker-compose-app.yml`):

```bash
docker compose -f document/docker/docker-compose-app.yml up -d
```

This deploys: mall-admin (:8080), mall-search (:8081), mall-portal (:8085).

### Port Mapping

| Service | Host Port | Container Port |
|---------|-----------|----------------|
| mall-admin | 8080 | 8080 |
| mall-search | 8081 | 8081 |
| mall-portal | 8085 | 8085 |
| MySQL | 3306 | 3306 |
| Redis | 6379 | 6379 |
| Nginx | 80 | 80 |
| RabbitMQ AMQP | 5672 | 5672 |
| RabbitMQ Management | 15672 | 15672 |
| Elasticsearch HTTP | 9200 | 9200 |
| Elasticsearch Transport | 9300 | 9300 |
| Logstash | 4560-4563 | 4560-4563 |
| Kibana | 5601 | 5601 |
| MongoDB | 27017 | 27017 |
| MinIO API | 9090 | 9000 |
| MinIO Console | 9001 | 9001 |

### Volume Mounts

| Service | Host Path | Container Path | Purpose |
|---------|-----------|----------------|---------|
| MySQL | `/mydata/mysql/data` | `/var/lib/mysql` | Data persistence |
| MySQL | `/mydata/mysql/conf` | `/etc/mysql` | Custom config |
| MySQL | `/mydata/mysql/log` | `/var/log/mysql` | Logs |
| Redis | `/mydata/redis/data` | `/data` | AOF persistence |
| Elasticsearch | `/mydata/elasticsearch/plugins` | `.../plugins` | Plugins (e.g., IK analyzer) |
| Elasticsearch | `/mydata/elasticsearch/data` | `.../data` | Index data |
| MongoDB | `/mydata/mongo/db` | `/data/db` | Data persistence |
| MinIO | `/mydata/minio/data` | `/data` | Object storage |
| Nginx | `/mydata/nginx/conf` | `/etc/nginx` | Nginx config |
| Nginx | `/mydata/nginx/html` | `.../html` | Static files |
| Apps | `/mydata/app/{name}/logs` | `/var/logs` | Application logs |

> [!TIP]
> All persistent data resides under `/mydata/`. Back up this directory for full system recovery.

### Scaling Considerations

- **mall-admin**: Stateless — scale horizontally behind a load balancer. Redis handles session/cache.
- **mall-portal**: Stateless — scale horizontally. Ensure shared Redis for member caching.
- **mall-search**: Stateless — scale horizontally. All state lives in Elasticsearch.
- **MySQL**: Vertical scaling or read replicas. The application uses a single datasource.
- **Elasticsearch**: Add nodes to the cluster and change `discovery.type` from `single-node`.

> [!NOTE]
> The Docker Compose files use `external_links` for inter-container communication (a deprecated feature). For production, use Docker networks or Kubernetes service discovery.

---

## 5. Operations

### Health Checks

Each module exposes Spring Boot Actuator at `/actuator/health`:

```bash
curl http://localhost:8080/actuator/health
curl http://localhost:8085/actuator/health
curl http://localhost:8081/actuator/health
```

### Log Management

Logging is configured via `mall-common/src/main/resources/logback-spring.xml` with Logstash integration:

- Application logs write to `/var/logs/` (mapped to `/mydata/app/{module}/logs/` on host)
- Logstash collects from ports 4560-4563 (one per module)
- Kibana provides visualization at port 5601

### Database Initialization

```bash
mysql -u root -proot < document/sql/mall.sql
```

The SQL file creates:
- Database `mall`
- All ~70 tables with schema (prefixed: `cms_*`, `oms_*`, `pms_*`, `sms_*`, `ums_*`)
- Seed data (admin user, default categories, demo products)

### MyBatis Generator (Code Regeneration)

To regenerate mapper/model classes after schema changes:

1. Update `mall-mbg/src/main/resources/generator.properties` with DB connection
2. Update `mall-mbg/src/main/resources/generatorConfig.xml` with target tables
3. Run `Generator.java` main class in `mall-mbg`

> [!WARNING]
> Regeneration overwrites all files in `mall-mbg/src/main/java/com/macro/mall/mapper/` and `mall-mbg/src/main/java/com/macro/mall/model/`. Custom DAO classes in `mall-admin` or `mall-portal` `dao/` packages are safe — they're in separate packages.

### Elasticsearch Index Management

Import all products:
```bash
curl -X POST http://localhost:8081/esProduct/importAll
```

The `EsProduct` document maps product data with nested `EsProductAttributeValue` objects. The search service supports keyword matching, brand/category filtering, and attribute aggregation.

### RabbitMQ Queue Setup

Queues are declared automatically by `mall-portal` on startup via `RabbitMqConfig`:

| Queue | Exchange | Routing Key | Purpose |
|-------|----------|-------------|---------|
| `mall.order.cancel` | `mall.order.direct` | `mall.order.cancel` | Actual cancellation processing |
| `mall.order.cancel.ttl` | `mall.order.direct.ttl` | `mall.order.cancel.ttl` | Delay queue (dead-letter) |

The TTL queue forwards expired messages to the cancel queue using dead-letter exchange configuration.

> [!TIP]
> Monitor queue depth via RabbitMQ Management UI (`http://localhost:15672`). A growing `mall.order.cancel.ttl` queue during peak hours is normal; a growing `mall.order.cancel` queue indicates the consumer is falling behind.

### Scheduled Tasks

`mall-portal` enables Spring's `@EnableScheduling`. The `OrderTimeOutCancelTask` runs on a cron schedule to catch any orders that weren't cancelled via the RabbitMQ mechanism (belt-and-suspenders approach).

---

## 6. Performance

### Redis Caching Strategy

- **Cache TTL**: 1 day (configured in `BaseRedisConfig`)
- **Serialization**: Jackson2 with type information (enables proper deserialization)
- **Cache service**: `RedisServiceImpl` provides get/set/delete/expire operations used by `UmsAdminCacheService` and `UmsMemberCacheService`
- **Cache failure resilience**: `RedisCacheAspect` wraps all `*CacheService` methods — if Redis is down, cache operations silently fail unless annotated with `@CacheException`

> [!NOTE]
> The `@CacheException` annotation marks cache methods that MUST throw on failure (e.g., login verification code validation). All other cache methods degrade gracefully when Redis is unavailable.

### Connection Pooling

Druid connection pool is configured per module in `application.yml`. Key tuning parameters:
- `initialSize` — initial connections on startup
- `minIdle` — minimum idle connections
- `maxActive` — maximum concurrent connections
- `maxWait` — max wait time for a connection from pool

### Pagination

All list operations use PageHelper (MyBatis plugin) or Spring Data pagination:
- `CommonPage.restPage(List)` — wraps MyBatis PageHelper results
- `CommonPage.restPage(Page)` — wraps Spring Data Page results (MongoDB, ES)

---

## 7. Security

### Authentication Architecture

```
Request → JwtAuthenticationTokenFilter → SecurityFilterChain
  ├── Token present & valid → SecurityContext populated → proceed
  ├── Token missing/invalid → RestAuthenticationEntryPoint (401)
  └── Token valid but insufficient permissions → RestfulAccessDeniedHandler (403)
```

**JWT Implementation (`JwtTokenUtil`):**
- Algorithm: HS512
- Claims: `sub` (username), `created` (issue timestamp as millis)
- Expiration: configurable via `jwt.expiration` (seconds)
- Token refresh: only re-issues if current token is >30 min old (`tokenRefreshJustBefore`)

### Dynamic URL-Based Authorization

When `DynamicSecurityService` bean is present (e.g., in `mall-admin`), the system enforces URL-level authorization:

1. `DynamicSecurityMetadataSource` loads all `ums_resource` entries on startup
2. For each request, it matches the URL against resource patterns
3. `DynamicAccessDecisionManager` checks if the user's roles include the required resource
4. This filter runs AFTER `JwtAuthenticationTokenFilter` and BEFORE `FilterSecurityInterceptor`

> [!WARNING]
> The `mall-portal` module does NOT enable dynamic resource authorization (no `DynamicSecurityService` bean). It relies solely on JWT authentication — any authenticated member can access all portal endpoints. If you need endpoint-level restrictions for members, you must implement it.

### Password Security

- Algorithm: BCrypt (`BCryptPasswordEncoder`)
- Storage: `ums_admin.password` column stores BCrypt hash
- No password complexity enforcement in code (business logic only)

### Security Whitelist

URLs in `secure.ignored.urls` completely bypass the security filter chain. Default whitelist includes:
- Swagger endpoints
- Login/register endpoints
- Actuator health check
- Static resources

### Known Security Issues

| Issue | Severity | Status | Detail |
|-------|----------|--------|--------|
| #948 | High | Closed (documented) | Default `jwt.secret` is weak — enables token forgery if not changed |
| CORS | Medium | By design | `GlobalCorsConfig` allows all origins (`*`) — restrict in production |
| CSRF | Low | Disabled | CSRF disabled (stateless JWT — expected for API-only services) |

> [!CAUTION]
> The CORS configuration (`addAllowedOriginPattern("*")`) is suitable for development only. In production, restrict to your actual frontend domain(s).

### Session Management

Sessions are disabled (`SessionCreationPolicy.STATELESS`). All state is carried in the JWT token. Redis is used for:
- Admin/member data caching (not session storage)
- Temporary verification codes (if implemented)

---

## 8. Developer Internals

### Repository Structure

```
mall/
├── pom.xml                          # Parent POM (dependency management)
├── mall-common/                     # Shared library
│   └── src/main/java/.../common/
│       ├── api/                     # CommonResult, CommonPage, ResultCode
│       ├── config/                  # BaseRedisConfig, BaseSwaggerConfig
│       ├── domain/                  # SwaggerProperties, WebLog
│       ├── exception/               # ApiException, GlobalExceptionHandler
│       ├── log/                     # WebLogAspect (request logging)
│       ├── service/                 # RedisService interface + impl
│       └── util/                    # RequestUtil
├── mall-mbg/                        # MyBatis Generator
│   └── src/main/java/.../
│       ├── mapper/                  # 76 mapper interfaces
│       ├── model/                   # 76 model + 76 example classes
│       ├── Generator.java           # Code generation entry
│       └── CommentGenerator.java    # Custom comment generator
├── mall-security/                   # Security library
│   └── src/main/java/.../security/
│       ├── annotation/              # @CacheException
│       ├── aspect/                  # RedisCacheAspect
│       ├── component/               # Filters, handlers, dynamic auth
│       ├── config/                  # SecurityConfig, IgnoreUrlsConfig
│       └── util/                    # JwtTokenUtil, SpringUtil
├── mall-admin/                      # Admin API (deployable)
│   └── src/main/java/.../
│       ├── config/                  # CORS, Security, MyBatis, OSS, Swagger
│       ├── controller/              # 30+ REST controllers
│       ├── dao/                     # Custom DAO interfaces
│       ├── dto/                     # Request/response DTOs
│       ├── bo/                      # Business objects
│       ├── service/                 # Service interfaces
│       ├── service/impl/            # Service implementations
│       └── validator/               # Custom validation (@FlagValidator)
├── mall-portal/                     # Portal API (deployable)
│   └── src/main/java/.../portal/
│       ├── config/                  # Alipay, RabbitMQ, Jackson, CORS, etc.
│       ├── controller/              # 14 REST controllers
│       ├── component/               # CancelOrderSender/Receiver, scheduled task
│       ├── dao/                     # Custom DAO interfaces
│       ├── domain/                  # Domain models (Mongo docs, DTOs)
│       ├── repository/              # MongoDB repositories
│       ├── service/                 # Service interfaces
│       ├── service/impl/            # Service implementations
│       └── util/                    # DateUtil
├── mall-search/                     # Search API (deployable)
│   └── src/main/java/.../search/
│       ├── config/                  # MyBatis, Swagger
│       ├── controller/              # EsProductController
│       ├── dao/                     # EsProductDao (MyBatis)
│       ├── domain/                  # EsProduct, EsProductAttributeValue
│       ├── repository/              # EsProductRepository (Spring Data ES)
│       ├── service/                 # EsProductService
│       └── service/impl/            # EsProductServiceImpl
├── mall-demo/                       # Demo module (not production)
└── document/                        # Deployment & reference docs
    ├── docker/                      # Docker Compose files, nginx.conf
    ├── sh/                          # Deployment shell scripts
    ├── sql/                         # Database schema (mall.sql)
    ├── postman/                     # API collections
    ├── elk/                         # Logstash config
    ├── reference/                   # Developer reference docs
    └── resource/                    # Architecture diagrams, screenshots
```

### Module Dependency Graph

```
mall-common ← mall-mbg ← mall-security ← mall-admin
                     ↑                  ← mall-portal
                     ↑                  ← mall-search
                     └── mall-demo
```

- `mall-common`: no internal dependencies (only Spring starters)
- `mall-mbg`: depends on `mall-common` (uses Redis, Swagger base, pagination)
- `mall-security`: depends on `mall-common` (uses Redis for caching)
- `mall-admin`: depends on `mall-mbg` + `mall-security` + Aliyun OSS + MinIO
- `mall-portal`: depends on `mall-mbg` + `mall-security` + MongoDB + RabbitMQ + Alipay
- `mall-search`: depends on `mall-mbg` + Elasticsearch (excludes Redis from mall-mbg transitively)

### Database Schema Overview

The schema uses prefixed table naming to organize by domain:

| Prefix | Domain | Key Tables |
|--------|--------|------------|
| `cms_` | Content Management | `cms_subject`, `cms_prefrence_area`, `cms_help` |
| `oms_` | Order Management | `oms_order`, `oms_order_item`, `oms_cart_item`, `oms_order_return_apply` |
| `pms_` | Product Management | `pms_product`, `pms_brand`, `pms_product_category`, `pms_sku_stock`, `pms_product_attribute` |
| `sms_` | Sales/Marketing | `sms_coupon`, `sms_flash_promotion`, `sms_home_advertise`, `sms_home_brand` |
| `ums_` | User Management | `ums_admin`, `ums_role`, `ums_resource`, `ums_member`, `ums_menu` |

Total: ~70 tables with full referential integrity.

### API Response Patterns

**Standard success response:**
```json
{"code": 200, "message": "操作成功", "data": {...}}
```

**Standard error responses:**
```json
{"code": 401, "message": "暂未登录或token已经过期", "data": null}
{"code": 403, "message": "没有相关权限", "data": null}
{"code": 404, "message": "参数检验失败", "data": null}
{"code": 500, "message": "操作失败", "data": null}
```

**Paginated response:**
```json
{
  "code": 200,
  "data": {
    "pageNum": 1,
    "pageSize": 5,
    "totalPage": 10,
    "total": 48,
    "list": [...]
  }
}
```

### Code Patterns and Conventions

**Controller pattern:**
- Annotated with `@Controller` (not `@RestController`) + `@ResponseBody` per method
- `@Api` and `@Tag` for Swagger documentation
- `@RequestMapping` on class for base path
- Return `CommonResult<T>` or `CommonResult<CommonPage<T>>`

**Service pattern:**
- Interface in `service/` package
- Implementation in `service/impl/` with `@Service`
- Business logic lives here; controllers are thin dispatchers

**DAO pattern (custom queries):**
- Interface in `dao/` package (annotated with MyBatis `@Mapper` via `@MapperScan`)
- XML mapping in `resources/dao/` directory
- Used for complex queries beyond single-table CRUD (which uses MBG mappers)

**Validation:**
- Custom `@FlagValidator` annotation validates integer fields against allowed values
- Standard JSR-303 validation via Spring Boot Validation starter

**Exception handling:**
- `GlobalExceptionHandler` catches `ApiException` and validation errors
- `Asserts.fail(message)` throws `ApiException` with custom message
- Framework-level: `RestAuthenticationEntryPoint` (401), `RestfulAccessDeniedHandler` (403)

### Testing

The project has minimal test coverage:
- `mall-admin`: `PmsDaoTests` (product DAO integration test)
- `mall-portal`: `PortalProductDaoTests` (product DAO test)
- `mall-search`: `MallSearchApplicationTests` (context load test)
- `mall-demo`: `MallDemoApplicationTests` (context load test)

Tests are skipped by default (`<skipTests>true</skipTests>` in parent POM).

---

## 9. Integration Points

### Swagger UI (API Documentation)

Each deployable module auto-generates Swagger documentation:

| Module | Swagger UI | API Docs JSON |
|--------|-----------|---------------|
| mall-admin | `http://localhost:8080/swagger-ui/` | `/v2/api-docs` |
| mall-portal | `http://localhost:8085/swagger-ui/` | `/v2/api-docs` |
| mall-search | `http://localhost:8081/swagger-ui/` | `/v2/api-docs` |

Security-enabled Swagger configs (admin, portal) include the `Authorization` header parameter for testing protected endpoints.

### Alipay Payment Integration

`mall-portal` integrates Alipay via the official Java SDK:

| Endpoint | Flow |
|----------|------|
| `/alipay/pay` | Generates desktop payment page (redirect) |
| `/alipay/webPay` | Generates mobile payment page (redirect) |
| `/alipay/notify` | Receives async payment confirmation from Alipay |
| `/alipay/query` | Queries transaction status by trade number |

Configuration binds to prefix `alipay.*` via `AlipayConfig` (`@ConfigurationProperties`).

### External Storage

**MinIO** (preferred for self-hosted):
- `MinioController` handles file upload/delete
- Bucket policy set to allow public read of uploaded files
- Configured via `minio.*` properties

**Aliyun OSS** (cloud option):
- `OssController` generates pre-signed upload policies
- Supports browser-direct upload with server callback
- Configured via `aliyun.oss.*` properties

### Logstash Integration

`logback-spring.xml` in `mall-common` configures appenders that send structured JSON logs to Logstash:
- Port 4560: Default application logs
- Ports 4561-4563: Available for per-module separation

The `WebLogAspect` AOP aspect logs all controller method invocations with request/response details into structured `WebLog` objects.

### MongoDB Collections

`mall-portal` uses MongoDB for:
- `MemberReadHistory` — product browsing history
- `MemberProductCollection` — product collections/favorites
- `MemberBrandAttention` — brand follows

These use Spring Data MongoDB repositories with automatic pagination support.

---

## 10. Troubleshooting

### Startup Failures

#### Error: `Failed to configure a DataSource`

**Cause:** MySQL not reachable or credentials incorrect.

**Solution:**
1. Verify MySQL is running: `docker ps | grep mysql`
2. Test connection: `mysql -h localhost -u root -proot`
3. Verify `application-dev.yml` datasource configuration

#### Error: `Connection refused` to Redis/MongoDB/RabbitMQ

**Cause:** Infrastructure service not started.

**Solution:**
```bash
docker compose -f document/docker/docker-compose-env.yml up -d
docker ps  # verify all containers are running
```

#### Error: `BeanCreationException` related to Elasticsearch

**Cause:** Elasticsearch version mismatch or not running.

**Solution:** Ensure ES 7.17.x is running. Spring Data ES in Boot 2.7.5 targets ES 7.17. Using ES 8.x will fail.

### Runtime Issues

#### Dynamic security metadata not loading

**Cause:** `ums_resource` table empty or `DynamicSecurityService` bean not registered.

**Solution:**
1. Check `SELECT * FROM ums_resource` — should have entries
2. Verify `MallSecurityConfig` in `mall-admin` declares `dynamicSecurityService()` bean

> [!NOTE]
> Community issue #884 reports path matching optimization needed for the dynamic security filter — URL patterns with path variables may not match correctly in all edge cases.

#### Single-product order generation fails

**Cause:** Known issue with generating orders for individual products (vs. cart-based). (Community issue #469)

**Solution:** Use the cart-based flow: add product to cart, then generate order from cart contents.

#### Promotion calculation errors with full-reduction

**Cause:** Edge case in coupon amount distribution algorithm. (Community issue #492)

**Solution:** Verify promotion rules don't create conflicting overlapping conditions.

> [!WARNING]
> The coupon apportionment algorithm distributes discount amounts proportionally across order items. Rounding errors of ±1 cent can occur with certain item price/quantity combinations. (Issue #356)

---

## 11. Quick Reference

### API Endpoint Summary

#### mall-admin (port 8080)

| Controller | Base Path | Operations |
|-----------|-----------|------------|
| `UmsAdminController` | `/admin` | Login, register, list, update, delete, role assignment |
| `UmsRoleController` | `/role` | CRUD roles, allocate resources/menus |
| `UmsResourceController` | `/resource` | CRUD API resources |
| `UmsMenuController` | `/menu` | CRUD navigation menus |
| `PmsProductController` | `/product` | CRUD products, batch operations |
| `PmsBrandController` | `/brand` | CRUD brands |
| `PmsProductCategoryController` | `/productCategory` | CRUD categories |
| `PmsProductAttributeController` | `/productAttribute` | CRUD attributes |
| `PmsProductAttributeCategoryController` | `/productAttribute/category` | Attribute categories |
| `PmsSkuStockController` | `/sku` | SKU stock management |
| `OmsOrderController` | `/order` | Order list, detail, delivery, close |
| `OmsOrderReturnApplyController` | `/returnApply` | Return processing |
| `OmsOrderReturnReasonController` | `/returnReason` | Return reason management |
| `OmsOrderSettingController` | `/orderSetting` | Order timeout settings |
| `SmsCouponController` | `/coupon` | Coupon CRUD |
| `SmsFlashPromotionController` | `/flash` | Flash sale events |
| `SmsFlashPromotionSessionController` | `/flashSession` | Flash sale time slots |
| `SmsFlashPromotionProductRelationController` | `/flashProductRelation` | Flash sale products |
| `SmsHomeAdvertiseController` | `/home/advertise` | Homepage ads |
| `SmsHomeBrandController` | `/home/brand` | Homepage brands |
| `SmsHomeNewProductController` | `/home/newProduct` | Homepage new arrivals |
| `SmsHomeRecommendProductController` | `/home/recommendProduct` | Homepage recommendations |
| `SmsHomeRecommendSubjectController` | `/home/recommendSubject` | Homepage subjects |
| `CmsPrefrenceAreaController` | `/prefrenceArea` | Preference areas |
| `CmsSubjectController` | `/subject` | Content subjects |
| `OmsCompanyAddressController` | `/companyAddress` | Company addresses |
| `UmsMemberLevelController` | `/memberLevel` | Member levels |
| `OssController` | `/aliyun/oss` | Aliyun OSS upload |
| `MinioController` | `/minio` | MinIO upload |

#### mall-portal (port 8085)

| Controller | Base Path | Operations |
|-----------|-----------|------------|
| `UmsMemberController` | `/sso` | Login, register, info |
| `OmsCartItemController` | `/cart` | Cart CRUD |
| `OmsPortalOrderController` | `/order` | Place, cancel, list, pay |
| `OmsPortalOrderReturnApplyController` | `/returnApply` | Submit return |
| `UmsMemberReceiveAddressController` | `/member/address` | Address CRUD |
| `UmsMemberCouponController` | `/member/coupon` | Coupon claim/list |
| `MemberAttentionController` | `/member/attention` | Brand follow |
| `MemberProductCollectionController` | `/member/productCollection` | Product collect |
| `MemberReadHistoryController` | `/member/readHistory` | Browse history |
| `HomeController` | `/home` | Homepage content |
| `PmsPortalBrandController` | `/brand` | Brand browsing |
| `PmsPortalProductController` | `/product` | Product detail/search |
| `AlipayController` | `/alipay` | Payment integration |

#### mall-search (port 8081)

| Controller | Base Path | Operations |
|-----------|-----------|------------|
| `EsProductController` | `/esProduct` | Import, search, CRUD index |

### Docker Commands Quick Reference

```bash
# Start all infrastructure
docker compose -f document/docker/docker-compose-env.yml up -d

# Start all application services
docker compose -f document/docker/docker-compose-app.yml up -d

# View logs for a specific container
docker logs -f mall-admin

# Restart a single service
docker restart mall-portal

# Check all container status
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
```

### Build Commands

```bash
# Full build (skip tests)
mvn clean package -DskipTests

# Build single module
mvn clean package -DskipTests -pl mall-admin -am

# Run locally (dev profile)
java -jar mall-admin/target/mall-admin-1.0-SNAPSHOT.jar --spring.profiles.active=dev
```

---

_Generated May 2026 from macrozheng/mall at d9501e9. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
