Skip to content
Sami Aktaş

Ledger № 65 · September 22, 2026

TR

The full ledger

Build Journal

65 entries, grouped by venture — every line a real date, a real progress note.

35

Payda

35 entries

Esnaf modu gitti, kişisel panel geldi

Bugün Payda'yı sadeleştirdim: esnaf modunu ve ona bağlı tahsilat, veresiye, üyelik, e-ticaret gibi yan sistemleri önce yedekleyip sildim, yalnız yüzdelik sistem kaldı. Ardından herkesin kendi adını ve fotoğrafını her projede aynı gösterebildiği bir Profilim alanı ekledim. Üstüne YouTube, Instagram, TikTok, Threads ve X için günden güne takip kurdum; artık tek satırda 'bugün toplam kaç beğeni, kaç yorum aldın' görünüyor. Hepsi yine tek Claude üyeliğiyle, testleri yeşil geçerek canlıya çıktı.

Kopilot tek akışa indi, sami skill denetiminden geçti

Kopilot sayfası iki paralel akış taşıyordu; tek kutu, tek gönder tuşu, tek sonuç kartına indirdim ve 12 uzman modlu denetimin bulduğu 20'den fazla açığı (idem anahtarı, metin kaybı, kaydırma, balon-kasa örtüşmesi, uzun sohbette hükmün kaçması) dört turda kapattım. Her tur 13 kapı ve tarayıcı testinden geçti, canlıya çıktı. Hepsi tek Claude Pro üyeliğiyle, kanıtsız tek satır iddia yok.

Numaranın yanına tutar, kartın üstüne 'Şimdi ne oldu?', sohbetten fiyat listesi ve banka kendiliğinden doluyor

Sami'nin üç isteğini tek akışa bağladım: ayrı 'Gelir ekle' tuşu kalktı, müşteri numarasının yanında tutar var; müşteri bulununca kartın en üstünde 'Şimdi ne oldu?' — satış olduysa geliri kaydet, olmadıysa almadı notu — önceki kayıtlar altta. En keyiflisi: yapıştırılan sohbette hangi hazır metin (fiyat listesi, IBAN) geçiyorsa fiyat listesi ve banka alanı kendiliğinden doluyor, yapay zekâ çağrısı yok, ücretsiz. Kural gevşemedi: eşleşme yoksa soru yine sorulur, elle seçim ezilmez. 16 yeni test, 320px'te taşma sıfır, hepsi Claude ile.

Tasarımı canlıya birebir taşıdım: sol menü, tek sütun Özet, Ayarlar grupları

Claude Design'da çizdiğim yenileme canlıda yarım kalmıştı; bugün planı adım adım uyguladım: masaüstünde sol menü ve sayfa başlığı, Özet'te KPI şeridi ile yan yana Kasa ve Ödenecekler, Defter'e tür seçicili Kayıtlar tablosu, Ekip'e hakediş tablosu, Ayarlar'a sol grup listesi. Her parça 13 test kapısından ve parolasız ekran ölçümünden (320px'ten 1280px'e taşma sıfır) geçti. Bir dağıtımı kendim durdurdum — testler koşarken bir belge düzenledim, deploy.sh yakaladı — ve temiz ağaçla yeniden çıkardım. Hepsi Claude ile.

Super-app research: Payda is a very good ledger, but still a ledger

The system has settled, so today I wrote no code at all — I spent it researching the "super app" idea. First I took stock of what exists: 29 endpoints, 8 collections, 1,400 checks; the money side (four-eyes approval, exchange rates sealed at transaction time, partner current account, period close, audit trail) is genuinely solid. But the one-sentence truth is this: every number in Payda is a hand-typed record of something that happened somewhere else — the sale happens elsewhere, the ad spend happens elsewhere, the money lands elsewhere. Measured against the three pillars of the super-app pattern, identity came out strong, payments exist only as bookkeeping, and a mini-app platform is unnecessary at this scale; in my context "super app" means moving from ledger to workbench. I listed five candidate directions — a conversation layer, bank statement matching, an intelligence layer that finally asks questions of the data we already collect, an installable app with real notifications for employees, and multi-team support — and left myself three questions to answer before choosing.

Product Strategy · Research · Super App · Roadmap

A deactivate button shipped, and two test gates turned out to be blind

