<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Can Ceylan</title>
    <description>The latest articles on DEV Community by Can Ceylan (@canceylan1988).</description>
    <link>https://dev.to/canceylan1988</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3861469%2F5a1153d6-d767-404d-8731-acf1033c9807.png</url>
      <title>DEV Community: Can Ceylan</title>
      <link>https://dev.to/canceylan1988</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/canceylan1988"/>
    <language>en</language>
    <item>
      <title>Two AI agents need one live memory file</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Wed, 29 Apr 2026 07:06:23 +0000</pubDate>
      <link>https://dev.to/canceylan1988/two-ai-agents-need-one-live-memory-file-7bg</link>
      <guid>https://dev.to/canceylan1988/two-ai-agents-need-one-live-memory-file-7bg</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Parallel AI coding feels magical until both agents start maintaining their own version of reality.&lt;/p&gt;

&lt;p&gt;One agent remembers a rule from chat history. The other reads a repo note that is already stale. A workflow gets updated in one place but not the other. The user ends up repeating the same instruction twice, forwarding approvals manually, and cleaning up collisions that should never have happened.&lt;/p&gt;

&lt;p&gt;In practice, the user becomes the synchronization layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real cause
&lt;/h2&gt;

&lt;p&gt;The root problem is not "bad memory." It is &lt;strong&gt;multiple writable memory surfaces&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If one agent treats a handoff file as live state, another agent treats a different file as live state, and both also rely on thread memory, the system has no clear authority. Drift is guaranteed.&lt;/p&gt;

&lt;p&gt;The same thing happens with parallel edits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no single place to check whether another lane is active&lt;/li&gt;
&lt;li&gt;no explicit ownership boundary&lt;/li&gt;
&lt;li&gt;no habit of writing what changed, why, and what not to touch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agents are not just missing information. They are missing a shared contract about where truth lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this takes longer than it should
&lt;/h2&gt;

&lt;p&gt;This failure mode is subtle because each individual step feels reasonable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;documenting in two places feels safer&lt;/li&gt;
&lt;li&gt;asking the user to confirm again feels polite&lt;/li&gt;
&lt;li&gt;starting work before checking for another active lane feels fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those local optimizations create a global tax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicated instructions&lt;/li&gt;
&lt;li&gt;overwritten edits&lt;/li&gt;
&lt;li&gt;ambiguous approvals&lt;/li&gt;
&lt;li&gt;no usable history when something breaks later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system looks collaborative on the surface while quietly depending on the user to keep it coherent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The operating model that fixes it
&lt;/h2&gt;

&lt;p&gt;Use one mutable collaboration-memory file and make everything else point to it.&lt;/p&gt;

&lt;p&gt;Then add four rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Current truth has one home.&lt;/strong&gt;&lt;br&gt;
One live file holds active rules, ownership, open lanes, and recent decisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;History is preserved, not silently deleted.&lt;/strong&gt;&lt;br&gt;
Resolved rollout history moves to an archive file so future debugging can reconstruct what changed and why.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-agent review is direct.&lt;/strong&gt;&lt;br&gt;
If one agent needs the other's approval, use a direct review/delegation mechanism instead of making the user relay the same context twice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel work starts with a pre-flight check.&lt;/strong&gt;&lt;br&gt;
Before meaningful edits, check for active lanes, declare ownership, and define a do-not-touch boundary if overlap is possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A simple template that works
&lt;/h2&gt;

&lt;p&gt;Keep a tiny &lt;code&gt;Active Work&lt;/code&gt; block in the live memory file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; owner: Codex
&lt;span class="p"&gt;-&lt;/span&gt; scope: admin workflow cleanup
&lt;span class="p"&gt;-&lt;/span&gt; started: 2026-04-29 08:30 Vienna
&lt;span class="p"&gt;-&lt;/span&gt; do-not-touch: app/admin/&lt;span class="err"&gt;*&lt;/span&gt; until handoff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one block turns "I thought nobody was in there" into an avoidable mistake instead of an excuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusable rule
&lt;/h2&gt;

