<?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: עדי מולדבסקי</title>
    <description>The latest articles on DEV Community by עדי מולדבסקי (@amoldavski).</description>
    <link>https://dev.to/amoldavski</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%2F3815132%2Ff49ef9ce-80a4-4965-998e-1ade5f17f97b.jpg</url>
      <title>DEV Community: עדי מולדבסקי</title>
      <link>https://dev.to/amoldavski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amoldavski"/>
    <language>en</language>
    <item>
      <title>Building Tickr: A TikTok-Style App Where Videos Have Permadeath</title>
      <dc:creator>עדי מולדבסקי</dc:creator>
      <pubDate>Mon, 09 Mar 2026 16:28:19 +0000</pubDate>
      <link>https://dev.to/amoldavski/building-tickr-a-tiktok-style-app-where-videos-have-permadeath-32f3</link>
      <guid>https://dev.to/amoldavski/building-tickr-a-tiktok-style-app-where-videos-have-permadeath-32f3</guid>
      <description>&lt;p&gt;I built &lt;a href="https://getickr.com" rel="noopener noreferrer"&gt;Tickr&lt;/a&gt; — a short video feed where every video has a real-time life timer. Watch it and the timer goes up. Skip it and the timer goes down. When it hits zero, the video is permanently deleted.&lt;/p&gt;

&lt;p&gt;No algorithm. No likes. No followers. Just survival.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Problem: Real-Time Timers Without a Server Loop
&lt;/h2&gt;

&lt;p&gt;The naive approach would be running a process that decrements every video's timer every second. With hundreds of videos, that's expensive and fragile.&lt;/p&gt;

&lt;p&gt;Instead, I store two values per video in DynamoDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;life_seconds&lt;/code&gt; — total accumulated life&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;last_updated_at&lt;/code&gt; — timestamp of the last watch/skip event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The remaining time is calculated on read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;life_seconds&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_updated_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No background jobs. No cron. The timer is just math.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Deleting Dead Videos
&lt;/h2&gt;

&lt;p&gt;DynamoDB has a built-in TTL feature. When a video's remaining life hits zero, I set a TTL attribute. DynamoDB automatically deletes it within minutes — no cleanup Lambda needed.&lt;/p&gt;

&lt;p&gt;A DynamoDB Stream catches the deletion event and promotes the next queued video into the arena.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time with WebSockets
&lt;/h2&gt;

&lt;p&gt;API Gateway WebSocket API handles the real-time connection. When a user watches a video, the client sends a &lt;code&gt;watch&lt;/code&gt; event. When they swipe away, a &lt;code&gt;skip&lt;/code&gt; event fires.&lt;/p&gt;

&lt;p&gt;The server tracks connection time — the client never sends "I watched for X seconds." This prevents cheating. The server measures the actual WebSocket connection duration and credits the video accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lambda&lt;/strong&gt; — all business logic (videos, upload, moderation, WebSocket handlers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt; — REST API + WebSocket API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB&lt;/strong&gt; — videos table with GSI for status-based queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 + CloudFront&lt;/strong&gt; — video storage and CDN delivery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rekognition&lt;/strong&gt; — content moderation (frame extraction + label detection)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fargate Spot&lt;/strong&gt; — seeder tasks that fetch content to bootstrap the arena&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;React + Vite with a TikTok-style vertical swipe feed. Key decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only the active video + neighbors get a &lt;code&gt;src&lt;/code&gt; attribute (prevents memory overload)&lt;/li&gt;
&lt;li&gt;Framer Motion for death animations (glitch dissolve when timer hits zero)&lt;/li&gt;
&lt;li&gt;WebSocket reconnection with exponential backoff&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What It Costs
&lt;/h2&gt;

&lt;p&gt;Running this on AWS serverless costs almost nothing at low scale. Lambda free tier covers most invocations. DynamoDB on-demand pricing means I pay per request. The most expensive part is the Fargate seeder tasks (~$2/day).&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Check it out at &lt;a href="https://getickr.com" rel="noopener noreferrer"&gt;getickr.com&lt;/a&gt; — swipe through some videos and watch the timers tick. Upload your own 15-second clip and see if it survives.&lt;/p&gt;

&lt;p&gt;Is "attention = life" compelling gameplay, or just stressful? Would love to hear what you think.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>aws</category>
      <category>python</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