A short four-item run: a deactivate button on the member card (same button for a suspension or a holiday — a deactivated member can't see the project in their list or write any data, but their earnings and history stay, and I can still pay them while they're inactive), the ability to change an employee's ad-account assignment after the invite, a "spent to date" line on ad-account cards, and manual payment entry closed for good — payment records are now produced only by the system's own flows. The auditor caught a false promise in the confirmation text: it said "a deactivated member cannot log in", but the account isn't closed at all, only project access drops; the wording was pulled back to the truth and the test now also measures the absence of that false promise. The real find of the run was that two gates were blind — yesterday's parity gate couldn't detect a stale exception, and the template-binding gate had never checked the row properties of 16 nested lists; coverage went from 75 blocks to 87. All nine mutations broke the gates by name; commit aa18bb2, 1,400 checks green.

Member Management · Ad Accounts · Test Gates · Emulator Testing · Cloud Functions

Is everything in the backend reachable from the UI? A parity gate plus a dead-code sweep

I turned the question "is everything the backend can do reachable from the frontend?" into a two-way audit: every endpoint, every single op of the multi-op endpoints, and every field the server writes went through one filter — can a user actually reach this? At endpoint level all 26 callables were wired, but at sub-op level five real gaps showed up: an ad account's name and warning threshold couldn't be changed after setup, a mistyped reminder couldn't be deleted, and the endpoint that renames a category while carrying old sales along could never be triggered. I wired all of them. On the dead-code side every deletion came with grep proof (the rotationQueue leftover from the old shift model, the lastProduct field that was written but never read, dead CSS and state), and an independent auditor agent spot-checked both the deletions and the things claimed to be in use. The lasting win isn't the one-off cleanup: the rule "every endpoint is either called from the UI or a justified exception" is now enforced by a test — we sabotaged the gate three ways and it named the culprit all three times. The same run added an optional short note to sales entry, visible on the purchase line of the customer card and never written when left blank; commit 85bfb79, 1,322 checks green.

Dead Code Removal · Parity Gate · Cloud Functions · Code Audit · Testing

Manual shift ordering, the 40-day due-date bug, and split customer records

The five-item run that started last night went live this morning. Every row in the shift list now has ↑/↓ arrows — I can order the rotation by hand, and moving someone doesn't change their working hour, only the rotation sequence. The "40 days" due-date bug I'd spotted was real and deeper than I thought: the formula skipped the template's first unpaid month, and pressing Pay got rejected by the server with "this month is already paid"; the corrected rule was written identically on both server and client, and across a 1,344-combination grid test the rejection window is zero. Customer records weren't disappearing either — they were splitting: the same number landed in separate documents as "0555…", "+90 555…" and so on; the server now reduces every spelling to one canonical key, and all 121 live customer records were migrated copy-verify-delete with zero loss. The group-remainder pie chart and the "pay from which group" hint above the payment form shipped in the same deploy; commit fe7122d, 1,212 checks green.

Shift Rotation · Due Date Logic · Data Migration · Firestore · Testing

Radical simplification to match the business model is live

Payda went through its biggest change yet today: everything that didn't fit the business model was deleted, and everything left now follows a single rule. Commission is one model only — a gross percentage of the sale; salary and per-sale models, task assignment, the banker login role and overhead categories were removed entirely. Entering a sale is down to four required fields (account, bank, category, tone), customer records gained number-based blocking, and tasks were replaced by dated reminders tied to an account. The hardest part of deleting wasn't the code, it was the proof: every removed piece was reported with grep evidence that it genuinely wasn't called any more, an independent auditor agent verified it on a random sample, and the test suite was rewritten for the new model — 1140 checks green.

Simplification · Dead Code Removal · Four-Eyes Approval · 1140 Tests

E-mail verification strip and deliverability work

Users signed in with an unverified e-mail now see a security strip in the panel: 'Send verification e-mail' in one click. A closing bug in the quick-action form was fixed too; both verified live. The next job is clear: we started the deliverability (SPF/DKIM) work so our e-mails stop landing in spam.

Email Verification · Security · UX

Live user testing: sign-in and e-mail verification fixed

I walked the site like a real user with a synthetic account: sign up → sign out → sign back in → transact. Everything the test caught was fixed the same day: new members weren't receiving the verification e-mail, unverified sign-up was possible, and sign-in stalled after a password reset — all fixed. In the UI the top-right bell is gone; notifications moved into the Summary (with 'Read' and 'Mark all read'), and the income/expense form now opens in place. The entire 8-item fix list went live.

Firebase Auth · Email Verification · UX

Shift rotation: the +1-hour rolling queue is live

The shift system now rotates the whole team in turn: each cycle the next person's shift slides +1 hour, and who comes when is visible 9 cycles ahead. The panel got an 'on shift now' badge and a rotation tab (current/next person + notifications). We started on the night of the 16th and finished by dawn; all 182 tests green, deployed.

Rotation Queue · Notifications · 182 Tests