&lt;p&gt;If multiple AI agents touch the same codebase, &lt;strong&gt;the collaboration system is part of the product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Do not optimize only for generation quality or coding speed. Optimize for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one live memory source&lt;/li&gt;
&lt;li&gt;explicit temporary ownership&lt;/li&gt;
&lt;li&gt;direct agent-to-agent review&lt;/li&gt;
&lt;li&gt;traceable history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Otherwise the user will end up doing project management by hand while the agents appear autonomous.&lt;/p&gt;

&lt;p&gt;That is not automation. It is outsourced coordination.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>product</category>
    </item>
    <item>
      <title>Scheduled publishing without a cron: runtime-evaluated date filters</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Tue, 28 Apr 2026 12:09:21 +0000</pubDate>
      <link>https://dev.to/canceylan1988/scheduled-publishing-without-a-cron-runtime-evaluated-date-filters-1mj</link>
      <guid>https://dev.to/canceylan1988/scheduled-publishing-without-a-cron-runtime-evaluated-date-filters-1mj</guid>
      <description>&lt;h2&gt;
  
  
  The cron-dependent approach and its failure mode
&lt;/h2&gt;

&lt;p&gt;The standard approach to scheduled publishing: a cron job runs at the scheduled time, updates a &lt;code&gt;published&lt;/code&gt; flag in the database, and the content becomes visible.&lt;/p&gt;

&lt;p&gt;The failure mode: the cron job misses its window. The newsletter fires at 07:00. The cron job that was supposed to set &lt;code&gt;published: true&lt;/code&gt; at 06:55 didn't run — server restart, network issue, timing drift. The newsletter goes out with a link to a 404.&lt;/p&gt;

&lt;p&gt;The cron approach has a single point of failure between "content ready" and "content visible."&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime evaluation: the always-consistent alternative
&lt;/h2&gt;

&lt;p&gt;Instead of updating a flag, evaluate visibility at request time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAllArticles&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;ArticleMeta&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;readAllMdxFiles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduledDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduledDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* by date */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An article with &lt;code&gt;scheduledDate: "2026-04-20T10:00:00Z"&lt;/code&gt; is invisible until that moment, then visible to every request after it — without any cron, any database update, any deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MDX frontmatter pattern
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scheduled&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;article"&lt;/span&gt;
&lt;span class="na"&gt;scheduledDate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-04-20T10:00:00Z"&lt;/span&gt;
&lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;published: false&lt;/code&gt; plus a future &lt;code&gt;scheduledDate&lt;/code&gt; means: draft, not yet visible.&lt;br&gt;&lt;br&gt;
&lt;code&gt;published: false&lt;/code&gt; plus a past &lt;code&gt;scheduledDate&lt;/code&gt; means: automatically visible now.&lt;br&gt;&lt;br&gt;
&lt;code&gt;published: true&lt;/code&gt; means: always visible, regardless of date.&lt;/p&gt;

&lt;p&gt;The two fields serve different purposes. &lt;code&gt;published&lt;/code&gt; is manual override. &lt;code&gt;scheduledDate&lt;/code&gt; is automatic timed release.&lt;/p&gt;
&lt;h2&gt;
  
  
  The dual-mechanism for newsletter integration
&lt;/h2&gt;

&lt;p&gt;Runtime evaluation handles visibility. It does not handle triggered actions — like sending a newsletter when an article goes live.&lt;/p&gt;

&lt;p&gt;For that, you still need a cron. But now the cron has one job: check if any article became visible in the last N minutes and fire the newsletter. It no longer needs to update the database first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cron at 07:00 UTC&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recentlyPublished&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAllArticles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduledDate&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;windowStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// last hour&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowStart&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;recentlyPublished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendNewsletter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Optionally: commit published: true to MDX to prevent re-sending&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference: the article is already visible before the cron runs. If the cron misses its window, the article is still live — only the newsletter is delayed, not the publication.&lt;/p&gt;

&lt;h2&gt;
  
  
  The consistency guarantee
&lt;/h2&gt;

&lt;p&gt;Runtime evaluation gives you a simple invariant: an article with a past &lt;code&gt;scheduledDate&lt;/code&gt; is always visible, on every server, in every region, with no state to sync. There's no "published in one region but not another" problem because there's no state — just a comparison against the current time.&lt;/p&gt;

