Skip to content
← All work

Tong Yulduzi

A national children's and teenagers' newspaper moved its print operation online. I took it from an empty database to a live product, then handed it to the editorial team who run it on their own now.

The Tong Yulduzi home page: a lead story with photograph, a most-read sidebar, and the latest-news feed below it.

The situation

Tong Yulduzi is a republic-level newspaper for children and teenagers in Uzbekistan. The paper itself keeps coming out on paper. What did not exist was the online half: somewhere for readers to find articles, somewhere for the archive of published issues to live, and somewhere for journalists to actually work.

So the job was two products sharing one database. A public site that has to be fast and stay up, and an editorial tool where a newsroom writes, edits, schedules and publishes. I built both, plus the deployment underneath them.

The schema

The backend is FastAPI over PostgreSQL, with SQLAlchemy models and Alembic migrations. The schema carries news, categories, users, media, galleries, tags and newspaper issues, with the join tables that let one article hold many images and many tags.

A few decisions that mattered more than the rest:

  • Article bodies are stored as JSONB, not HTML. Structured content survives a
  • Issues are first-class. A printed newspaper has editions, so the archive
  • Roles are narrow. Writer, editor and admin, because that is what the

Search across the archive

Readers look for an article they half remember. That is a full-text problem, and I kept it inside PostgreSQL rather than adding a search server the client would have to pay for and maintain.

tsvector columns with GIN indexes, ranked with ts_rank. The tuning was the real work: I watched what editors and readers were typing and adjusted the weighting until the article people wanted came up first, instead of simply the newest one.

Making it fast, with numbers

Page loads were slower than they should have been. Two causes, handled separately:

  • The most-read pages were recomputing the same result for every visitor. Those
  • Several queries were missing indexes and doing sequential scans.

I measured timings before and after each change rather than shipping both at once and assuming. If you change two things and it gets faster, you have learned nothing about which one helped.

The front end

Both surfaces are Next.js and TypeScript, built from the agreed designs and matched closely on spacing, type and colour.

The part that shaped most of the work: almost all of the readership arrives on a phone. So the reader site was built for a small screen first and the editorial tool had to stay usable on one too, because journalists file from wherever they happen to be.

Deployment, and the boring parts that matter

CI runs pytest against a throwaway database, builds the Docker images, and deploys. If the health check fails after a deploy, it rolls back to the previous image automatically, so readers never see the site go down.

Backups run nightly, encrypted, stored away from the server. More importantly, I ran a full restore rehearsal into a clean environment. A backup you have never restored is a hypothesis, not a backup, and this archive is a newspaper's history.

The whole thing runs as one Docker Compose stack behind Nginx on a single small VPS. A newspaper's budget is not a startup's, and the architecture reflects that on purpose.

The repository is private, since it belongs to the client. The site is public.