A real app bottom sheet: '+' opens the form in place

I fixed a fair criticism: the 'Add' button opened an empty routing screen and everything funneled to the summary — pointless. Now tapping '+' slides up a real transaction form from the bottom, just like phone apps: pick Income/Expense, enter the amount, save — it records instantly and closes, you never leave the screen. In-place, fluid, native-app feel. Centered card on desktop, full width on mobile. 166 tests green, live.

Bottom Sheet · Mobile UX · Tests

Phone-app feel: bottom navigation + big buttons

I gave Payda a real phone-app feel: instead of tabs on top there's now a fixed floating bottom bar — Summary, Ledger, a huge '+' Add in the middle, Team and Settings. Tapping Add shows two giant cards ('What do you want to add?' Income / Expense) that take you to the form in one touch. One-handed thumb use got much easier. On desktop it sits as an elegant floating bar. Verified everything on the emulator, 166 tests green, live.

Bottom Navigation · Mobile UX · Tests

Tabbed panel (button logic) + dead-code cleanup

I split Payda's long-scrolling admin panel into button-style tabs: three big fixed tabs on top (Summary · Ledger · Team & Shifts), each hiding the others — you switch sections without scrolling, and your personal shift/task summary stays on top. Then I cleaned the dead code left over from features I'd removed earlier (bank presets, the banker balance-top-up panel) — 16 unused bindings and 3 dead functions gone; I walked the banker and admin screens live to confirm no white screens or errors. Desktop+mobile, 166 tests green.

Tabbed UI · Refactor · Tests

Visual depth + tactile buttons + a live experience test

This time I tested Payda by actually using it: opened it in the emulator, clicked through every section, opened settings, added income/expense from the UI — everything worked, zero console errors. I also fixed the 'flat' look people complained about: accent lines and layered shadows on KPI boxes, soft depth and hover lift on cards, tactile feel on all buttons (glow on hover, press-in on click), accent dots on section headers. CSS and copy only; business logic untouched, 166 tests green, solid on desktop+mobile.

Design · CSS · Experience Testing

Shift tracking system + currency-drift fix

Today I added shift tracking to Payda: it computes rotating shifts automatically (e.g. start at 12:00, slide +1 hour daily), everyone sees their own and the team's hours, and a red countdown warning appears half an hour before a shift. I also fixed an annoying bug: fixed-expense amounts drifted with the live exchange rate — now the amount stays fixed in the currency you entered. Managers/partners also got a 'what's left in which bank after deductions' view and a field to note which account was tried for a non-buying customer. 166 checks green, verified on desktop and mobile.

Shifts · Currency Pinning · Tests

Banker without e-mail, automatic partner share, bank clutter gone

I simplified Payda further: you can now add a banker with just a name and percentage, no e-mail needed (we only need to know; the invite can come later). Partner share is now automatic from net profit and each partner sees THEIR own percentage — previously the first partner's percentage showed for everyone; fixed. The confusing 'route payment through bank account' preset is fully removed. Canned texts now fill the screen as a grid instead of one narrow column. 162 automated checks green, live.

Simplification · Profit Share · Tests

Dropped the clutter: notes, banker confusion, canned tone

Today I decluttered Payda: removed the 'notes' feature people found pointless; sales/contact tone is now free text instead of fixed soft/neutral/hard choices; recording a negative customer response now also stores 'which bank was shown'; and the banker's confusing 'top up balance / enter expense' panel is gone — expenses are strictly a manager/partner job now. 159 automated checks green, live.

Simplification · UX · Tests

Wider partner approvals, online indicator, security scan

Four jobs in Payda today: (1) searching a customer number now also shows which account paid into which bank. (2) With a partner present, it's no longer just profit share — changing a member's %, removing a member and deleting a project all require the other partner's approval; no one can break the structure alone. (3) Partners see a green dot for who's online. (4) An OWASP Top 10 security scan: access control, XSS, headers, injection — all clean; the two remaining items (2FA, bot protection) will be toggled from the panel. 163 automated checks green, live.

Four-Eyes Approval · OWASP · Tests

Sales tone + picky-customer tracking + broadcast tasks

I grew Payda's mini-CRM today: every sale now records the tone (soft/hard) and method used. More importantly, we can now log customers who DIDN'T buy — 'tried this number from that account with a soft tone, declined'. So when the same picky customer is tried again from another account, their history shows. Also added one-tap task assignment to everyone. 142 automated checks green, live.

Mini-CRM · Tasks · Tests

Permission audit across all roles + 3 fixes