&lt;p&gt;This makes it particularly well-suited for static site generators and edge-rendered content, where database updates would require a redeployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you gain&lt;/strong&gt;: simplicity, consistency, no failure mode from missed cron jobs, works on read-only filesystems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you give up&lt;/strong&gt;: instant unpublishing (you'd need to remove the file or set &lt;code&gt;scheduledDate&lt;/code&gt; to a future date), and the ability to see exactly which articles are "live" without querying at a specific time.&lt;/p&gt;

&lt;p&gt;For most publishing workflows, the gains outweigh the trade-offs.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>backend</category>
    </item>
    <item>
      <title>Soft deletes aren't just for audit trails — they're your sales pipeline</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Mon, 27 Apr 2026 08:14:00 +0000</pubDate>
      <link>https://dev.to/canceylan1988/soft-deletes-arent-just-for-audit-trails-theyre-your-sales-pipeline-2fi7</link>
      <guid>https://dev.to/canceylan1988/soft-deletes-arent-just-for-audit-trails-theyre-your-sales-pipeline-2fi7</guid>
      <description>&lt;h2&gt;
  
  
  Why marketplaces shouldn't hard-delete listings
&lt;/h2&gt;

&lt;p&gt;When a listing goes inactive on a marketplace — a seller closes their account, a venue cancels, a product is removed — the naive response is to delete the record. It's gone, it's irrelevant.&lt;/p&gt;

&lt;p&gt;But that record contains exactly the information you need to win them back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contact details&lt;/li&gt;
&lt;li&gt;What they listed and at what price&lt;/li&gt;
&lt;li&gt;When they were last active&lt;/li&gt;
&lt;li&gt;Why they stopped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hard delete destroys all of this. A soft delete — setting &lt;code&gt;isActive = false&lt;/code&gt; — preserves it. Your inactive records become your CRM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforce it at the database level, not in application code
&lt;/h2&gt;

&lt;p&gt;Application-level soft delete is fragile. Any developer, any migration script, any admin panel with a "Delete" button can bypass it. Six months later someone writes a cleanup script that issues &lt;code&gt;DELETE WHERE isActive = false&lt;/code&gt; and you lose your entire lapsed-user pipeline.&lt;/p&gt;

&lt;p&gt;The reliable approach is to remove &lt;code&gt;DELETE&lt;/code&gt; permission from the application database role entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Application role: can read, insert, update — cannot delete&lt;/span&gt;
&lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;listings&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;app_role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Admin role: can delete, but only with explicit confirmation&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;listings&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;admin_role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;isActive = false&lt;/code&gt; is not a convention — it's the only option the application has. Hard deletes require admin credentials and an explicit action.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to build on top of inactive records
&lt;/h2&gt;

&lt;p&gt;Once you've preserved the data, build the re-engagement workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter inactive records by time since last activity (30 days, 90 days, 6 months)&lt;/li&gt;
&lt;li&gt;Segment by what they listed — different outreach for high-value vs casual sellers&lt;/li&gt;
&lt;li&gt;Track re-activation rate as a metric separate from new user acquisition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conversion rate on re-engaging inactive users is almost always higher than acquiring new ones. They already know your platform. Something caused them to stop — a direct outreach with a specific reason to return is often enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naming convention matters
&lt;/h2&gt;

&lt;p&gt;Don't name the column &lt;code&gt;deleted&lt;/code&gt; or &lt;code&gt;is_deleted&lt;/code&gt;. Name it &lt;code&gt;isActive&lt;/code&gt; or &lt;code&gt;status&lt;/code&gt;. The framing shapes how developers think about the data.&lt;/p&gt;

&lt;p&gt;A column called &lt;code&gt;deleted&lt;/code&gt; invites deletion-by-update thinking — "we're pretending it's deleted." A column called &lt;code&gt;isActive&lt;/code&gt; frames it correctly — this is an active/inactive lifecycle state, not a tombstone.&lt;/p&gt;

&lt;h2&gt;
  
  
  When soft delete is the wrong pattern
&lt;/h2&gt;

&lt;p&gt;Soft delete adds complexity. It means every query needs a &lt;code&gt;WHERE isActive = true&lt;/code&gt; clause, or you risk surfacing inactive records in user-facing views.&lt;/p&gt;

&lt;p&gt;It's worth the overhead when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inactive records have re-engagement value (marketplaces, SaaS)&lt;/li&gt;
&lt;li&gt;You need audit history for compliance&lt;/li&gt;
&lt;li&gt;Users expect to be able to reactivate ("I want my old account back")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not worth it for truly ephemeral data — log entries, session records, temporary tokens. Hard delete those.&lt;/p&gt;

&lt;p&gt;The rule of thumb: if a business person would want to contact the entity represented by that record, soft delete it.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Autotest With Social Posts</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:37:42 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-with-social-posts-3pp0</link>
      <guid>https://dev.to/canceylan1988/autotest-with-social-posts-3pp0</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Race 1</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:37:38 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-race-1-5918</link>
      <guid>https://dev.to/canceylan1988/autotest-race-1-5918</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Bad slug</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:32:27 +0000</pubDate>
      <link>https://dev.to/canceylan1988/bad-slug-440b</link>
      <guid>https://dev.to/canceylan1988/bad-slug-440b</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Article Page Test</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:32:21 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-article-page-test-4kak</link>
      <guid>https://dev.to/canceylan1988/autotest-article-page-test-4kak</guid>
      <description>&lt;p&gt;This is the article body for the page test.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Race 2</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:31:18 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-race-2-5cc</link>
      <guid>https://dev.to/canceylan1988/autotest-race-2-5cc</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Past Scheduled</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:30:55 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-past-scheduled-5166</link>
      <guid>https://dev.to/canceylan1988/autotest-past-scheduled-5166</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Round Trip</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 03:30:46 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-round-trip-4dj0</link>
      <guid>https://dev.to/canceylan1988/autotest-round-trip-4dj0</guid>
      <description>&lt;p&gt;This is an automated test article body.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>You Don't Need to Code Like a Developer — You Need to Think Like a Product Owner</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 24 Apr 2026 12:55:53 +0000</pubDate>
      <link>https://dev.to/canceylan1988/you-dont-need-to-code-like-a-developer-you-need-to-think-like-a-product-owner-4odg</link>
      <guid>https://dev.to/canceylan1988/you-dont-need-to-code-like-a-developer-you-need-to-think-like-a-product-owner-4odg</guid>
      <description>&lt;h1&gt;
  
  
  You Don't Need to Code Like a Developer — You Need to Think Like a Product Owner
&lt;/h1&gt;

&lt;p&gt;I used to sit in product meetings watching engineers debate architecture decisions and secretly feel like I was only getting half the conversation. Now I'm shipping my own ideas. I'm not going to pretend I became a developer. But I'm not not one either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;There's a version of this story that's about AI being democratising and the future being now. That version is boring and also slightly dishonest. The real version is that I spent years building a very specific frustration: I could see what needed to be built, I understood users, I could write a product spec that would make a senior engineer nod, but the moment I was alone with a blank screen I was stuck.&lt;/p&gt;

&lt;p&gt;My background is operations and product. I scaled a food delivery business across Austria, then moved into a more structured product ownership role at a national rail freight company. Two very different environments, one shared limitation: speed was always somebody else's ceiling, not mine. That's a hard place to be if you're wired the way I am.&lt;/p&gt;

&lt;p&gt;So I started learning. A frontend course in Vienna. Experimenting with ChatGPT and Claude to generate code. Picking up just enough HTML and CSS to know what I was looking at. But without a real infrastructure layer, without understanding how the pieces actually connect, I kept hitting the same wall. Prototype. Impress myself. Immediately get stuck on something backend.&lt;/p&gt;

&lt;p&gt;Then Claude Code happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed when AI moved into the infrastructure layer
&lt;/h2&gt;

&lt;p&gt;This is the answer to one of the most searched questions in this space right now: can you actually build something real with AI coding tools if you're not a developer?&lt;/p&gt;

&lt;p&gt;Short answer: yes, with an important caveat. The shift that made it real for me wasn't the AI getting smarter at writing code in isolation. It was Claude Code integrating directly into the development environment, specifically Visual Studio Code. That's the difference between someone writing you a recipe and someone standing in your kitchen with you.&lt;/p&gt;

&lt;p&gt;Before that integration, I'd generate code in a chat window, paste it somewhere, watch it break, not know why, and start over. With Claude Code inside the IDE, the feedback loop collapsed. The model can see the file structure, understand what's broken, and suggest fixes in context. For someone who understands what they want but not always how to get there, that context is everything.&lt;/p&gt;

&lt;p&gt;I describe it as getting 200 extra horsepower. The car was already mine. I just finally had an engine that matched what I was trying to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code vs OpenAI Codex: what I actually use them for
&lt;/h2&gt;

&lt;p&gt;This is the other question people search for constantly, and most answers either read like a spec sheet or come from people who have never actually tried to build something with their own idea on the line.&lt;/p&gt;

&lt;p&gt;Here's where I've landed, at least for now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; is my primary driver. Its ability to hold context across a project, to understand what I'm trying to build conceptually, not just syntactically, is still the thing I value most. It's also genuinely good at front-end architecture, which is where most of my work lives. The limitation I keep running into is subscription-based: there are rate limits, and when you're deep in a build session, hitting a wall mid-flow is a specific kind of pain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codex&lt;/strong&gt; entered my stack as an emergency backup when Claude hits its limit. What surprised me is that it earned a permanent spot. It's particularly sharp in debugging scenarios, catching logical errors and edge cases that sometimes slip through during faster generation. It handles isolated, well-defined tasks cleanly. Where it's weaker, at least in my experience so far, is in the bigger picture. Give it a full feature to architect from scratch and it starts to feel like it's thinking about the current file, not the whole system.&lt;/p&gt;

&lt;p&gt;The honest summary: Claude Code thinks about your project. Codex solves your problem. Right now I need both.&lt;/p&gt;

&lt;p&gt;I'll also mention Gemini here briefly, because I did try it. The integration into my current stack was rough and its ability to hold context across a longer build felt noticeably behind. I gave up faster than I expected to. That could change, and I'll keep an eye on it.&lt;/p&gt;

&lt;p&gt;The next thing I'm genuinely curious about is improving the communication between Claude and Codex within the same workflow. Right now they're two separate conversations. The goal is something more like a handshake. Still testing. Will report back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real edge: thinking like a product owner, not a developer
&lt;/h2&gt;

&lt;p&gt;Here's the argument I don't see made enough, and it's the one that actually changed how I work.&lt;/p&gt;

&lt;p&gt;Most people trying to build with AI tools are trying to impersonate a developer. They're learning syntax, memorising patterns, trying to approximate what a software engineer does. That's the wrong frame entirely. And it's also exhausting.&lt;/p&gt;

&lt;p&gt;The real unlock isn't replacing the developer. It's understanding that you don't need to.&lt;/p&gt;

&lt;p&gt;What you need is to be a very good product owner. And if you've spent any time working in an agile or scrum environment — writing user stories, running sprint planning, defining acceptance criteria, grooming a backlog — then you already have most of the toolkit. You just haven't pointed it at an AI yet.&lt;/p&gt;

&lt;p&gt;Think about what a product owner actually does in a functioning team. They translate business goals into clear, scoped, testable requirements. They prioritise ruthlessly. They communicate across functions — engineering, design, stakeholders — and make sure everyone is building the same thing. They ask the question "what does done actually look like?" before a single line of code gets written.&lt;/p&gt;

&lt;p&gt;That's exactly what you need to do with AI. The tools that used to serve your engineering team now serve you. Claude Code is your dev team. Codex is the specialist you bring in for tricky bugs. You write the brief. You define the sprint. You review the output. You decide what ships.&lt;/p&gt;

&lt;p&gt;The AI doesn't care if you can write a for-loop. It cares whether you can tell it precisely what to build, why, and how you'll know when it's working. That's product thinking. And if you've been doing product work in any serious capacity, you're closer to this than you realise.&lt;/p&gt;

&lt;p&gt;There's also a deeper business advantage here that I think gets underestimated. Understanding how a business actually runs — unit economics, user flows, operational constraints, what matters to a customer versus what matters to an investor — gives you an edge that no amount of syntax knowledge can replicate. The AI can write the code. It can't tell you whether the feature you're asking for is the right one to build. That judgment, the business judgment, is still yours. And in a one-man setup, it's everything.&lt;/p&gt;

&lt;p&gt;This is how you become a one-man company sooner than you think. Not by becoming a full-stack developer. By becoming the combining force: the person who understands the business well enough to direct an AI development team, who knows enough about the technology to have an intelligent conversation with the tools building it, and who doesn't need to wait for a sprint review to unblock themselves.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't need to replace the developer. You need to be the product owner who finally has a dev team that never sleeps and never needs onboarding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What most people get wrong about AI-assisted development
&lt;/h2&gt;

&lt;p&gt;They treat it as autocomplete. As a faster way to write the code they already knew they needed to write.&lt;/p&gt;

&lt;p&gt;That framing undersells it and also sets you up for disappointment, because when you treat it as autocomplete it fails in very autocomplete-like ways. It confidently finishes sentences you didn't quite start right.&lt;/p&gt;

&lt;p&gt;The better frame, the one that's actually working for me, is thinking of the AI as a technical co-founder who is infinitely patient, available at 2am, and needs you to know what you want to build even if not how. You still have to think. You still have to understand the output well enough to know when something is wrong. The frontend course I did wasn't wasted just because I'm not writing all my own code. It gave me enough vocabulary to be a useful collaborator instead of just a passenger.&lt;/p&gt;

&lt;p&gt;There's also a practical architecture lesson here that took me longer than I'd like to admit: knowing enough about databases, API logic, and backend structure doesn't mean you have to write that layer yourself. It means you can have an intelligent conversation with the tool that's writing it for you. That distinction matters.&lt;/p&gt;

&lt;p&gt;My personal website, ceylan.co.at, is itself the result of this stack. It's not a static template. It's a living thing I'm building and iterating, often at unusual hours, using exactly the tools I'm writing about here. That feedback loop, where the project and the learning are the same thing, is something I wrote more about in the context of building Fleamio, my startup, where the stakes of getting the architecture right are considerably higher.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with the infrastructure layer, not the chat window.&lt;/strong&gt; If you're serious about building, get Visual Studio Code set up and connect Claude Code to it. Generating code in isolation and pasting it somewhere is a frustrating and slow way to learn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dust off your product owner toolkit and point it at AI.&lt;/strong&gt; User stories. Acceptance criteria. Backlog grooming. Sprint scoping. If you've worked in agile environments, you already know how to brief a team. That's the skill. Apply it here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn just enough of the fundamentals to be a useful collaborator.&lt;/strong&gt; A frontend basics course, a weekend with SQL, one solid read-through of how APIs work. You don't need to be able to build from scratch. You need to recognise when something is broken and ask the right question about why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build your own stack in layers, not as a single bet.&lt;/strong&gt; Claude Code as primary, Codex for debugging and when limits hit. Add tools when you have a specific reason, not because someone on Reddit said it's better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat the subscription limits as a forcing function.&lt;/strong&gt; When Claude hits its ceiling, switch to Codex. The interruption is annoying but it also trains you to write better, more complete prompts the first time so you need fewer follow-ups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let your business understanding be the moat.&lt;/strong&gt; The AI can write the code. It cannot tell you which problem is worth solving, what users will actually pay for, or when a feature is a distraction. That's the judgment you bring. It's not a soft skill — it's the whole strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document as you go.&lt;/strong&gt; I'm doing this publicly on the site. You can do it privately. Either way, writing down what worked, what broke, and what you still don't understand is the fastest way to actually retain any of this rather than just producing output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't wait until you understand everything.&lt;/strong&gt; The gap between what I know and what I'm building has been present the entire time. That's not a bug. That's how you learn faster than a classroom ever taught you to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stack will change. The tools will get better, or be replaced by something I haven't tried yet. What won't change is the underlying principle: if you understand the business, know what you want to build, and are willing to stay curious about how — the distance between a product idea and a working product is smaller than it has ever been. You might not need a dev team. You might just need to start acting like the product owner you already are.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Autotest Workflow Tech Social</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Tue, 21 Apr 2026 03:09:22 +0000</pubDate>
      <link>https://dev.to/canceylan1988/autotest-workflow-tech-social-5f2c</link>
      <guid>https://dev.to/canceylan1988/autotest-workflow-tech-social-5f2c</guid>
      <description>&lt;p&gt;This is the article body for the social post test.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
  </channel>
</rss>
