# Ability Center Naming Design

> Status: Draft approved in conversation, pending user review of written spec

## Goal

Define a long-term naming system for this repository so it can evolve from a single `OutlookReport` implementation into an `ability-center` that hosts multiple business capabilities. The first capability domain is `exam-sprint`, and within that domain the system will support multiple report types, starting with `outlook` and later `achievement`.

## Core Decisions

### Repository identity

- Rename repository identity from `ability-service` to `ability-center`.
- The repository should represent a multi-capability center, not a single service or a single report flow.

### Domain identity

- The first business capability domain is `exam-sprint`.
- `exam-sprint` is the bounded context.
- The stable business resource inside that context is `report`.
- `outlook` and `achievement` are report types, not top-level domain names.

### Resource model

- External API centers on `exam-sprint reports`.
- Internal domain centers on `ExamSprintReport`.
- Report generation, storage, PDF rendering, and download delivery are implementation concerns around the report resource.

### Type model

- `OUTLOOK` represents the 临考突击展望报告.
- `ACHIEVEMENT` represents the 临考突击成果报告.
- New report types should be added by extending `ExamSprintReportType`, not by inventing a new top-level domain.

## Architecture Naming Model

### Top-level structure

```text
ability-center
├── ability-center-runtime
├── ability-center-kernel
└── abilities
    └── exam-sprint
        ├── contracts
        ├── application
        ├── domain
        └── infrastructure
```

### Module responsibilities

#### `ability-center-runtime`

Purpose:

- Spring Boot startup
- HTTP wiring
- runtime configuration
- module assembly
- adapter entrypoints

This module should not become a place for business rules.

#### `ability-center-kernel`

Purpose:

- cross-capability foundational abstractions
- shared exception base classes
- response envelope primitives
- stable, domain-agnostic conventions

This module must not contain `exam-sprint` specific request, response, state, or rendering concepts.

#### `abilities/exam-sprint/contracts`

Purpose:

- external request and response contracts
- report type enums used by public interfaces
- stable contract objects shared across runtime and application boundaries

This module describes interfaces, not adapters.

#### `abilities/exam-sprint/application`

Purpose:

- use case orchestration
- generation workflow coordination
- dispatching and scheduling coordination
- transaction boundaries
- invoking domain policies and infrastructure ports

This module answers: how is a use case executed?

#### `abilities/exam-sprint/domain`

Purpose:

- report aggregate and related value objects
- report type policies
- business rules and state transitions
- repository and generation port interfaces

This module answers: what is correct in business terms?

#### `abilities/exam-sprint/infrastructure`

Purpose:

- Azure Blob Storage implementation
- in-memory or future persistence implementations
- PDF generation implementation
- template rendering implementation
- type-specific rendering adapters

This module answers: how does the system talk to external systems?

## Naming Layers

The naming stack must follow this order:

1. business capability domain: `exam-sprint`
2. stable business resource: `report`
3. report type: `outlook`, `achievement`
4. implementation concern: generation, rendering, storage, delivery

The naming stack must not follow this order:

1. storage technology
2. PDF generation mechanism
3. async task mechanism
4. current single report type

## Package Naming

### Root package

- Current: `cn.yunzhixue.microservice.ability`
- Target: `cn.yunzhixue.ability.center`

`microservice` should be removed from the primary package identity because it describes a deployment style, not a stable business model.

### Target package layout

```text
cn.yunzhixue.ability.center
├── kernel
├── examsprint
│   ├── contracts
│   │   └── report
│   ├── application
│   │   └── report
│   ├── domain
│   │   └── report
│   ├── infrastructure
│   │   └── report
│   └── adapter
│       └── http
```

### Type-specific implementation packages

Type-specific rendering or handling belongs below the report capability, for example:

```text
cn.yunzhixue.ability.center.examsprint.infrastructure.report.rendering.outlook
cn.yunzhixue.ability.center.examsprint.infrastructure.report.rendering.achievement
```

This keeps `outlook` and `achievement` visible where they are truly relevant, without allowing them to dominate the whole bounded context.

## API Resource Design

### External resource identity

Public APIs should expose the resource as `report`, not `task`.

#### Target paths

- `POST /api/exam-sprint/reports`
- `GET /api/exam-sprint/reports/{reportId}`
- `GET /api/exam-sprint/reports/{reportId}/download`

#### Explicitly rejected public path

- `GET /api/exam-sprint/reports/downloads?storageKey=...`

`storageKey` is an infrastructure detail and must not be a public resource lookup mechanism.

### Public resource behavior

- Clients create a report.
- Clients query a report.
- Clients download a report artifact when available.
- Clients select the report type through a contract field, not through a new top-level capability path.

## Public Contract Design

### Top-level request

Use a stable request that supports multiple report types:

- `CreateExamSprintReportRequest`

Recommended fields:

- `reportType`
- `payload`

### Report type enum

- `ExamSprintReportType`
  - `OUTLOOK`
  - `ACHIEVEMENT`

### Top-level response models

- `CreateExamSprintReportResponse`
- `ExamSprintReportDetailResponse`
- `ExamSprintReportGenerationStatus`

Recommended common response fields:

- `reportId`
- `reportType`
- `generationStatus`
- `createdAt`
- `updatedAt` where applicable
- `expiresAt`
- `downloadUrl`
- `failureReason`

### Why `reportId` instead of `taskId`

`taskId` reveals processing mechanics. `reportId` reflects the business resource that the client actually owns.

## Domain Model Naming

### Core aggregate