Today I audited Payda end-to-end through the eyes of all five roles (manager, partner, banker, worker, profit-share partner): each role tried to step outside its permissions and the system rejected every attempt. Along the way I found one hole — an unauthorized worker could delete team notes; closed it. I also removed a useless permission flag and narrowed the banker's default permissions to their actual job. The automated security suite grew from 104 to 131 checks, all green, deployed.

Permission Audit · Security · 131 Tests

The panel now runs on the new UI

The biggest piece of Phase 2 landed: the admin panel now runs on the new React UI — KPIs, period and currency switches, countdown-based upcoming payments, quick income/expense, the ledger and CSV. I verified it all with real flows in the emulator: added a sale, deleted it, paid the rent, watched an invalid entry get rejected. The evidence file and the audit gate are green; the live site still runs the old UI — the migration proceeds safely.

React · TypeScript · Emulator Testing

First screens of the new React UI are working

First concrete step of Phase 2: Payda's new React+TypeScript UI is up — sign-in, sign-up, password reset and the My Projects screen ported one-to-one. The best part: the new UI talks to the backend through a typed contract; I created the first project through that channel and verified it end-to-end in the emulator. The live site still runs the old UI; the migration will proceed screen by screen, with tests.

React · TypeScript · Typed Contracts

Phase 1 done: repo layout, CI and typed contracts

I put Payda on a major restructuring plan and finished the first phase: the project is now a real git repository with a root workspace, architecture/data-model docs and a GitHub Actions test gate. Old prototypes went to the archive, vulnerable packages were updated (no high-risk advisories left) and the 104 tests are still green. On top, I laid the first stone of Phase 2: the typed contracts that will be the shared language of frontend and backend. One Claude session, full transparency.

Git · CI/CD · Typed Contracts

Countdown for upcoming payments

Today I added one of those small things you'll check daily: fixed monthly payments now show with a countdown — 'rent, the 5th of each month, due in 4 days'. An Upcoming Payments card at the top of the panel sorts the nearest one first; anything due today turns red. Verified the math with a unit test and shipped it.

Countdown · Payments · Unit Tests

Payment approvals + backend split into modules

Today I added partial or one-shot payouts for partners paying workers/bankers; if there's a second partner, changes go to them for approval (four-eyes). Then I split the 800-line single-file backend into modules — lib/core + handlers/ (project, transaction, member, finance, tasks, sharing, scheduled) — behavior identical, all 104 tests still green. Removed the dead code too. Still one Claude session.

Cloud Functions · Modular Architecture · Tests

Mini-CRM, a task system and recurring-expense automation

Payda got a real mini-CRM today: search a number and you see whether that person is a customer, what they bought and WHO entered the sale, line by line — with customer notes. Alongside it came a real task system (managers assign, workers complete from 'My Tasks'), a scheduled function that posts fixed monthly expenses automatically, and a profit-share bug fix. Test suite 84/84 green, all in a single Claude session.

Mini-CRM · Task System · Scheduled Functions

Big pre-launch sweep: 10 gaps, 10 fixes

Today I combed through Payda as if launching tomorrow: period filters, CSV export, full reverse entries when deleting a sale, KVKK (Turkish data-protection) pages, an account panel, a PWA manifest and more — found 10 gaps and closed all 10 the same day. The security pass also caught and fixed CSV formula injection and a double-delete race; test suite 68/68 green. Still one Claude session, still build in public.

KVKK/GDPR · PWA · CSV Export · Security Audit

Customer records (mini-CRM) and modular permissions

Sales can now optionally include a customer number and product; search a number and you see who bought what and from which account. Customer data counts as personal data (PII), so only members with that permission can see it. Authorization is now fully modular: the role defines the screen, and every capability can be toggled one by one (a banker can do banking only — or ads too, if allowed). All 61 integration tests passed; backend and UI went live.

Cloud Functions · Firestore Rules · Security (PII) · Integration Tests

Three in one: design, security, SEO

Today I set three expert agents on Payda at once: the designer built an accessible, mobile-friendly design system with OKLCH tokens; the security expert tightened percentage fields and amount limits in an OWASP audit; the SEO agent added hreflang, a favicon and WebSite schema. In between, customer records (mini-CRM) and the fully modular permission system also went live — 61 security tests still green. All in one Claude session; I only steered.

Design System · OWASP Audit · SEO

Bot protection with reCAPTCHA

We added reCAPTCHA to Payda's sign-in and sign-up flows to protect against automated/bot abuse.

reCAPTCHA · Security

Role permissions and project management

We defined who can see and touch what: worker, partner and banker roles. Fixed the project create/delete flow with safe confirmations and applied the debugging and security-audit plan phase by phase.

Firebase · Roles/Permissions · Security

