I have done commercial web development since 2019. Now I build web products end to end and work on existing systems. The public projects below cover APIs, online booking and subscription billing, integrations, Telegram bots and Mini Apps, and LLM features.
Open to contract work: a fixed-price project, hourly or monthly work, a seat on your team, or taking over an existing codebase. Telegram @sinnercode · portfolio
Recorded from the Pulse demo on GitHub Pages. The traffic is synthetic.
2025 – now · Senior Full-Stack Developer · Independent / Contract
Full-cycle web products and work on existing systems: architecture, dashboards and admin panels, APIs and integrations, optimizing queries, job queues and large imports, CI/CD, monitoring, backup and restore, code review, refactoring and releases.
2023 – 2025 · Full-Stack Developer · Independent projects and contracts
Services with subscriptions, payments and automation: a SaaS for links and contacts, a Telegram sales platform with automatic delivery of digital goods, a website analytics service. I designed the API and database, built the UI, deployed and supported them. Next.js, TypeScript, Node.js, Python, PostgreSQL, Redis, Nginx.
2021 – 2023 · Full-Stack Developer · Contract development
Internal web apps for sales departments and service companies: a CRM for handling requests, a document portal with approvals, supplier catalog sync with price and stock updates. React, TypeScript, Node.js, PostgreSQL, Redis, Docker.
2019 – 2021 · Web Developer · Freelance
Websites and online stores for small businesses: an auto parts store with CSV import, a site for a chain of repair shops with a cost calculator and requests sent to a CRM, WordPress sites with custom themes. JavaScript, PHP, WordPress, MySQL.
The commercial code from this work is private, so the public repositories below are standalone projects built on made-up data.
The demos run on GitHub Pages without a backend. The API is replaced by code in the browser.
Pulse · TypeScript, Fastify, SQLite, React · demo · write-up
Cookieless web analytics with uptime monitoring. Each rollup row stores a HyperLogLog sketch: an exact set up to 512 hashes, then 2048 registers. That is how unique visitors are merged across time buckets.
Ledgerline · TypeScript, Fastify, PostgreSQL, React · demo · write-up
Subscription billing with trials, proration, gapless invoice numbers, dunning and a double-entry ledger. A constraint trigger deferred to COMMIT rejects any journal transaction whose entries do not sum to zero, whatever code wrote it. The demo runs the same engine in the browser, with a test clock that moves a day, a week or a month at a time.
Slotbook · Go, PostgreSQL, React · demo · write-up
Online booking for salons, with a booking widget and a staff day view. Double booking is ruled out by one EXCLUDE USING gist constraint, not by a check in Go: when 20 goroutines hold the same slot, exactly one succeeds. 23 JSON vectors pin how slots behave across DST changes, and both the Go generator and its TypeScript port pass them.
Relay · Python, FastAPI, Redis, SQLite, React · demo · write-up
Takes webhooks from Tilda, amoCRM and Bitrix24 and delivers them to Telegram, Google Sheets, amoCRM and email. The Redis queue is built on sorted sets: a worker claims a job with a lease (120 seconds by default) in one Lua script, and if the worker dies, the job goes back to the queue when the lease runs out.
DocMind · Python, FastAPI, pgvector, React · demo · write-up
Answers questions over PDF, DOCX, HTML files and web pages with citations, and has a Telegram bot. Sources go out over SSE before the model is called, so each [n] is clickable as soon as it streams in. The demo has no LLM: it searches with BM25 in the browser.
Zernolist · React, aiogram 3, FastAPI, SQLAlchemy · demo · write-up
A coffee and tea shop inside Telegram, with payment in Stars or on receipt. The server prices every order from the catalog and ignores client prices: a test sends price: 1 and still gets the catalog subtotal.
FlowDesk · Next.js, Fastify, Prisma, PostgreSQL · demo · write-up
A CRM with a deals kanban and roles. Refresh tokens rotate, and a reused one revokes every token from that login. A conditional updateMany inside a transaction stops two concurrent refreshes from both getting a new pair.
n8n-home-ai-workflows · n8n, Ollama, Qdrant, Docker Compose
Four workflows: meeting notes to Notion via Claude, a family calendar digest, document Q&A on local models, an error handler. Code-node logic is built from ES modules, and the tests run the jsCode stored in the workflow JSON. No live demo, and I haven't run the workflows against live Anthropic, Notion, Google or Telegram accounts.
Smaller demos are in portfolio: a landing page with a cost calculator, an async scraper, a lead-collection bot and an Excel dashboard.
Write-ups on how specific parts of these projects work. Each one quotes the code, links to the lines at a pinned commit, then says what the tests cover and where the code is still thin. Index: notes/.
- The trial balance was zero and the invoice was written off twice: a retry loop working from stale invoice copies, and the invariants that catch what the trial balance cannot
- Two tabs, one slot: letting PostgreSQL refuse the second booking: a check in Go that gave one slot to 14 of 20 requests, and the retry that stopped a deadlock from turning a
409into a500 - Berlin on 29 March: booking slots across a DST change without adding 24 hours: dates walked on UTC midnights, and 23 vectors shared by Go and TypeScript
- The late ack was the small bug: fencing a Redis queue with the lease deadline: part 2, where the fencing token turns up a worse bug
- My Redis queue claimed jobs atomically and still handed the same job to two workers: two races, a test that forces them on every run, and the fix
- Relay's delivery queue on two Redis sorted sets with a 120-second lease
- How FlowDesk rotates refresh tokens with a conditional UPDATE and a cross-tab lock
- How Zernolist prices an order on the server and accepts each Telegram Stars charge once
- How DocMind sends sources before the first token and links [n] markers mid-stream
- How Pulse counts unique visitors with a daily salt and a sparse-to-dense HyperLogLog
Bugs I found in my own projects, each fixed with a test that failed first:
- Relay: a connection error or timeout on the amoCRM note, the request that follows the lead, made the worker retry the delivery and create the lead a second time; any failure of the note now goes into the delivery's result, and the note gives up before the attempt's timeout (
fb4dbe9) - Slotbook: two writes on one period at the same moment could deadlock inside PostgreSQL's exclusion-constraint check, and the request whose transaction the deadlock detector aborted got
500: a loser instead of409 slot_taken, a confirmation instead of going through; holds, blocks, reschedules and confirmations now run the transaction again on40P01(54ccd48,939022a; see the write-up) - Ledgerline: when a failed retry ended dunning inside the retry loop, every open invoice was written off, and the loop's stale copy of the next one reopened it, recorded another payment attempt and wrote it off a second time; the trial balance stayed at zero (
b8aabf0; see the write-up) - Slotbook: the notification worker sent a claimed batch one row at a time under one lease, so with slow sends a row late in the batch could be reclaimed by another worker and sent by both; each row's lease is now renewed right before its send (
a38902f) - Relay: two claim races with several workers on one Redis, then a stale worker overwriting the new owner's record (
b0ae35c,8c6ccb4; see the two Relay notes above) - Relay: an event stored but never queued when enqueue fails (issue #1,
c845ca0) - DocMind:
docmind askfinding nothing afterdocmind ingestwith default settings, and[0]turning into a citation (issue #1,d89f9ea) - Home AI flows: the doc-QA chunker dropping the start of a long paragraph with no whitespace, so the document was embedded from a fragment (issue #1, #2)
- Relay: a request longer than the lease could be sent twice; the lease is now renewed while the connector runs (
c4be59c) - FlowDesk: a published fallback JWT secret accepted in production, a login limit bypassed with
X-Forwarded-For, and refresh tokens that were never deleted (4770f75,af961e9) - Pulse: live ranges dropping the current minute, hour or day, and uptime monitors probed every 5 minutes whatever their interval (
b6a0fa4,83ce266) - Zernolist: two payments, or a payment and a cancel, racing on one order on SQLite (
fa866de)
Telegram @sinnercode · portfolio
Коммерческая веб-разработка с 2019 года. Сейчас занимаюсь разработкой веб-продуктов полного цикла и развитием существующих систем. В открытых проектах выше — API, онлайн-запись и биллинг подписок, интеграции, Telegram-боты и Mini Apps, функции на LLM. Беру проекты с фиксированной ценой, почасовую и помесячную работу, могу войти в вашу команду или разобраться в чужом коде.
- 2025 — сейчас. Senior Full-Stack Developer, independent / contract. Полный цикл разработки веб-продуктов и развитие существующих систем.
- 2023–2025. Full-Stack Developer, независимые проекты и контракты. Сервисы с подписками, платёжными интеграциями и автоматизацией.
- 2021–2023. Full-Stack Developer, контрактная разработка. Внутренние веб-приложения для отделов продаж и сервисных компаний.
- 2019–2021. Web Developer, фриланс. Сайты и интернет-магазины для малого бизнеса.
Коммерческий код из этой работы закрыт, поэтому открытые репозитории выше — самостоятельные проекты на выдуманных данных. README у них на английском; у всех, кроме Relay, есть русская версия или короткий пересказ по-русски.
Ошибки, которые я нашёл у себя и исправил, каждую с тестом, который сначала падал, перечислены выше в разделе Recently fixed.
Разборы того, как устроены отдельные части проектов, с кодом и ссылками на строки:
- Оборотная ведомость сходилась в ноль, а счёт списали дважды: цикл повторов на устаревших копиях счетов и инварианты, которые видят то, чего не видит оборотная ведомость
- Две вкладки, один слот: вторую запись отклоняет сам PostgreSQL: проверка на Go, которая отдала один слот 14 запросам из 20, и повтор транзакции, после которого дедлок больше не превращает
409в500 - Берлин, 29 марта: слоты записи при переводе часов без прибавления 24 часов: даты по полуночам UTC и 23 вектора, общие для Go и TypeScript
- Поздний ack оказался мелочью: fencing token из срока аренды в очереди на Redis: вторая часть, где fencing token вскрывает ошибку посерьёзнее
- Очередь на Redis атомарно забирала задачи и всё равно отдавала одну и ту же двум воркерам: две гонки, тест, который ловит их при каждом запуске, и исправление
- Очередь доставок Relay на двух sorted set в Redis с арендой задачи на 120 секунд
- Ротация refresh-токенов в FlowDesk через условный UPDATE и блокировку между вкладками
- Как Zernolist считает цену заказа на сервере и принимает каждый платёж в Telegram Stars один раз
- Как DocMind отдаёт источники раньше первого токена и превращает [n] в ссылки на лету
- Как Pulse считает посетителей через суточную соль и HyperLogLog
Написать: Telegram @sinnercode, портфолио.



![DocMind demo: a question, the answer streaming with [1] and [2], and the matching source cards highlighted](/sinnercode228/sinnercode228/raw/main/assets/docmind-answer.webp)