FX Risk Calculator is a Flask-based backend that stores portfolios and FX positions, pulls normalized exchange-rate data from configurable providers (e.g., ExchangeRate.host), and exposes health/validation endpoints to support FX risk analysis workflows.
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, frontend, calculations, api, ui
-
Assignees: umutdinceryananer
-
URL: https://github.com/umutdinceryananer/FX-Risk-Calculator/issues/44
-
Estimate: 3-4h
Enable switching the portfolio view base from the UI without persisting multi-base rates by rebasing canonical USD snapshots on the fly.
Acceptance Criteria
-
Backend: provide a
rebase_snapshot(rates_usd, new_base)helper and use it to serve metrics when?base=<CCY>is supplied (default toportfolio.base). -
Backend: reject invalid base codes or missing
<new_base>/USDquotes with a 422 response, and include{"view_base": "<CCY>", "as_of_date": "<YYYY-MM-DD>"}in metrics replies. -
Frontend: add a “View in” dropdown (e.g., USD/EUR/GBP/TRY) on the dashboard that refetches value, exposure, P&L, and timeline endpoints with
?baseand remembers the selection inlocalStorage.
Technical Notes
-
Canonical stored base remains USD (
FX_CANONICAL_BASE); ECB fallback must normalize to USD before persisting. -
All Decimal math should respect the shared rounding policy.
-
Dropdown changes should debounce to avoid excessive refresh traffic.
Test Notes
-
Backend unit tests covering EUR/GBP/TRY rebasing, invalid base handling, and missing quote failures.
-
Frontend tests verifying dropdown selection triggers refetches and persists across reloads.
Subtasks
-
Backend rebase helper + validation
-
Metrics endpoint
?baseplumbing -
Frontend dropdown + persistence
-
Docs/OpenAPI updates
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: meta
-
Assignees: umutdinceryananer
-
URL: #43
Description
Polish release: verify health, update docs, close redundant tasks.
Acceptance Criteria
-
Health endpoints green; demo works end-to-end.
-
README & Postman reflect final endpoints.
Technical Notes
- Tag a lightweight release in Git.
Test Notes
- Manual system test pass.
Subtasks
-
Final QA checklist
-
Close issues
-
Add a scripted release gate (e.g.,
make release-check) that runspytest, provider smoke tests, and health checks before tagging. -
Commit the Postman collection with the README update and version it alongside the release tag.
-
Provide a small helper (e.g.,
scripts/tag_release.py) to automate creating signed Git tags for repeatable releases.
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: infra, docs
-
Assignees: umutdinceryananer
-
URL: #42
Description
Default provider order and env validation.
Acceptance Criteria
-
.env.example:FX_PRIMARY_PROVIDER=exchange,FX_FALLBACK_PROVIDER=ecb. -
App warns on unsupported provider values.
Technical Notes
- Single source of truth in
config.py.
Test Notes
- Boot with only Exchange & ECB.
Subtasks
-
Env update
-
Config guard
-
Centralize supported provider identifiers in
config.pyand validate env values during boot, logging actionable errors when mismatched. -
Extend
.env.examplewith a table summarizing primary/fallback providers, required variables, and behavior. -
Add a unit test that boots with Exchange + ECB values to guard against configuration regressions.
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: frontend, ui
-
Assignees: umutdinceryananer
-
URL: #41
Description
Friendly UX for provider failures/timeouts and validation errors.
Acceptance Criteria
-
Toasts for network/HTTP errors; retry CTA for refresh.
-
Form validation messages inline for CRUD screens.
Technical Notes
- Map known codes (422/429/5xx) to friendly messages.
Test Notes
- Simulate failures with mocked responses.
Subtasks
-
Error handler module
-
UI toasts/messages
-
Ensure backend errors include structured fields (
code,message, optionalretry_after) so the frontend toast layer can map responses cleanly. -
Build a reusable client-side error utility that converts HTTP status/validation payloads into toast copy and inline form messages.
-
Cover timeout, validation failure, and 5xx retry flows in UI tests (Cypress/Playwright) using mocked APIs.
-
State: OPEN
-
Author: umutdinceryananer
-
Labels: docs, data
-
Assignees: umutdinceryananer
-
URL: #40
Description
Add deterministic demo data for first-run experience.
Acceptance Criteria
-
ΓÇ£Global Book (USD)ΓÇ¥ + 4ΓÇô6 diverse positions (LONG/SHORT, multiple CCYs).
-
Idempotent seed (safe to re-run).
Technical Notes
- Provide a CLI
seed_democommand.
Test Notes
- Dashboard shows values on first run.
Subtasks
-
Seed script
-
README instructions
-
Implement an idempotent
seed_demoCLI command (e.g.,flask seed demo) that upserts the portfolio and positions. -
Document the command in a new README "Quick Try" section guiding users through seeding and calling demo endpoints.
-
Reuse the seeded portfolio within integration tests to validate risk calculations end-to-end without duplicating fixtures.
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: docs
-
Assignees: umutdinceryananer
-
URL: #39
Description
Write complete documentation and example requests.
Acceptance Criteria
-
README: setup, run, seed, scheduler, provider order, stale semantics.
-
Postman collection with env variables.
-
Link to
/docs(OpenAPI) and note data attribution (Exchange + ECB).
Technical Notes
- Include a troubleshooting section.
Test Notes
- New machine walkthrough.
Subtasks
-
README
-
Postman JSON
-
API schema export
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, performance
-
Assignees: umutdinceryananer
-
URL: #38
Description
Ensure endpoints meet basic latency budgets and avoid N+1.
Acceptance Criteria
-
Value calc < 250 ms for ~2k positions on local dev.
-
Dashboard TTFB < 2s.
-
Confirm proper indexes are used.
Technical Notes
- Add simple timing logs; inspect query plans if needed.
Test Notes
- Run with generated data set.
Subtasks
-
Timing logs
-
Query/index review
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, testing
-
Assignees: umutdinceryananer
-
URL: #37
Description
Spin up app in test mode and verify full flow: Create portfolio → add positions → refresh → metrics → what-if.
Acceptance Criteria
-
E2E passes using mocked providers (no external calls).
-
Response contracts verified; totals sane.
Technical Notes
- Use Flask test client + in-memory DB or isolated test DB.
Test Notes
- Include fallback scenario (Exchange down → ECB).
Subtasks
-
E2E script
-
Mocks & fixtures
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: testing
-
Assignees: umutdinceryananer
-
URL: #36
Description
Comprehensive pytest suite for calculations, providers, and CRUD.
Acceptance Criteria
-
Calculations ≥90% coverage; overall ≥80%.
-
Provider tests mock HTTP with
responses. -
Time-dependent tests use
freezegun.
Technical Notes
- Organize tests by module; fixtures for standard payloads.
Test Notes
- Edge cases: SHORT signs, shocks, rounding, weekend gaps.
Subtasks
-
Calc tests
-
Provider tests
-
CRUD tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: infra, devx
-
Assignees: umutdinceryananer
-
URL: #35
Description
Containerize API + Postgres with docker compose for quick setup.
Acceptance Criteria
-
docker compose upstarts API + Postgres; app reachable; Alembic auto-migrates. -
Healthchecks for both services.
Technical Notes
- Mount code for live reload in development; environment via
.env.
Test Notes
- Fresh machine smoke test.
Subtasks
-
Dockerfile
-
docker-compose.yml
-
Healthchecks + Makefile
-
State: OPEN
-
Author: umutdinceryananer
-
Labels: infra, ci
-
Assignees: umutdinceryananer
-
URL: #34
Description
Run tests/lint in CI with Postgres service; publish coverage badge.
Acceptance Criteria
-
Workflow runs Python tests (pytest + coverage) and lint; frontend lint.
-
Postgres service available; DB URL configured.
-
Coverage gate: overall ≥80%, calc ≥90%.
-
README shows badge.
Technical Notes
-
Cache Python deps; optional matrix (3.11/3.12).
-
Use
services: postgreswith healthcheck.
Test Notes
- Dummy PR verifies CI success.
Subtasks
-
Workflow YAML
-
Coverage badge in README
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: infra, quality
-
Assignees: umutdinceryananer
-
URL: #33
Description
Automate code quality for Python and frontend.
Acceptance Criteria
-
Python: ruff/flake8, black, isort, mypy configured and passing.
-
Frontend: ESLint + Prettier configured and passing.
-
.pre-commit-config.yamlruns on commit.
Technical Notes
- Add Makefile targets:
make lint,make typecheck.
Test Notes
- Sample failing commit verified.
Subtasks
-
Config files
-
Pre-commit hooks
-
Makefile targets
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, infra
-
Assignees: umutdinceryananer
-
URL: #32
Description
Add JSON logging with request_id, duration_ms, and basic provider timing.
Acceptance Criteria
-
Log fields:
event, route, method, status, duration_ms, request_id, timestamp, source, stale. -
Request ID generated per request and propagated to logs.
Technical Notes
- Python
logging+ JSON formatter; simple middleware for request_id.
Test Notes
- Unit tests for log helper; manual inspection.
Subtasks
-
JSON formatter
-
Request ID injector
-
Timing decorator
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, security
-
Assignees: umutdinceryananer
-
URL: #31
Description
Allow front-end origin and throttle manual refresh.
Acceptance Criteria
-
CORS allows
http://localhost:<port>(configurable). -
POST /rates/refreshreturns 429 within 60s of last success.
Technical Notes
Flask-CORSfor allowed origins; in-process timestamp gate.
Test Notes
- Preflight OPTIONS handled; 429 path covered.
Subtasks
-
CORS config
-
Throttle gate
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, frontend
-
Assignees: umutdinceryananer
-
URL: #30
Description
Consistent Decimal rounding and UI formatting policy.
Acceptance Criteria
-
Rates: 6ΓÇô8 dp; Amounts: 2ΓÇô4 dp.
-
UI uses thousands separators and fixed decimal places per field.
Technical Notes
-
Centralize Decimal context and rounding in calc utils.
-
Reuse formatting helpers in frontend.
Test Notes
- No float drift; reproducible rounding.
Subtasks
-
Rounding policy doc
-
Backend utils
-
UI helpers
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, frontend
-
Assignees: umutdinceryananer
-
URL: #29
Description
Enforce UTC for storage and consistent display formatting.
Acceptance Criteria
-
DB timestamps in UTC.
-
UI shows local time with hint ΓÇ£as of UTCΓÇ¥.
-
Helpers for parse/format used everywhere.
Technical Notes
- Moment alternatives in vanilla JS (e.g.,
Intl.DateTimeFormat).
Test Notes
- DST transitions; Istanbul local display sanity.
Subtasks
-
Backend UTC utils
-
UI format helpers
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, frontend
-
Assignees: umutdinceryananer
-
URL: #28
Description
Clear user experience for positions without available rates and API errors.
Acceptance Criteria
-
API responses include
unpricedcount; reasons (unknown currency, missing pair). -
UI badge shows unpriced count; tooltip explains reason(s).
-
Toasts for refresh failures and 429 (too frequent refresh).
Technical Notes
- Map HTTP codes to human-readable messages.
Test Notes
- Unknown currency; ECB missing USD/EUR.
Subtasks
-
Backend messaging
-
UI badges/toasts
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: frontend, ui
-
Assignees: umutdinceryananer
-
URL: #27
Description
Interactive table for positions with currency/type filters, sort, and pagination.
Acceptance Criteria
-
Client-side or server-side pagination (choose based on dataset).
-
Filters apply instantly; sort by currency/amount/type.
Technical Notes
- DataTables.js or custom minimal grid; a11y friendly.
Test Notes
- 2k rows responsiveness; keyboard nav.
Subtasks
-
Grid component
-
Filters/sort
-
Pagination
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, frontend, ui
-
Assignees: umutdinceryananer
-
URL: #26
Description
Render a time-series line chart for last 30 days of portfolio value.
Acceptance Criteria
-
Continuous line; missing days are gaps (no markers).
-
Hover shows date + value.
Technical Notes
- Backend series endpoint computes daily close with stored rates + current positions (MVP).
Test Notes
- Date formatting; weekend gaps.
Subtasks
-
Backend
/metrics/portfolio/:id/value/series?days=30 -
Frontend chart
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: frontend, ui
-
Assignees: umutdinceryananer
-
URL: #25
Description
Visualize exposure by currency as bar/pie with tooltips.
Acceptance Criteria
-
Top-N grouping; an ΓÇ£OtherΓÇ¥ slice when enabled.
-
Tooltips show native net and base equivalent.
Technical Notes
- Chart.js; lazy data fetch; zero-state handling.
Test Notes
- Single vs multi-currency datasets.
Subtasks
-
Chart render
-
Legends/tooltips
-
Zero-state
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: frontend, ui
-
Assignees: umutdinceryananer
-
URL: #24
Description
Show KPI cards (Value, Daily P&L, #Positions) and allow manual refresh; display source/stale/last updated.
Acceptance Criteria
-
Header:
Source: exchange|ecb | Stale: true/false | Last updated: <date> -
ΓÇ£Refresh FXΓÇ¥ button hits backend; success/failure toasts.
-
When stale, show banner with tooltip (ΓÇ£Provider down or weekend/holidayΓÇ¥).
Technical Notes
- Debounce button to avoid duplicate clicks.
Test Notes
- Simulate failed refresh; confirm banner visibility.
Subtasks
-
KPI cards
-
Refresh flow
-
Stale banner
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: frontend, ui
-
Assignees: umutdinceryananer
-
URL: #23
Description
Bootstrap 5 shell with navbar and client-side routing for /dashboard and /portfolio.
Acceptance Criteria
-
No full page reload between sections (SPA feel).
-
Mobile responsive navbar & cards.
Technical Notes
- Vanilla JS modules; fetch API wrappers; minimal state store.
Test Notes
- Chrome/Firefox/Edge smoke; mobile viewport.
Subtasks
-
Layout + navbar
-
Router (hash or History API)
-
Fetch helpers
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, calculations
-
Assignees: umutdinceryananer
-
URL: #22
Description
Simulate a ┬▒10% shock in one currency and return impact.
Acceptance Criteria
-
POST /api/v1/metrics/portfolio/:id/whatifwith{currency, shock_pct}in [-10, 10]. -
Returns
{delta_value, new_value, shocked_currency}. -
Validation errors for out-of-range, unknown currency, or empty portfolio.
-
Support an optional
?base=<CCY>parameter so the what-if result is expressed in the requested view base and the response reportsview_baseandas_of_date.
Technical Notes
- Decimal-safe; only selected currency revalued.
Test Notes
- Positive/negative shocks; SHORT interactions.
Subtasks
-
Endpoint + validation
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, calculations
-
Assignees: umutdinceryananer
-
URL: #21
Description
Compute P&L between today (or latest) and previous available day; flag if positions changed.
Acceptance Criteria
-
GET /api/v1/metrics/portfolio/:id/pnl/daily→{pnl, as_of_date, prev_date, positions_changed}. -
Weekends/holidays handled (previous available day).
-
positions_changedchecks if composition changed sinceprev_date(basic heuristic). -
Support an optional
?base=<CCY>parameter so the P&L is expressed in the requested view base and the response reportsview_baseandas_of_date.
Technical Notes
- Basic change detection: compare counts/sums per currency and type.
Test Notes
- Missing days; DST/UTC safeguards.
Subtasks
-
Snapshot logic
-
Endpoint
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, calculations
-
Assignees: umutdinceryananer
-
URL: #20
Description
Aggregate exposure per currency with optional top-N and ΓÇ£OtherΓÇ¥ grouping.
Acceptance Criteria
-
GET /api/v1/metrics/portfolio/:id/exposure?top_n=5 -
For each currency:
net(native) &base_equiv; sorted byabs(base_equiv)desc. -
Optional ΓÇ£OtherΓÇ¥ bucket.
-
Support an optional
?base=<CCY>parameter so exposure values are returned in the requested view base withview_baseandas_of_datealongside the totals.
Technical Notes
- Respect LONG/SHORT sign; ignore unpriced in base_equiv.
Test Notes
- LONG/SHORT mixes; ties; top-N correctness.
Subtasks
-
Aggregation service
-
Endpoint + params
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, calculations
-
Assignees: umutdinceryananer
-
URL: #19
Description
Compute aggregate portfolio value in base currency.
Acceptance Criteria
-
GET /api/v1/metrics/portfolio/:id/value→{value_base, value, priced, unpriced}. -
Unpriced positions excluded from total;
unpricedcount returned. -
Support an optional
?base=<CCY>parameter (default portfolio base) that returns values in the requested view base and includesview_baseandas_of_datein the response.
Technical Notes
- Use latest available daily snapshot (by
as_of_date).
Test Notes
- Mixed priced/unpriced; rounding verified.
Subtasks
-
Service + endpoint
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, calculations
-
Assignees: umutdinceryananer
-
URL: #18
Description
Pure functions to convert native amounts to base using a rates snapshot and handle sign for LONG/SHORT.
Acceptance Criteria
-
If
pos_ccy==base, no lookup. -
LONG positive, SHORT negative contribution.
-
Deterministic with given snapshot dict.
-
Provide a
rebase_snapshot(rates_usd: dict, new_base: str) -> dicthelper with Decimal-safe calculations and shared rounding.
Technical Notes
-
One
Decimalcontext (ROUND_HALF_EVEN, adequate precision). -
No floats anywhere.
Test Notes
- ≥90% coverage for this module; edge cases around rounding.
Subtasks
-
Utils
-
Unit tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend
-
Assignees: umutdinceryananer
-
URL: #17
Description
Manage positions under a given portfolio with pagination and filtering.
Acceptance Criteria
-
POST/GET/PUT/DELETE /api/v1/portfolios/:id/positions. -
Pagination (
page,page_size), filter bycurrency,type. -
422 if
amount<=0or invalid currency; 404 for missing portfolio.
Technical Notes
- Store
typeas ENUM; Decimal parsing robust.
Test Notes
- Large numbers precision; pagination boundaries.
Subtasks
-
Endpoints + query params
-
Schemas & validation
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend
-
Assignees: umutdinceryananer
-
URL: #16
Description
REST endpoints to create/read/update/delete portfolios with base currency validation.
Acceptance Criteria
-
POST/GET/PUT/DELETE /api/v1/portfoliosimplemented. -
422 on invalid base CCY; 404 on unknown ID; clear error messages.
-
Deleting a portfolio cascades to positions.
Technical Notes
- Prefer marshmallow schemas for validation; serialize Decimal safely.
Test Notes
- Happy path + invalid ISO + unknown ID + delete cascade.
Subtasks
-
Endpoints
-
Schemas & errors
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, docs, api
-
Assignees: umutdinceryananer
-
URL: #15
Description
Generate and serve /openapi.json + /docs (Swagger UI).
Acceptance Criteria
-
Every endpoint has request/response schemas + examples.
-
/docsrenders; schema is valid (linted). -
README links to
/docs. -
Metrics endpoints document an optional
?base=USD|EUR|...query parameter (defaulting to the portfolio base) with examples for both default and explicit bases.
Technical Notes
flask-smorestorapispec+ marshmallow; reusable error schema.
Test Notes
- Contract smoke test: required fields present.
Subtasks
-
Schemas & examples
-
Swagger UI mount
-
Schema lint
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, data
-
Assignees: umutdinceryananer
-
URL: #14
Description
Backfill last 30 days for allowed currency set; idempotent inserts.
Acceptance Criteria
-
Idempotent inserts; avoids duplicates.
-
Completeness checks for the last 30 days.
-
Backfills canonical base (USD) only; other view-bases are derived at read time.
Technical Notes
- Keep inserts batched for performance (e.g.,
executemany).
Test Notes
- Completeness check; duplicate prevention.
Subtasks
-
Service + CLI
-
Tests for idempotency
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, scheduling
-
Assignees: umutdinceryananer
-
URL: #13
Description
Run APScheduler hourly; provide manual refresh POST /api/v1/rates/refresh with 60s throttle.
Acceptance Criteria
-
Job calls orchestrator and UPSERTs latest rates.
-
Manual hits are rejected with 429 if called within 60s of previous success.
-
Only one scheduler instance runs (main-process guard).
-
Scheduler fetches only canonical base (USD); no multi-base writes.
Technical Notes
-
Use
if __name__ == "__main__"guard; or an env flagSCHEDULER_ENABLED=true. -
Manual refresh does not accept base; it always refreshes canonical snapshot.
Test Notes
- Trigger job in tests; verify DB writes and headers in response.
Subtasks
-
APScheduler wiring
-
Refresh endpoint
-
Throttle state (in-process)
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, infra
-
Assignees: umutdinceryananer
-
URL: #12
Description
Centralize HTTP behaviors for providers.
Acceptance Criteria
-
Default timeout=5s; retries=2; exponential backoff with jitter.
-
Respect 429/5xx; do not retry on 4xx (except 429).
-
Uniform exceptions with
code,status,message.
Technical Notes
- Requests
SessionwithHTTPAdapter+ retry strategy; jitter via random factor.
Test Notes
- Simulate 429 with Retry-After; 5xx sequences.
Subtasks
-
Client wrapper
-
Error types
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, resiliency
-
Assignees: umutdinceryananer
-
URL: #11
Description
Try Exchange → ECB; if both fail, return last known snapshot with stale=true.
Acceptance Criteria
-
Orchestrator picks primary; on failure tries fallback; else uses last snapshot.
-
/health/ratesreturns{source, last_updated, stale}. -
Log provider timings (ms).
-
Orchestrator persists only canonical base (USD) rates. If source is ECB (EUR-base), convert to USD before persist.
Technical Notes
-
In-memory last-known snapshot cache + persisted DB latest.
-
Keep last-known-good USD-based snapshot in memory + DB. All UI view-bases are computed on demand.
Test Notes
- Simulated primary failure; both failure → stale fallback; verify health output.
Subtasks
-
Orchestrator service
-
Health wiring
-
Simple timing logs
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, api
-
Assignees: umutdinceryananer
-
URL: #10
Description
Implement ECB fallback; compute non-EUR base via cross-rate.
Acceptance Criteria
-
For USD base:
A/USD = (A/EUR) / (USD/EUR)within tolerance (e.g., 1e-6). -
Providers return normalized snapshots; orchestrator can rebase snapshots to any view base using helper, without hitting DB.
-
Handle weekend/holiday gaps (missing days).
-
Return
source='ecb'.
Technical Notes
-
Use daily series endpoints; if USD/EUR missing for date, skip that date or mark unpriced.
-
Add rebase_snapshot(snapshot, new_base) utility:
A/new_base = (A/USD) / (new_base/USD) using canonical USD snapshot.
Test Notes
- Cross-rate numeric verification; gap handling.
Subtasks
-
Frankfurter client
-
Cross-rate util
-
Tests
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, api
-
Assignees: umutdinceryananer
-
URL: #5
Description: Fetch latest and historical FX rates from Fixer.io (or equivalent).
-
Acceptance Criteria
-
get_latest("USD")returns timestamped rates for allowed symbols. -
get_history("USD","EUR",30)returns daily series. -
Proper headers, API key, and error handling.
-
-
Technical Notes
-
Respect provider base currency limitations and quotas.
-
Map provider response to normalized schema.
-
-
Test Notes
- Use HTTP mocking (responses/httpretty) and VCR-style fixtures.
-
Subtasks
-
Implement client with retries/backoff.
-
Map responses, handle errors/timeouts.
-
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, api
-
Assignees: umutdinceryananer
-
URL: #4
Description: Design provider interface to standardize real data access.
-
Acceptance Criteria
-
Interface methods:
get_latest(base:str)->{source, timestamp, rates{CCY:rate}},get_history(base, symbol, days)->series. -
All providers return normalized payloads.
-
Providers return normalized snapshots that the orchestrator can rebase to any view base without writing new records.
-
-
Technical Notes
-
Add provider registry and selection via env.
-
Add a reusable
rebase_snapshot(snapshot, new_base)utility whereA/new_base = (A/USD) / (new_base/USD)using the canonical USD snapshot.
-
-
Test Notes
- Contract tests for normalized output.
-
Subtasks
-
Define interface and dataclasses.
-
Provider registry and factory.
-
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, data
-
Assignees: umutdinceryananer
-
URL: #3
Description: Seed reference currencies and add server-side validation.
-
Acceptance Criteria
-
currenciestable populated with common codes (USD, EUR, GBP, JPY, TRY, CHF, AUD, CAD, …). -
API rejects non-ISO codes with helpful 422 message.
-
-
Technical Notes
- Maintain allowlist in DB, load on boot into in-memory set.
-
Test Notes
- Positive/negative validation tests.
-
Subtasks
-
Seed script for
currencies. -
Validation middleware/helpers.
-
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, db
-
Assignees: umutdinceryananer
-
URL: #2
Description: Implement currencies, fx_rates, portfolios, positions with indexes and constraints.
-
Acceptance Criteria
-
Alembic
upgrade/downgraderuns cleanly. -
Uniqueness:
currencies.codeand(base_currency, target_currency, timestamp, source)upsert key forfx_rates. -
Proper FKs:
positions.portfolio_id → portfolios.id.
-
-
Technical Notes
-
Indexes:
-
fx_rates(base_currency, target_currency, timestamp desc) -
positions(portfolio_id, currency)
-
-
Decimal precision:
fx_rates.rate DECIMAL(18,8);positions.amount DECIMAL(20,4).
-
-
Test Notes
- Migration smoke test on empty DB.
-
Subtasks
-
Define SQLAlchemy models.
-
Generate initial migration.
-
Add composite unique/indices.
-
-
State: CLOSED
-
Author: umutdinceryananer
-
Labels: backend, infra, docs
-
Assignees: umutdinceryananer
-
URL: #1
Description: Create Flask app factory, base structure, environment config, and health endpoints.
-
Acceptance Criteria
-
App factory pattern works;
run.pystarts server. -
.env.exampleexists and documents required variables. -
/healthand/health/ratesreturn 200 (rates can be ΓÇ£uninitializedΓÇ¥).
-
-
Technical Notes
-
Packages: Flask, SQLAlchemy, Alembic, Pydantic (or marshmallow), Requests, APScheduler.
-
Config classes: Development/Production; read from env
-
-
Test Notes
- Smoke test for
/health.
- Smoke test for
-
Subtasks
-
Create
app/__init__.pywith factory and blueprints. -
Add
config.pyand.env.example. -
Implement
/healthand/health/rates(stub). -
Update
READMEquick start.
-