Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions frontend/.dart_tool/package_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@
"packageUri": "lib/",
"languageVersion": "3.7"
},
{
"name": "http",
"rootUri": "file:///Users/akarso/.pub-cache/hosted/pub.dev/http-0.13.6",
"packageUri": "lib/",
"languageVersion": "2.19"
},
{
"name": "http_parser",
"rootUri": "file:///Users/akarso/.pub-cache/hosted/pub.dev/http_parser-4.1.2",
"packageUri": "lib/",
"languageVersion": "3.4"
},
{
"name": "leak_tracker",
"rootUri": "file:///Users/akarso/.pub-cache/hosted/pub.dev/leak_tracker-10.0.9",
Expand Down Expand Up @@ -133,6 +145,12 @@
"packageUri": "lib/",
"languageVersion": "3.5"
},
{
"name": "typed_data",
"rootUri": "file:///Users/akarso/.pub-cache/hosted/pub.dev/typed_data-1.4.0",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{
"name": "vector_math",
"rootUri": "file:///Users/akarso/.pub-cache/hosted/pub.dev/vector_math-2.1.4",
Expand Down
12 changes: 12 additions & 0 deletions frontend/.dart_tool/package_config_subset
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ fake_async
3.3
file:///Users/akarso/.pub-cache/hosted/pub.dev/fake_async-1.3.3/
file:///Users/akarso/.pub-cache/hosted/pub.dev/fake_async-1.3.3/lib/
http
2.19
file:///Users/akarso/.pub-cache/hosted/pub.dev/http-0.13.6/
file:///Users/akarso/.pub-cache/hosted/pub.dev/http-0.13.6/lib/
http_parser
3.4
file:///Users/akarso/.pub-cache/hosted/pub.dev/http_parser-4.1.2/
file:///Users/akarso/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/
leak_tracker
3.2
file:///Users/akarso/.pub-cache/hosted/pub.dev/leak_tracker-10.0.9/
Expand Down Expand Up @@ -74,6 +82,10 @@ test_api
3.5
file:///Users/akarso/.pub-cache/hosted/pub.dev/test_api-0.7.4/
file:///Users/akarso/.pub-cache/hosted/pub.dev/test_api-0.7.4/lib/
typed_data
3.5
file:///Users/akarso/.pub-cache/hosted/pub.dev/typed_data-1.4.0/
file:///Users/akarso/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/
vector_math
2.14
file:///Users/akarso/.pub-cache/hosted/pub.dev/vector_math-2.1.4/
Expand Down
29 changes: 28 additions & 1 deletion frontend/.dart_tool/package_graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"name": "pano_chart_frontend",
"version": "0.0.0",
"dependencies": [
"flutter"
"flutter",
"http"
],
"devDependencies": [
"flutter_test"
Expand Down Expand Up @@ -41,6 +42,15 @@
"vm_service"
]
},
{
"name": "http",
"version": "0.13.6",
"dependencies": [
"async",
"http_parser",
"meta"
]
},
{
"name": "flutter",
"version": "0.0.0",
Expand Down Expand Up @@ -211,10 +221,27 @@
"term_glyph"
]
},
{
"name": "http_parser",
"version": "4.1.2",
"dependencies": [
"collection",
"source_span",
"string_scanner",
"typed_data"
]
},
{
"name": "sky_engine",
"version": "0.0.0",
"dependencies": []
},
{
"name": "typed_data",
"version": "1.4.0",
"dependencies": [
"collection"
]
}
],
"configVersion": 1
Expand Down
167 changes: 167 additions & 0 deletions frontend/docs/PR-004.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# PR-004 — HTTP Adapter (Candle API)

## Purpose

Introduce the **HTTP adapter** that implements the `CandleApi` port defined in `frontend/PR-002.md` and connects the frontend application layer to the backend `/api/v1/candles` endpoint frozen in `docs/PR-011.md`.

This PR is the **only place** where HTTP, JSON transport, and network concerns are allowed.

---

## References

* `AGENTS.md` — global collaboration rules
* `COMMON.md` — shared API semantics
* `frontend/PR-002.md` — CandleApi port & DTOs
* `frontend/PR-003.md` — GetCandleSeries frontend use case
* `docs/PR-011.md` — frozen backend API contract

---

## Scope (Hard Lock)

### ✅ Included