Bank-grade security and data isolation

We made sign-in, e-mail verification and password reset work, and wired every feature to a real backend. Most importantly, we built the architecture role-isolated — an employee cannot see or change anyone else's data — close to banking standards, with all writes server-side.

Firestore Rules · Firebase Auth · Security

The Payda journey begins

We set up Payda — a project management and accounting platform — on Firebase: database, authentication and hosting. Built the entire data layer from scratch.

Firebase · Firestore · Firebase Auth

12

Ekran Çeviri

12 entries

Dropped the Grok API: Claude is now the single AI hub

I cancelled the Grok API subscription; from now on Claude is my single AI hub. Ekran Çeviri's translation engine was wired to Grok — Google and Bing engines are still in the code as fallbacks, but the quality gates assume the Grok path. So this cancellation calls for a rework of the app's translation pipeline; the code still contains GrokMotor. I log abandoned decisions too, because building in public means showing what got reversed, not only what worked.

Grok API · Claude · Translation Engine · Reversed Decision

Stripped the repo down to Windows and shipped v1.1.0

I removed the old platform's source from the repo (it still lives in git history), moved the Windows project to the root, and rewrote the README from scratch for a Windows user. I wired the API key flow end to end: the key is asked for on first launch, masked as you type, stored with Windows' own encryption (DPAPI), and never written to the settings file; text that doesn't start with "xai-" is rejected, because a bad paste used to silently break every translation. GitHub Actions passed 54/54 tests on a real Windows machine and produced the 74 MB single-file .exe that needs no installer — and if the tests fail, no .exe is produced at all.

Release · GitHub Actions · DPAPI · API Key

Five-Expert Audit: 77 Findings and the Risk of Instructions Coming From the Screen

I ran a background audit from five expert angles (systems, security, linguistics, UX, QA); it produced 77 findings, distilled to 18 after removing duplicates. The most critical was a security one: the other person's on-screen messages were being fed raw into the system instruction and the output could be pasted without me reading it — meaning text on screen could effectively dictate my replies. Untrusted content is now explicitly labeled as data. The linguist caught "1,5 saat 150 chf" turning into "15 stund 150" in the outgoing message, so I added a number-preservation rule and a quality gate. I also took a backup and rewrote 13 commits of git history to purge a leaked xAI key, and closed QA's sneakiest finding: the tests were validating a copy of the production code, and now call the real functions.

Security · Prompt Injection · Git History · Testing · Audit

Wrote the Windows version from scratch as a second app

My friends are on Windows, and "adapting" the existing version wasn't possible — screen capture, text recognition and the entire UI were all platform-specific. So I wrote a separate app in C# / .NET 8 / WPF: capture via GDI BitBlt, on-device text recognition via Windows.Media.Ocr, the translation overlay as a click-through WPF layered window, and the shortcut via RegisterHotKey + SendInput. I ported the translation intelligence over intact — dialect detection, dictionaries, prompts, and the number and price protection gates. I ran 44 pure-logic tests, and one caught a real bug: the word "chli" was in Zürich's strong-signal list even though Bern uses it too, so someone writing in Bern dialect was getting replies in Zürich dialect. Fixed in both versions.

Windows · C# · .NET 8 · WPF · Port

The audit surfaced 32 defects; the worst one was deleting prices

I traced the "translations are wrong enough to be misread" complaint to its root: in live mode, blocks were matched purely by their position on screen, with no look at the text — so when a new message arrived and the list scrolled up, every message inherited the translation of the one above it. The second serious defect was sneakier: the timestamp cleaner was treating patterns like 12.50 (a price), 10-15 (a duration) and 12.05 (a date) as clock times and stripping them from the text. After the fix I measured it: number loss 0/5. I also put timeouts on the screen capture calls — with no response the work queue locked up permanently — and versioned and wiped the polluted translation memory, which had the app's own output and one-letter keys stored in it.

Audit · Translation Accuracy · OCR · Bug Fix

Found the Deadlock That Silently Killed "Translate Region"

After closing the app and hitting "Translate Region" again, nothing happened — not even a warning. The cause was a call in the middle of the background work queue that waited on the main thread: if the main thread was busy with a window, the queue deadlocked and the "translation in progress" flag stayed on forever. I removed the blocking call, took the confirmation dialog off the queue, and added a 15-second cancel for stuck jobs plus a health watchdog that checks every 5 seconds. I ran my own reproduction for 20 rounds and got 20/20 clean; that loop is now part of the release gate, so no build ships unless it passes.

Swift · Concurrency · Deadlock · Test Automation

Root cause of the crashes: two threads writing the same data

