asifmk/CHANGELOG.md
Changelog

How ReturnKoto? works

Founder · Feb 2026 to present · returnkoto.com, release 2026.02

ReturnKoto? answers one question for people in Bangladesh: if I had put this amount into this mutual fund, what would it be worth today? Type an amount and a period, and it replays that investment over the fund's real price history, with every dividend counted. It is free, has no ads, and the amount you type never leaves your browser.

I started it in February 2026 because no site in Bangladesh showed a retail investor what a fund had actually returned once dividends were counted. I designed it, wrote the data rules, and built and shipped every page myself with Claude Code and Cursor. This page is for a hiring manager who wants to know how deep it goes.

The site in numbers

Public pages
169 in the sitemap, most of them written by the build
Funds tracked
38 open-end funds: 20 growth, 11 balanced, 7 income
Fund managers
10, each read by its own parser
AMC-Verified
14 of 38, each checked with its asset manager before the badge went up
Shariah-compliant
8 of the 38, filterable across the site
Longest history
15.5 years of monthly NAVs
Homepage counter
"Join 5,590+ people using it", as the site words it
Build code
About 11,000 lines across the 12 main build scripts, before the site's own HTML, CSS, and JavaScript
Commits
About 1,080 since early August 2026 across the site and build repos: roughly 300 by hand, the rest by the scheduled data job

The figures above the build code are read from returnkoto.com's public data files by a daily job, which keeps the last good set if a check fails. They last changed on 25 Oct 2026. Build code and commits were counted from the two private repositories on 25 Oct 2026; history before August was purged on purpose while the site is in beta.

Every page, and what it is for

Homepage
Three layers. First an empty amount field and one button. Then the answer: the best result across all funds, with the middle and lowest results directly under it. Then, only on request, the full set of charts, filters, and fund lists.
38 fund pages
Each opens with "BDT 1,00,000 invested 3 years ago is X today", then a trust ledger for prices, dividends, and fund manager review, the fund's rank among peers of the same type, its full dividend record, costs, and verified holdings.
Compare, plus 90 pair pages
Two or three funds side by side on returns, fees, exit loads, risk, and what they hold. 90 fund pairs also get a page of their own, so a search for "fund A vs fund B" lands on an answer.
Holdings and stocks
Every fund's portfolio from its manager's statement, reconciled to the taka. When a new statement arrives, a card shows what changed since the last one. A stocks page counts which shares the funds hold most.
Blog, 22 posts
14 explainers with interactive charts, and 8 weekly data reports the build writes itself from frozen snapshots, so a report never changes after it is published.
Learn, FAQ, guides
Plain-language explanations, a searchable FAQ, and three long guides. Every FAQ answer also ships as FAQPage structured data for search engines and AI answers.
Methodology
The full calculation and rating method, written so anyone can redo a figure by hand.
Status page
Hosted on a separate provider, so it stays up when the site is down. A status light in every page footer reads from it.
404 page
Suggests the closest real page and has instant search, from a list of every page the build writes.

The rule: right or withheld

A published figure is either right or not shown. When sources disagree, the code does not pick one. Drift detection stops a bad sync before it reaches a fund page, and anything short of fully confirmed is labelled instead of hidden:

  1. AMC-Verified: Shown only after the asset manager and ReturnKoto? went through the fund's figures together and agreed on what appears.
  2. Partial: Some dividend records are missing, so the total return may be understated. The page says so.
  3. Estimated: A figure is modelled, and labelled as modelled.
  4. Withheld: Two sources disagree on a figure. It stays off the page.

AI made the build fast. The rules are what make the output trustworthy, and they are product decisions, not model behaviour. That split is how I would run AI features on any team.

How the data moves

A scheduled GitHub Actions job runs the whole chain. Nobody types a number between a fund manager's website and the page.

  1. Collect: One parser per fund manager. Between them they read server-rendered tables, a public CMS API, a JSON feed found behind a JavaScript-rendered page, and the backend API of a Next.js site. When a page holds several tables, the parser keeps the newest date, never the first match.
  2. Validate: A new price is accepted only if it is dated on or after the end of the series and sits within 15% of the secondary series. A one-day jump above 8% that fully reverses on the next price is dropped as a spike. A manager's site that goes 45 days without a new price gets its funds tagged as outdated.
  3. Fold in: The validated price joins the fund's return series, so every figure on the site is recalculated, not only the latest price on display.
  4. Archive: Every price collected goes into a private archive. That archive is becoming ReturnKoto?'s own history: once a fund's archive overlaps the secondary series for long enough, that fund can drop the secondary source.
  5. Compute: Total returns for lump sums and monthly SIPs, with dividends reinvested by default or taken as cash. The homepage date is the newest date every fund has, so one late fund holds the date back instead of hiding behind the others.
  6. Build: Python generators write the fund pages, pair pages, weekly reports, share images, sitemap, and llms.txt from the computed data.
  7. Publish: The job commits, rebases, and pushes. Cloudflare Pages deploys, and the edge cache for the data files is purged.
  8. Watch: Keyword monitors check the homepage, fund pages, compare tool, and data file every 3 minutes. A heartbeat alerts me if the data job stops running.

