Skip to content

Commit 509154b

Browse files
author
Sergii Solonyna
committed
Update documentation for releasing a new version and clarify CI process for pub.dev publishing
1 parent 02571b6 commit 509154b

2 files changed

Lines changed: 177 additions & 10 deletions

File tree

CLAUDE.md

Lines changed: 153 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,53 @@ dart test
2222

2323
# Run tests with coverage
2424
dart test --coverage=coverage
25+
26+
# Check publish readiness (dry run)
27+
dart pub publish --dry-run
28+
```
29+
30+
## Releasing a New Version
31+
32+
Publishing to pub.dev is automated via GitHub Actions (`.github/workflows/publish.yml`). It triggers when a git tag matching `v*.*.*` is pushed. **The tag version must exactly match `pubspec.yaml`** — CI enforces this and fails the pipeline if they differ.
33+
34+
Steps to release:
35+
36+
```bash
37+
# 1. Update version in pubspec.yaml
38+
# e.g., change: version: 1.0.0
39+
# to: version: 1.1.0
40+
41+
# 2. Update CHANGELOG.md
42+
# - Move all items from [Unreleased] into a new versioned section:
43+
# ## [1.1.0] - 2026-03-01
44+
# - Add the new version comparison link at the bottom:
45+
# [1.1.0]: https://github.com/astro-api/astroapi-flutter/compare/v1.0.0...v1.1.0
46+
# - Update the [Unreleased] link to compare from the new tag:
47+
# [Unreleased]: https://github.com/astro-api/astroapi-flutter/compare/v1.1.0...HEAD
48+
49+
# 3. Commit both files
50+
git add pubspec.yaml CHANGELOG.md
51+
git commit -m "chore: release v1.1.0"
52+
53+
# 4. Create an annotated git tag — must be "v" + exact pubspec version
54+
git tag v1.1.0
55+
56+
# 5. Push the commit and the tag (tag push triggers publish.yml)
57+
git push origin main
58+
git push origin v1.1.0
2559
```
2660

61+
The CI pipeline then:
62+
1. Validates tag version == pubspec.yaml version
63+
2. Runs `dart analyze` + `dart format` check
64+
3. Runs `dart test`
65+
4. Publishes via `dart pub publish --force` to pub.dev
66+
67+
**Semantic versioning rules** (follow [semver.org](https://semver.org)):
68+
- `PATCH` (1.0.x) — bug fixes, no API changes
69+
- `MINOR` (1.x.0) — new features, backwards-compatible
70+
- `MAJOR` (x.0.0) — breaking API changes
71+
2772
## Architecture
2873

2974
```
@@ -37,12 +82,101 @@ lib/
3782
dio_http_client.dart # Dio-based implementation with retry
3883
errors/astrology_exception.dart # AstrologyException
3984
categories/ # 16 category clients
85+
base_category_client.dart # Base class all clients extend
4086
models/
4187
requests/ # Request types (toJson())
42-
responses/ # Response types (fromJson())
43-
enums/ # Language, HouseSystem, etc.
88+
requests.dart # Omnibus file, ~1750 lines, all request classes
89+
birth_data.dart, subject.dart # Core shared request models
90+
chart_options.dart, data_options.dart, standard_options.dart
91+
report_options.dart, date_time_location.dart, fixed_stars_config.dart
92+
responses/
93+
responses.dart # All response types (fromJson() + GenericResponse typedefs)
94+
enums/ # Language, HouseSystem, ZodiacType, Tradition,
95+
# PerspectiveType, DetailLevel
96+
```
97+
98+
## Layer-by-Layer Reference
99+
100+
### Entry Point
101+
102+
`lib/astroapi.dart` is the barrel export. Everything a user (or AI) needs is re-exported from here: the main client, config, errors, HttpHelper, all 16 category clients, all 6 enums, all request and response models.
103+
104+
### AstrologyClient (`lib/src/client/astrology_client.dart`)
105+
106+
Creates a single `DioHttpClient` from the config and passes it to all 16 category clients. Exposes them as named getters:
107+
108+
| Getter | Client class | Description |
109+
|--------|-------------|-------------|
110+
| `.data` | `DataClient` | Planetary positions, aspects, house cusps, lunar metrics |
111+
| `.charts` | `ChartsClient` | Natal, synastry, composite, transit, solar/lunar return charts |
112+
| `.analysis` | `AnalysisClient` | Natal, synastry, composite, compatibility, progression reports |
113+
| `.horoscope` | `HoroscopeClient` | Personal and sun-sign horoscopes (daily/weekly/monthly/yearly) |
114+
| `.glossary` | `GlossaryClient` | Zodiac signs, planets, aspects, house systems, cities lookup |
115+
| `.astrocartography` | `AstrocartographyClient` | Location analysis, power zones, relocation charts |
116+
| `.chinese` | `ChineseClient` | Ba Zi, zodiac, solar terms, element balance |
117+
| `.eclipses` | `EclipsesClient` | Upcoming eclipses, natal checks, interpretations |
118+
| `.lunar` | `LunarClient` | Moon phases, lunar mansions, void-of-course periods |
119+
| `.numerology` | `NumerologyClient` | Core numbers, comprehensive analysis, compatibility |
120+
| `.tarot` | `TarotClient` | Card draws, spreads, birth cards, daily cards |
121+
| `.traditional` | `TraditionalClient` | Dignities, receptions, almutens, lots, profections, firdaria |
122+
| `.fixedStars` | `FixedStarsClient` | Fixed star positions, conjunctions, presets |
123+
| `.svg` | `SvgClient` | SVG chart images — returns `String`, not JSON |
124+
| `.enhanced` | `EnhancedClient` | Enhanced personal and global analysis |
125+
| `.insights` | `InsightsClient` | Has 5 sub-clients (see below) |
126+
127+
`InsightsClient` exposes: `.relationship`, `.pet`, `.wellness`, `.financial`, `.business`
128+
129+
### Config Layer (`lib/src/config/astrology_client_config.dart`)
130+
131+
- **`AstrologyClientConfig`**: `apiKey` (required), `baseUrl`, `timeout` (ms, default 10000), `debug` (bool), `logger` (function), `retry` (RetryConfig)
132+
- Env var fallbacks: `ASTROLOGY_API_KEY`, `ASTROLOGY_API_BASE_URL`
133+
- **`RetryConfig`**: `attempts`, `delayMs`, `retryStatusCodes` (default: `[408, 425, 429, 500, 502, 503, 504]`)
134+
- **`RequestOptions`**: per-request `headers`, `queryParams`, `timeout` override, Dio `CancelToken`
135+
136+
### HTTP Layer (`lib/src/http/`)
137+
138+
- **`HttpHelper`** (abstract interface): `get`, `post`, `put`, `delete` — the only dependency injected into category clients; mock this in tests
139+
- **`DioHttpClient`** (concrete Dio implementation):
140+
- Injects `Authorization: Bearer <apiKey>` via Dio interceptor
141+
- Auto-unwraps `data` or `result` envelope keys from API responses
142+
- Implements retry logic based on `RetryConfig`
143+
144+
### Category Clients (`lib/src/categories/`)
145+
146+
- All extend `BaseCategoryClient` (holds the `HttpHelper` reference)
147+
- Each exposes typed `async` methods returning response model instances
148+
- `SvgClient` is the exception: returns raw `String` (SVG markup), not a model
149+
150+
### Request Models (`lib/src/models/requests/`)
151+
152+
Plain Dart classes with `toJson()`**no code generation**. The main file `requests.dart` is an omnibus (~1750 lines) with all request classes. Shared building blocks live in separate files (`BirthData`, `Subject`, `ChartOptions`, etc.) and are exported from the barrel.
153+
154+
### Response Models (`lib/src/models/responses/responses.dart`)
155+
156+
Two strategies:
157+
- **Fully typed** (commonly-accessed fields): `PlanetaryPositionsResponse`, `AspectsResponse`, `HouseCuspsResponse`, `ChartData` — have real `fromJson()` factories
158+
- **`GenericResponse`** (variable/complex schemas): wraps `Map<String, dynamic>`; dozens of `typedef` aliases provide semantic names (e.g., `typedef HoroscopeResponse = GenericResponse`). This is intentional — not a TODO.
159+
160+
### Error Handling (`lib/src/errors/astrology_exception.dart`)
161+
162+
`AstrologyException` fields: `statusCode`, `code`, `message`. Factory `fromDioError()` normalises Dio errors into `AstrologyException`.
163+
164+
## Testing
165+
166+
Uses `mocktail` to mock `HttpHelper`:
167+
168+
```dart
169+
class MockHttpHelper extends Mock implements HttpHelper {}
170+
171+
final client = DataClient(MockHttpHelper());
44172
```
45173

174+
Test layout:
175+
- `test/helpers/test_helpers.dart``MockHttpHelper`, shared test data factories
176+
- `test/unit/client_test.dart``AstrologyClient` construction and sub-client wiring
177+
- `test/unit/errors/astrology_exception_test.dart` — exception parsing
178+
- `test/unit/categories/` — one test file per category client (16 files)
179+
46180
## Usage Example
47181

48182
```dart
@@ -80,7 +214,7 @@ final compat = await client.insights.relationship.getCompatibility(
80214
CompatibilityRequest(subjects: [subject1, subject2]),
81215
);
82216
83-
// SVG chart
217+
// SVG chart (returns String)
84218
final svg = await client.svg.getNatalChartSvg(
85219
NatalChartSvgRequest(subject: subject),
86220
);
@@ -89,18 +223,27 @@ final svg = await client.svg.getNatalChartSvg(
89223
## Key Design Decisions
90224

91225
- **No code generation**: Plain Dart classes instead of freezed/json_serializable for simplicity and faster compilation
92-
- **GenericResponse**: Complex API responses use `GenericResponse` (wraps `Map<String, dynamic>`) with typed fields for commonly-used properties
226+
- **GenericResponse**: Complex API responses use `GenericResponse` (wraps `Map<String, dynamic>`) — intentional, not a gap to fill
93227
- **HttpHelper abstraction**: The `HttpHelper` interface enables easy mocking in tests with `mocktail`
94228
- **Retry logic**: Built into `DioHttpClient`, configurable via `RetryConfig`
95229
- **SVG responses**: `SvgClient` returns `String` directly instead of JSON
96230
- **InsightsClient**: Has 5 sub-clients (relationship, pet, wellness, financial, business)
97231

98-
## Testing
232+
## Extending the SDK
99233

100-
Uses `mocktail` to mock `HttpHelper`:
234+
**Add a new category client:**
235+
1. Create `lib/src/categories/<name>_client.dart`, extend `BaseCategoryClient`
236+
2. Add a getter to `AstrologyClient` in `lib/src/client/astrology_client.dart`
237+
3. Export from `lib/astroapi.dart`
101238

102-
```dart
103-
class MockHttpHelper extends Mock implements HttpHelper {}
239+
**Add a new request model:**
240+
1. Add the class with `toJson()` to `lib/src/models/requests/requests.dart` (or its own file)
241+
2. Export from `lib/astroapi.dart`
104242

105-
final client = DataClient(MockHttpHelper());
106-
```
243+
**Add a new response model:**
244+
1. Add `fromJson()` factory to `lib/src/models/responses/responses.dart`
245+
2. Export from `lib/astroapi.dart`
246+
247+
**Add a new enum:**
248+
1. Create `lib/src/models/enums/<name>.dart`
249+
2. Export from `lib/astroapi.dart`

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,30 @@ try {
105105
}
106106
```
107107

108+
## Releasing a New Version
109+
110+
Publishing to pub.dev is automated via GitHub Actions and triggers when a git tag is pushed. The tag version **must match** `pubspec.yaml` exactly — CI enforces this.
111+
112+
```bash
113+
# 1. Update version in pubspec.yaml (e.g. 1.0.0 → 1.1.0)
114+
115+
# 2. Update CHANGELOG.md — move [Unreleased] items to a new [1.1.0] section,
116+
# update the comparison links at the bottom
117+
118+
# 3. Commit
119+
git add pubspec.yaml CHANGELOG.md
120+
git commit -m "chore: release v1.1.0"
121+
122+
# 4. Tag — must be "v" + exact pubspec version
123+
git tag v1.1.0
124+
125+
# 5. Push commit and tag (tag push triggers publish to pub.dev)
126+
git push origin main
127+
git push origin v1.1.0
128+
```
129+
130+
Semver rules: `PATCH` for bug fixes, `MINOR` for new backwards-compatible features, `MAJOR` for breaking changes.
131+
108132
## License
109133

110134
MIT

0 commit comments

Comments
 (0)