The app was crashing intermittently, and other times it threw a network error and translated nothing at all. The audit showed the translation cache, the block list and the translation strings were all being touched from two threads at once — that means memory corruption, i.e. a crash. I locked every one of them and then ran an 8-queue × 3,000-round hammer test without a single crash. On the network side, one transient failure was killing the whole translation; I gave it its own session with 3 retries spaced 0.6s and 1.8s apart, which dropped the wait on an unreachable host from 11 seconds to zero. The third problem was my own fault: I rebuilt the app ~20 times that day, and since the signature changed on every build the OS kept revoking the accessibility permission. I created a stable signing identity and verified the permission now survives across builds.

Crash · Concurrency · Network Resilience · Permissions

Built a Local Translation Memory and Fixed OCR Dropping Letters

I set up a flow that writes every translation to disk and checks that memory before calling the engine: re-translating the same messages dropped from 8.3 seconds to 0.00, and fuzzy matching catches it even when OCR reads the text slightly differently. I measured the real cause of the "dropped letters" complaint — the text was reaching Vision far too small; upscaling with Lanczos took the character error rate from 0.50% to 0.16% and fully-correct lines from 88.5% to 96.6%. Along the way I caught a numbering bug that was pinning translations to the wrong messages, stopped trusting the model for ordering, and added a regression test. I also closed a memory leak that grew from 31 MB to 106 MB in six minutes; it now sits flat at 81 MB.

OCR · Apple Vision · Caching · Memory Leak · Grok API

Taught it to tell Swiss German dialects apart, one by one

The app handled standard German fine but produced nonsense on Swiss German — which was exactly where I needed it. I pulled a golden test set of 15,610 messages out of real chat history and wrote detection that automatically distinguishes Zürich, Bern, Basel, Eastern Swiss and Wallis dialects; the panel shows which one is active, and the reply I write in Turkish comes out in that same dialect. In the chat-switching test, Bern → Zürich → Bern → Hochdeutsch all resolved correctly; 31/31 unit tests and a 6-minute, 40-round soak test passed clean. I also added a local translation memory, so a sentence translated once never goes to the model again.

Dialect Detection · Swiss German · Testing · Translation Memory

Translate-what-I-type shortcut, and an API key leaking into the build

I added a feature that takes what I type in Turkish and, on a keypress, rewrites it in the other person's language and in the tone I picked; the shortcut is now assignable from inside the app. During an audit I found the packaging script was copying my dev machine's config.json into the app bundle as the default settings — meaning my personal API key was shipping inside the distributed build. I cut that out. I also wrote 13 offline unit tests and gated the release script on them: no package is produced unless the tests pass.

Shortcut · Security · Testing · Release Gate

The app was reading its own translations and translating them again

I noticed live mode had gone into an infinite loop: the Turkish translation it painted on screen was picked up on the next pass as a "new message" and translated again. I excluded the translation layer from screen capture and the loop closed. In the same round I chained the engines — Bing → Google → Grok; if one fails the next takes over, and the panel shows which one produced the result. I also fixed the grouping logic that merged separate chat bubbles into a single block, since merged bubbles destroyed the meaning entirely.

Live Translation · OCR · Translation Engine · Bubble Grouping

Turned an Alfred script into a real desktop app

This started as a single translation script bolted onto Alfred; I moved it into a properly installed app that lives in the menu bar on its own. You drag a rectangle over a region of the screen and the app reads the text there and gives back the translation. Along the way I fixed two traps: because it ran as a background app, the OS was silently hiding every notification window it created, and the screen recording permission wasn't being requested under the right identity. By the end of the first day the app actually launched and could select a region.

Desktop · OCR · Screen Capture · Menu Bar

14

samiaktas.com

14 entries

Auditing the journal's own data: a duplicate venture and colliding IDs

This time I audited the journal's own data rather than the code, and six concrete errors turned up: "Payda" was recorded twice in the ventures list (the real root cause of the inflated homepage counter — the code had a guard, but the data was still dirty), four entry numbers were used twice (10, 30, 31, 32), four entries were empty auto-generated stubs with some Ekran Çeviri and Devam work misfiled under samiaktas.com, five entries had no tags, and one entry still showed Turkish on the English page. On top of that, work done since 16 August had never been written up at all. I fixed the lot in a single pass: the duplicate venture removed, colliding numbers reassigned, the empty stubs replaced with the real work and moved to the right venture, and the missing tags and translation filled in.

Firestore · Data Quality · i18n · Content

Post-audit repair: 36 changes across 18 files, independently verified

