Full-stack · Cloud AI
Zenfolio
A unified portfolio dashboard across trading platforms — upload a screenshot of your trading history and an AI parser turns it into structured buy, sell and dividend records.
- 3
- Services
- Go
- Backend language
Overview
Anyone holding stocks across more than one broker has the same problem: each platform shows you its own slice, and none of them show you the whole position. Zenfolio pulls those slices into one dashboard — total assets, realised and unrealised return, annualised rate via XIRR, and gain/loss broken down per holding.
The awkward part is getting the data in. Brokers export inconsistently and many don’t export usefully at all, so Zenfolio takes the path users actually have available: upload a screenshot of your trading history and let the system read it.
My Role
Solo — the React client, both Go services, the data model, and the container setup.
Architecture
Three containerised services behind Docker Compose.
The React client (Vite, Redux Toolkit, shadcn/ui, with components developed in Storybook) talks to a single REST API.
The core API in Go and Gin handles transactions, portfolio state, chart metrics and
authentication, persisting through GORM to MySQL. It is also where screenshot parsing
lives: uploaded images go to Gemini 2.5 Flash behind a small ModelType abstraction, so
the model is a swappable implementation rather than something welded into the handlers.
The price service is a separate Go microservice. It owns all contact with the external stock-price API and fronts it with a Redis cache, which is the reason it is separate at all — price data is shared across every user and every holding, changes on its own schedule, and is rate-limited upstream. Caching it inside the core API would have meant coupling portfolio logic to somebody else’s quota.
Choosing Go here was partly deliberate range: the other backends in this portfolio are Node and Python, and I wanted the concurrency model and deployment story of a compiled service to be something I had actually shipped rather than read about.