* HTTP implementation of `CandleApi`
* Query parameter mapping
* JSON decoding into DTOs
* Network error translation
* Adapter-level tests

### ❌ Excluded

* UI widgets
* State management
* Caching
* Retry logic
* Authentication

If it is not HTTP transport, it does not belong here.

---

## Folder Structure

```
/frontend/lib/
features/candles/
infrastructure/
http_candle_api.dart

/frontend/test/
features/candles/infrastructure/
```

---

## HTTP Client Choice (Locked)

* Use `package:http` (dart `http` client)
* No Dio

Rationale:

* Small surface area
* Easy to fake in tests
* No interceptors or magic

---

## Adapter Responsibilities

### HttpCandleApi

Responsibilities:

* Build GET request for `/api/v1/candles`
* Encode query parameters
* Decode JSON response
* Return `CandleSeriesResponse`

Constraints:

* Stateless
* No caching
* No retries
* No Flutter widget dependencies

---

## Request Mapping Rules

* `symbol`, `timeframe`, `from`, `to` mapped 1:1 to query parameters
* `from` and `to` serialized as RFC3339 strings
* Query parameters must be URL-encoded

---

## Response Handling Rules

* HTTP 200 → parse response body
* HTTP 400 → throw client error
* HTTP 500 → throw server error
* Unexpected status → generic failure

Error types may be simple and internal.

---

## Testing Requirements

### Required Test Cases

* `HttpCandleApi_buildsCorrectRequest`
* `HttpCandleApi_parsesSuccessfulResponse`
* `HttpCandleApi_handles400`
* `HttpCandleApi_handles500`

Tests must:

* Fake HTTP client
* Avoid real network calls

---

## Implementation Constraints

* Constructor injection of HTTP client and base URL
* No static globals
* No logging

---

## Definition of Done (PR-004)

PR-004 is considered **done** only when **all** conditions below are met:

* [ ] `CandleApi` implemented via HTTP
* [ ] Query parameters match backend contract
* [ ] JSON decoded into DTOs
* [ ] Error cases covered by tests
* [ ] No UI or state logic present
* [ ] Static analysis passes
* [ ] PR is reviewable in under 20 minutes

---

## Explicit Non-Goals

* No request retries
* No timeout tuning
* No cancellation support

---

## Reviewer Checklist

Reviewer must confirm:

* Adapter respects API contract exactly
* No logic leakage beyond transport
* HTTP client is properly injected

---

## Guiding Principle

Transport is a detail, not a decision.
Empty file added frontend/docs/PR-005.md
Empty file.
56 changes: 56 additions & 0 deletions frontend/lib/features/candles/infrastructure/http_candle_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'dart:convert';

import 'package:http/http.dart' as http;

import '../api/candle_api.dart';
import '../api/candle_request.dart';
import '../api/candle_response.dart';

class HttpCandleApiException implements Exception {
final int? statusCode;
final String message;

HttpCandleApiException(this.message, {this.statusCode});

@override
String toString() =>
'HttpCandleApiException(statusCode: $statusCode, message: $message)';
}

/// HTTP adapter implementing [CandleApi].
class HttpCandleApi implements CandleApi {
final String baseUrl;
final http.Client _client;

HttpCandleApi({required this.baseUrl, http.Client? client})
: _client = client ?? http.Client();

@override
Future<CandleSeriesResponse> fetchCandles(CandleRequest request) async {
final uri =
Uri.parse(baseUrl).replace(path: '/api/v1/candles', queryParameters: {
'symbol': request.symbol,
'timeframe': request.timeframe,
'from': request.from.toUtc().toIso8601String(),
'to': request.to.toUtc().toIso8601String(),
});

final res = await _client.get(uri);

if (res.statusCode == 200) {
final body = jsonDecode(res.body) as Map<String, dynamic>;
return CandleSeriesResponse.fromJson(body);
}

if (res.statusCode == 400) {
throw HttpCandleApiException('Bad request', statusCode: 400);
}

if (res.statusCode == 500) {
throw HttpCandleApiException('Server error', statusCode: 500);
}

throw HttpCandleApiException('Unexpected status: ${res.statusCode}',
statusCode: res.statusCode);
}
}
1 change: 1 addition & 0 deletions frontend/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ environment:
dependencies:
flutter:
sdk: flutter
http: ^0.13.0

dev_dependencies:
flutter_test:
Expand Down
Loading