After the audit I ran the repair phase: 36 changes applied across five non-overlapping groups, 18 files touched, and the site's identity generation (entry number, project slug, page anchor, JSON-LD id) pulled out of four duplicated copies into a single new module. Three accuracy bugs visible in production are gone: same-day entries were rendering in reverse order, a duplicated "Payda" record made the homepage counter read 4 active ventures instead of 3, and the same post was being published under multiple identities in the structured data. A hole in the local preview tool was closed and the tool now listens only on my own machine; the journal script now takes a backup before writing and refuses to overwrite the document if it changed in the meantime. Every group was then re-audited by an independent agent that hadn't done the repair: four passed clean, and in the publish-pipeline group three of the repair agent's changes had introduced new problems — the verifier reverted all three. Nothing was pushed to production, no live data was touched, and all 20 modified files were backed up so the whole thing can be undone with one command.

Astro · Node.js · Bash · JSON-LD · Accessibility

A 53-agent audit: 13 of 19 critical claims collapsed

I ran a parallel audit of the site and its surrounding tooling across nine specialist modes (debugging, architecture, performance, clean architecture, backend, frontend, tech lead, security, DevOps); 53 agents ran in total and every critical finding had to survive a rebuttal test from two independent reviewers. The result was not what I expected: 13 of the 19 "critical" claims fell apart once measured — "the site hasn't deployed in three days", "HTML is cached at no layer", "analytics is delaying critical CSS" all failed verification against the live site. The three genuinely urgent items that remained had nothing to do with the site itself; they were in the local tools around it. The application layer held up better than I assumed: the URL safety filter blocked all 21 attack vectors tried against it, and there is no secret leakage in the built output. My lasting rule for this project: a conclusion reached by reading code isn't a finding until it's measured against production.

Multi-Agent Audit · Security · Performance · Astro · Firestore

Admin Panel and API Integration

Today I connected the Grok API to the site. I built a simple admin interface to add new projects and change images. Automatic publishing feature was also added. (Later cancelled: I dropped the Grok API subscription.)

Admin Panel · Auto-sharing · Discontinued

Daily System Improvements

Today I improved my daily system. I made data handling more realistic.

Build Journal · Automation · Data Handling

Code diet: ~8 MB of dead weight gone, structure now modular

We cleared the leftovers of the old single-file site (nearly 8 MB of dead files); the original went into the archive. Header, footer and journal-entry blocks that were copy-pasted across three pages became single components — changing a view now means editing one file. Cyrillic/Greek/Vietnamese font subsets a Turkish site never uses were dropped too (39 definitions down to 16). The look stayed pixel-identical.

Refactor · Modular Architecture · Performance

The site is bilingual now: the English version is live