How a return is computed

  1. Each fund keeps one real NAV per month, the latest published price in that month, from launch to today. For funds with a full daily history, lump-sum look-back windows anchor on real calendar dates instead.

  2. A lump sum buys units once at the starting NAV. A monthly SIP buys units every month at that month's NAV.

  3. Cash dividends are reinvested in the payout season at that month's NAV, or kept in a separate cash pile if you choose cash. Stock dividends and unit conversions apply on their effective dates.

  4. Final value is units times the newest NAV, plus any cash. Lump sums annualize with CAGR, SIPs with IRR. Published NAVs are already net of fees.

The FAQ walks one example by hand, and its arithmetic matches the engine exactly: BDT 1,00,000 buys 10,000 units at NAV 10. A BDT 1 dividend per unit is reinvested at NAV 11, which adds 909.09 units. At NAV 12 the holding is worth BDT 1,30,909, a 30.9% total return.

When the data was wrong, and what changed

  1. Fixed: A parser read a frozen legacy table that sat above the live one on a manager's page, and the site briefly flagged that manager as not updating. I caught it within hours. Parsers now keep the newest row they find, and no public claim about a third party goes out until it is checked in a real browser.
  2. Fixed: A fund manager reported our numbers as wrong. The audit found month-end dividends falling outside the look-back window. After the fix, the manager's own published returns reproduce to within 0.01 percentage points.
  3. Fixed: An audit in July found the edge cache serving weeks-old HTML at the canonical addresses. HTML is no longer cached at the edge, and the data files are purged after every publish.
  4. Removed: Removed every fund manager whose published prices are not market prices. A smaller roster I can defend beats a longer one I cannot.
  5. Changed: Screened about 52 untracked funds. About 31 passed the automated checks, and none was listed until its manager's own records were checked as well.

Built for a phone

More than 90% of visitors are on phones, so every change is checked at 390 pixels wide before it ships. Touch targets are at least 44 pixels, text contrast is held to WCAG AA, motion stops for anyone whose device asks for reduced motion, and terms a beginner might not know, such as SIP, NAV, and annualized, open a short explanation on tap.

Some choices are about fairness, not polish. Fund groups, the funds directory, the first pair in the compare tool, and the lead blog post are shuffled on every visit, so no fund or manager gets a permanent spotlight. Star ratings live on one page and in a collapsed panel, labelled experimental, until the method has more verification behind it.

Settings sit in the address bar, so a result can be shared, but the amount is never sent to analytics. The site uses one self-hosted typeface at 18.7 KB, plus a 1.1 KB font that holds a single character: the taka sign, which the main typeface lacks.

Search and AI answers

Page titles stay under 60 characters and descriptions under 155. Addresses have no file extensions. The site publishes an llms.txt and deliberately lets AI crawlers in, because being cited in AI answers is part of the plan. The site-wide share image carries no figures, since Facebook and WhatsApp keep the first copy they fetch and a number on it would go stale. Each fund page gets its own dated share card instead.

Working with the fund managers

Each asset manager can get a password-protected preview copy of the site, served by a Cloudflare Worker behind a firewall rule, to review its funds before anything reaches production. The AMC-Verified badge goes up only after that sign-off. When a manager shares audited statements, the audited expense ratio appears beside the prospectus fee instead of replacing it.

The partner page states the commercial line in writing: a partner may pay a referral fee, and can never pay for rankings, returns, badges, homepage order, or a place on the roster.

How I run it with AI

Claude Code and Cursor do the building. Both start from the same written context: a project memory file of about 860 lines of rules and dated owner decisions, a design system file, and three Cursor rule files that every edit follows: mobile first, randomized order stays, and every holdings update carries cost data.

When work moves from one tool to another, I write a handoff: what exists, the hard rules, and what comes next. Every audit, from the homepage UX review to the FAQ and the source-of-truth check, starts as a document, and its fixes ship as a dated entry in a change log. My writing-standard skill checks every page and post before it goes out.

The AI writes the code. I make the calls it cannot: which funds are trustworthy enough to list, what a figure must pass before it shows, and what stays private.

What is next

Move each fund to data from its own manager only, once the private archive overlaps the secondary series. Bring more managers through verification. Then leave beta, and publish the change log that is kept privately today.

Try the calculator on returnkoto.com