CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
Notable changes to Sage. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the versions follow
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Sage was developed in private and its history was rewritten before publication,
so there is no commit-by-commit record from before this release. The log starts
here.
## [Unreleased]
### Changed
- Company logos and news thumbnails are now per-user switches in
Settings → Privacy, off for every account. If you built with
`NEXT_PUBLIC_LOGO_DEV_TOKEN`, logos will show initials after upgrading
until each user turns them on; the variable now only supplies a default key.
### Removed
- `NEXT_PUBLIC_NEWS_THUMBNAILS`. Remove it from `.env`; thumbnails are the
"News thumbnails" switch in Settings → Privacy.
## [1.0.0-beta.2] - 2026-09-16
A walkthrough of a clean install, and a second pass over the numbers against a
real book. If you installed beta.1, this is the release to be on.
### Your first import
- A freshly imported book shows the dividends it has received straight away.
Before, the first page you opened spent the once-a-day dividend
reconciliation on an empty book, so an import showed almost no received
income for a day, and the overview printed a full forward year against that
as growth.
- The first import sets your display currency to the one most of your book is
in, and says so. A mixed-currency book with none set used to disagree with
itself: one page guessed USD, others showed dashes.
- New holdings say "Fetching prices" while their first prices arrive, instead
of announcing that prices are unavailable.
- Sector and country data heal on their own. A profile that failed to load at
import, or has gone a week without refreshing, is fetched again in the
background, so an `Unknown` slice no longer stays forever.
- A broker's interest row now replaces the payment Sage generated for the same
custom holding and date, instead of landing next to it and counting twice.
### The front page leads with income
- The overview opens with what the book will pay over the next twelve months,
and every payment it has received or expects on one axis: paid, confirmed and
estimated, fading as it moves into the future. Portfolio value moved below it.
- The monthly rhythm is a ring against an even-year reference, so a lumpy year
is something you see.
### Numbers
- Benchmarks are total-return indexes. Comparing a portfolio that includes
dividends against price-only indexes flattered every book: by 1.4 percentage
points against the S&P 500 over the year it was measured.
- Trading fees are part of cost basis. They were recorded and never used.
- Realised gains from sales are computed, and total return covers the whole
life of the book, not only what is still held.
- A reconciled dividend carries withholding tax like an imported one.
- A settled close beats an intraday print from the same session, so the total
stops moving while the market is shut.
- A chart window no longer opens on a day nothing traded, which had left most
holdings unpriced on its first point for YTD and 3M.
- A holding whose price history stopped is still counted, at its last price,
and the page names it and the date. The notice now says when only the chart
history is old and today's value uses a current price.
- Gains read in both money and percent.
### Removed
- The money-weighted return. Its arithmetic was right, but without a cash
account it reads moving money between holdings as withdrawals and deposits,
which can put it far from the time-weighted return for no real reason. It can
come back if Sage gets a cash model.
### Smaller
- Diversification opens with funds x-rayed into their sectors.
- An invalid query parameter is a 400 error, not a 500.
- Labels on Diversification are no longer clipped to a few characters.
## [1.0.0-beta.1] - 2026-09-10
First public release.
### Portfolio and holdings
- One row per position with daily change, total return, weight and yield,
sortable in place.
- Custom holdings for instruments no provider covers, priced by you, so a book
with something unlisted in it still adds up.
- A page per instrument: price history, your position in it, profile,
fundamentals, dividend history, news and analyst ratings.
### Dividends
- A calendar showing one year at a time, with received and predicted payments in
the same grid. Payment certainty is encoded in three tones - paid, confirmed,
estimated - and a date Sage predicted rather than the company declaring is
marked separately from an amount Sage forecast.
- Analytics: forward twelve-month run rate, per-payer and per-month breakdowns,
income by year, and dividend growth rates.
- Positions you have since sold stay in the history, because income you actually
received should not disappear because you exited.
- A total that would span more than one currency renders as a dash rather than a
figure that is wrong in every currency you might read it as.
### Performance
- Time-weighted return chained daily over the range you pick, annualized past a
year, beside a money-weighted XIRR.
- Volatility, beta, maximum drawdown, best and worst day, and benchmark lines.
- A reconciliation banner when stored price history disagrees with your own
transactions, naming the holdings and adjusting nothing.
### Diversification and categories
- Weights by sector, country, region, asset class and currency, on market value
or on what you paid.
- An X-Ray toggle that looks through funds and ETFs to their underlying
holdings instead of counting each fund as one line.
- Anything Sage cannot classify goes to an `Unknown` bucket in plain sight
rather than being spread across the ones it can.
### Getting your book in
- A forgiving CSV importer: it guesses the columns, shows you the parsed rows
before committing, and lists what it could not read with a reason. Reads
`$1,241.30`, `1.241,30`, `1 241,30` and `1'241.30` as the same number, and
flags ambiguous dates rather than guessing.
- Broker transaction words are mapped, with anything left over offered as a
dropdown rather than a file to go and edit.
- Re-importing an overlapping file is safe: every row carries a hash and the
ones already recorded are recognised as duplicates.
- A dedicated Snowball Analytics reader, and single-holding entry for a handful
of positions.
### Corporate actions
- A read-only audit trail of what Sage did with splits and what it declined to
do, printing its own coverage so a cold price store cannot read as confidence.
### Privacy and self-hosting
- Web app, API and Postgres come up together under one `docker compose up`.
There is no Sage server.
- Company logos and news thumbnails are off by default, because both would name
what you hold to a third party. With both unset, nothing does.
- Prices and ECB reference rates are stored in your own database as they arrive,
so a provider outage leaves you with the last known values and a notice rather
than an empty app.
- Export your transactions as CSV or everything as JSON at any time, with no
provider calls involved.
- Account recovery from a shell (`sage reset-password`), because Sage sends no
email.
### Known limitations
- **Market data is not licensed.** The default price source is an unofficial
Yahoo client: broad coverage, no key, and it can break without warning - it
did on 2026-08-09. Official providers are supported, but their free tiers are
small enough that most setups still fall back.
See [`docs/MARKET-DATA.md`](./docs/MARKET-DATA.md).
- Sage has no tax-residency model. One dividend tax rate applies to every
holding.
- There is no offline cache in the installable phone app, deliberately: stale
figures are worse than none in an app whose value is that its numbers are
current.
- Sage records and measures; it does not advise. See
[`docs/DISCLAIMER.md`](./docs/DISCLAIMER.md).
[1.0.0-beta.2]: https://github.com/bjarkeef/sage/releases/tag/v1.0.0-beta.2
[1.0.0-beta.1]: https://github.com/bjarkeef/sage/releases/tag/v1.0.0-beta.1