samiaktas.com/en is open — the entire site in English: homepage, journal archive and venture pages. A TR/EN button sits top right; there is deliberately no auto-redirect (Google's advice: hreflang + user choice). All 15 journal entries, my About story and the whole UI were hand-translated; even dates format per language. Zero code duplication: the same files render both languages. AI engines and Google can now cite this ledger for English queries too.

i18n · hreflang · SEO · Astro

Real expenses and technology tags

The ledger's 'zero expenses' didn't reflect reality — we opened an overhead class called 'Workflow & Tools' and recorded the Claude Pro subscription (17 USD ≈ ₺796). Transparency now shows the real number; the class doesn't count as a venture and gets its own itemized section. Every journal entry also got tags for that day's technologies and security work — visitors see at a glance what each job was built with.

Transparency · Overhead · Tagging

Journal archive and venture pages

As the build journal grew, we restructured it: the homepage now shows only the last 5 entries and the full ledger lives at /gunluk. Every venture got its own journal page — Payda and samiaktas.com read separately, and any new venture gets its page automatically. Entries now run newest to oldest, every page introduces itself to search engines with its own title and schema, and the sitemap updates itself.

Astro · SEO · Schema.org

The site publishes itself + a triple expert audit

Today we built a pipeline that automatically rebuilds and publishes the site on every edit (build → deploy → instantly notify search engines). Then came three separate expert audits — design, SEO/GEO and security: accessibility/contrast fixes, richer structured data, and the database write rule locked to my account only. Note: this entire site was built with a single Claude Pro subscription, together with AI.

CI/Automation · Security · SEO · Accessibility

Rebuilt the site with zero-JavaScript Astro

For the fastest visibility on AI and Google, we moved the site to a fully static, zero-JavaScript Astro build. The result: ~34 KB, sub-half-second loads, and every piece of content embedded so bots read it instantly. We simplified the design too: a text-first opening and a single large photo in About.

Astro · Tailwind CSS · Zero-JS

Identity, login and the UI settled

We wrote the About text (Adana; starting my software entrepreneurship with this site), secured the admin login with Firebase and reworked the UI. We also found and fixed a missing DNS record on the e-mail side; [email protected] works now.

Firebase Auth · DNS · Security

Search-engine and AI visibility package

We introduced the site to Google, Bing and Yandex; set up the sitemap, robots.txt, llms.txt, Schema.org markup and IndexNow. AI crawlers like GPTBot/ClaudeBot got read access. Cloudflare added speed, security (SSL, WAF) and a caching layer.

SEO · Schema.org · Cloudflare · WAF/SSL

The site is finally live

We moved the broken portfolio site to Firebase Hosting and got it online. Split the single 7 MB file into pieces and made it persistent with Firestore; the page no longer resets on every refresh. Step by step, with AI, without knowing how to code.

Firebase Hosting · Firestore · JavaScript

04

Reels Stüdyo

4 entries

Every run now produces platform descriptions, a hook band and an A/B cover

I closed the five gaps the research file had left unimplemented. Every run now generates a description file per platform and per language, and the "cover text must never repeat the title" rule actually holds: the cover says "AI WROTE THE CODE" while the title says "Day 1: Claude wrote a security patch for my site." I added a hook band of at most 8 words over the 0.4–2.9 second window right after the cover; since it's burned in the same encode there's no extra processing time, and I verified it by pulling the frame at 1.5 seconds. Because the stamp decision has no supporting data, each run now produces both the stamped cover and a "?" variant, so there's fresh material for YouTube's Test & Compare every day. I also lay out the last 9 covers as a profile grid using Instagram's 3:4 crop and added a views/retention note field to the Publications tab; 38/38 tests and the quality gate passed at -14.0 LUFS.

Swift · ffmpeg · CoreText · Content automation · A/B testing

Stopped treating the cover as a separate file and burned it into the video's first frame

I didn't want to answer "text or a video frame on the cover?" by guessing, so I ran 6 researcher agents plus 1 synthesizer in parallel; 68 web searches produced 10 evidence-backed decisions. The most valuable finding: on all three platforms the video autoplays in the feed, so the cover never appears there — it only exists on profile and discovery surfaces. So I burned the cover into the first 0.4 seconds of the video and verified it by extracting the output's first frame. The research overturned three of my earlier decisions: the dark left band is gone (TikTok's grid crops covers to a center square), the circular stamp is gone (it reads as a clickbait signal), and the "pick the shocked face" logic is gone; in their place came a center-block layout, an angled rectangular label, and an evidence card carrying a screenshot of that day's tool. After rebuilding, all 38 unit tests and the quality gate passed again, with duration holding at 19.66 + 0.4 = 20.075 seconds.

Multi-agent research · Cover design · ffmpeg · A/B testing

Wrote Reels Stüdyo from scratch and installed it as a signed macOS app

I didn't leave the plan on paper: I wrote the StudyoKit video engine, the SwiftUI panel and the CLI the same day, signed the build, and installed it as /Applications/Reels Stüdyo.app. To verify it I produced a test clip from Turkish TTS speech and a real face photo, deliberately dark and quiet; the audio moved from -24.6 LUFS to exactly -14.0, a 25.3-second video came down to 19.6 seconds, and the 0.3-second gap below the threshold was correctly preserved. All 38 unit tests passed, and the quality gate now checks LUFS, resolution, fps, first-frame brightness and duration ratio automatically on every job. When I found that Homebrew's ffmpeg 8.x ships without libass, I wrote subtitle burning myself via CoreText → PNG → overlay; with whisper large-v3-turbo the Turkish transcription came out word-perfect on all four sentences. I also migrated the journal and site infrastructure from my Devam app as GunlukKit — 15 files that compiled without a single line of change.

Swift · SwiftUI · ffmpeg · Apple Vision · whisper.cpp · CoreText

Locked the vertical video pipeline's standards through research

Before writing any code, I researched the pipeline that turns a phone-shot vertical video into a publish-ready file in one pass: I fixed -14 LUFS as the audio target, 0.4 seconds as the silence-trim threshold, and 1080x1920 at 30 fps as the output. I reworked the cover template twice; in the first draft the text sat in the lower left, and once I saw that Instagram's profile grid crops covers to 3:4, I moved every critical element into the center safe box. For German subtitles I tested Apple's on-device translation engine, found Turkish missing on macOS 26, and routed the path as Turkish → English → German instead. I verified the 2026 API limits of YouTube, Instagram and TikTok one by one and wrote ten decisions into PLAN.md. I deliberately wrote no code in this round.

ffmpeg · loudnorm · Apple Translation · Platform APIs · Planning