From 5f49435f5ce7cf4e89efa64008e24caa744a7873 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 5 May 2025 22:58:06 +0000 Subject: [PATCH] Updated README.md --- README.md | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/README.md b/README.md index e69de29..2736ab9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,100 @@ +# Technical Assignment + +The candidate is asked to build a small project consisting of two Go processes: + +- The **API server** accepts trade submissions via POST `/trades` and writes them to a queue table. +- The **worker process** continuously reads new trades, validates them, stores them, and instantly updates the account's profit. + +Your code must compile, pass `go vet` and `go test -race`, and run via `docker-compose up`. + +## Purpose of This Task + +We want to assess your ability to write clean HTTP code, work with SQL, and reason about concurrency. + +## What You Should Build + +### Components and Architecture + +```text +┌──────────────┐ POST /trades ┌───────────────┐ +│ API Server │ ─────────────────► │ Queue Table │ +│ cmd/server │ └───────────────┘ +└──────────────┘ ▲ + │ SELECT … FOR UPDATE +┌──────────────┐ UPDATE stats │ +│ Worker │ ◄───────────────────────┘ +│ cmd/worker │ +└──────────────┘ +``` + +- **API (HTTP)** — exposes one POST endpoint and one GET endpoint. +- **Queue** — an SQLite table `trades_q` used by the API to enqueue trades, and by the worker to mark them as processed. +- **Worker** — a separate process that polls the queue every 100ms, calculates `profit`, and updates `account_stats`. + +### Trade Input Format + +| Field | Type | Validation Rule | +| - | - | - | +| `account` | string | must not be empty | +| `symbol` | string | `^[A-Z]{6}$` (e.g. EURUSD) | +| `volume` | float64 | must be > 0 | +| `open` | float64 | must be > 0 | +| `close` | float64 | must be > 0 | +| `side` | string | either "buy" or "sell" | + +Profit calculation (performed by the worker): + +```go +lot := 100000.0 +profit := (close - open) * volume * lot +if side == "sell" { profit = -profit } +``` + +### HTTP Contracts + +| Method | URL | Request / Response | Expected Behavior | +| - | - | - | - | +| POST | `/trades` | JSON trade payload | Enqueue trade; respond with 200 OK or 400 on errors | +| GET | `/stats/{acc}` | `{"account":"123","trades":37,"profit":1234.56}` | Return current statistics for the given account | +| GET | `/healthz` | plain text OK | Health check endpoint (for Kubernetes liveness probe) | + +### How to Run + +```shell +# Terminal 1 +go run ./cmd/server.go --db data.db --listen 8080 + +# Terminal 2 +go run ./cmd/worker.go --db data.db --poll 100ms +``` + +Sample request: + +``` +curl -X POST http://localhost:8080/trades \ + -H 'Content-Type: application/json' \ + -d '{"account":"123","symbol":"EURUSD","volume":1.0, + "open":1.1000,"close":1.1050,"side":"buy"}' + +curl http://localhost:8080/stats/123 +# {"account":"123","trades":1,"profit":500.0} +``` + +## What We Expect from Your Code + +| Requirement | Minimum / Bonus | +| - | - | +| Go 1.22+, only stdlib + light libs | sqlx / chi / validator OK | +| `go vet` and `go test -race` pass | required | +| Test coverage | ≥ 60% | +| Dockerfile + docker-compose.yml | bonus (+1) | +| README: how to run + curl examples | required | + +## How We Will Evaluate + +CI script (GitLab CI) will: + +- Run `go vet` and `go test -race -covermode=atomic`. +- Launch both API and worker processes in the background. +- Send one invalid and one valid POST request. +- Fetch and validate the response from `/stats`.