- Current direction to retire: `OutlookReportTaskRecord`
- Target direction: `ExamSprintReport`

### Repository

- Current direction to retire: `OutlookReportTaskRepository`
- Target direction: `ExamSprintReportRepository`

### Internal identity and state naming

Recommended internal terms:

- `reportId`
- `reportType`
- `generationStatus`
- `storageObjectKey`
- `fileName`
- `failureReason`

If the system keeps an internal generation workflow object separate from the public report aggregate later, that internal split must still preserve `ExamSprintReport` as the stable business-facing root concept.

## Application Layer Naming

Recommended target names:

- `ExamSprintReportController` for the runtime HTTP entrypoint
- `ExamSprintReportApplicationService`
- `ExamSprintReportGenerationDispatcher`
- `AsyncExamSprintReportGenerationDispatcher`
- `ExamSprintReportGenerationWorker`
- `ExamSprintReportRetentionScheduler`

The public-facing HTTP controller should not expose `task` in its name. Internal asynchronous and retention mechanics may still use `generation`, `dispatcher`, `worker`, and `scheduler` where that precision adds clarity.

## Infrastructure Naming

Recommended target names:

- `ExamSprintReportStorage`
- `AzureBlobExamSprintReportStorage`
- `InMemoryExamSprintReportStorage`
- `ExamSprintReportPdfGenerator`
- `OpenHtmlToPdfExamSprintReportPdfGenerator`
- `ExamSprintReportRenderer`
- `ClasspathOutlookExamSprintReportRenderer`
- `ClasspathAchievementExamSprintReportRenderer`

`outlook` and `achievement` should appear in infrastructure names when differentiating type-specific rendering or handler implementations.

## Outlook Payload Naming

The current `OutlookReport` request payload should become a type-specific payload instead of a top-level API request.

### Payload type

- Current direction to retire: `CreateOutlookReportTaskRequest`
- Target direction: `OutlookExamSprintReportPayload`

### Top-level payload fields

- `reportMetadata`
- `readinessOverview`
- `syllabusMasteryProfile`
- `pastPaperVocabularyProfile`
- `highFrequencyVocabularyProfile`
- `vocabularyFrequencyBands`
- `sprintPlanOptions`
- `diagnosticCaseStudy`

### Nested payload types

- `ReportMetadata`
- `ReadinessOverview`
- `SyllabusMasteryProfile`
- `VocabularyProfile`
- `DimensionScore`
- `VocabularyFrequencyBand`
- `SprintPlanOption`
- `DiagnosticCaseStudy`

### Specific field decisions

#### `ReportMetadata`

- `reportVersionLabel`
- `learnerName`
- `targetExamName`
- `sprintPeriodLabel`
- `authorName`

`reportTitle` is rejected because the current meaning is closer to a version or label than the document's actual primary title.

#### `ReadinessOverview`

- `summary`
- `currentStage`
- `keyInsight`
- `readinessScore`

#### `SyllabusMasteryProfile`

- `masteryPercent`
- `diagnosis`
- `recommendation`
- `dimensionScores`

#### `VocabularyProfile`

- `masteredWordCount`
- `totalWordCount`
- `masteryPercent`
- `diagnosis`
- `recommendation`
- `sampleWords`

#### Vocabulary profile field names

- current `examVocabulary` → target `pastPaperVocabularyProfile`
- current `commonVocabularyMastery` → target `highFrequencyVocabularyProfile`

`commonVocabularyMastery` is rejected because it mixes a vague scope (`common`) with a narrow metric word (`mastery`) while actually representing a full profile object.

#### `VocabularyFrequencyBand`

- `bandLabel`
- `masteryPercent`
- `targetPercent`

#### `SprintPlanOption`

- `planName`
- `cadenceLabel`
- `focus`
- `actionItems`
- `expectedOutcome`
- `tagLabel` (recommended addition)

`cycleLabel` is rejected as a long-term field name because it currently mixes at least two meanings: cadence text and recommendation-style tagging.

#### `DiagnosticCaseStudy`

- `title`
- `context`
- `diagnosis`
- `strategy`
- `keyTakeaway`

## Naming Rules for Future Report Types

When a new report type is introduced, apply these rules:

1. Add a new `ExamSprintReportType` value.
2. Keep public resource paths unchanged under `/api/exam-sprint/reports`.
3. Add type-specific payload and rendering/handling classes under the `report` capability.
4. Do not invent a new top-level capability domain unless the business domain itself changes.
5. Keep common report lifecycle naming shared across all types.

## Names to Retire

The following names should be retired from the long-term primary naming system:

- `ability-service`
- `microservice` in the root package prefix
- `OutlookReportTask...` as a primary resource family
- `taskId` in public contracts
- `storageKey` in public contracts
- `VocabularyModule`
- `commonVocabularyMastery`
- `cycleLabel` as a single overloaded field
- `/api/reports/outlook/tasks`
- `/downloads?storageKey=...`

## Accepted Long-Term Vocabulary

The long-term naming language should prioritize:

- `ability-center`
- `exam-sprint`
- `report`
- `reportType`
- `outlook`
- `achievement`
- `generation`
- `retention`
- `storage`
- `renderer`
- `kernel`

## Migration Guidance

This design is about naming direction, not implementation sequencing. The migration can happen incrementally, but every incremental step should converge on the same final vocabulary:

1. rename repository and root identifiers
2. establish module layout and package roots
3. replace public API resource naming
4. replace public contract naming
5. replace domain and application naming
6. move type-specific concepts under the report type model

No intermediate rename should introduce a second temporary vocabulary that conflicts with this target system.
