产品设计
I’m hooked on Peak Design’s new City bags
It's just a hook, sewn into a bag, but I really, really like it. Peak Design is so proud of its clever integration that the San Francisco-based maker of camera gear gave it a name: BagLev, for its ability to keep its new City Line of bags levitated above the dirty ground. How many of […]
AI 资讯
Dog Whisperer
This is a submission for Weekend Challenge: Dog Days Edition Dog Whisperer is an app that looks at a photo of your dog, figures out what it's probably feeling, and then actually says it out loud in a voice that matches the mood. Grumpy dog gets a grumpy voice. Dramatically offended dog gets... a dramatically offended voice. You get the idea. It also doubles as a pet log — meals, weight, and walks tracked over time in Snowflake, with trend charts so you can actually see if your dog's been eating more than usual or losing weight. Add your pets and start logging. Use your unique username to keep track of your pets! Here is App in action: https://dogwhisperer-whi6rye8zklcdtnedyxmww.streamlit.app/ Demo Code Kaku-g / dog_whisperer How I Built It I used Google's Gemini (model: gemini-3.5-flash-lite ) to infer the mood of the dog (or cat, lizard, ferret — whoever's in the photo) from a single image, then passed that straight into Gemini's native TTS (model: gemini-3.1-flash-tts-preview ) to give it a voice that actually matches the mood — a sleepy dog sounds sleepy, a dramatic one sounds dramatic. For logging and trends, I used Snowflake — compute, databases, and tables — to store meals, weight, and walks for every pet and power the trend charts in the app. So it's really two things working hand in hand: a generative AI pipeline paired with a data warehouse. The AI part is what makes the app fun — inferring your pet's mood and giving it a voice. The Snowflake part is what gives it a real use case , since it's something you could keep using for long. Prize Categories I used Google AI and Snowflake, so I'm submitting under both: 🏆 Best Use of Google AI 🏆 Best Use of Snowflake
AI 资讯
Warm Hearth — A Landing Page Built Around One Fire
This is a submission for Frontend Challenge - Comfort Food Edition, Perfect Landing What I Built Warm Hearth — a landing page for a comfort food restaurant built around one idea: everything on the menu comes from the same wood-fired hearth in the back. Instead of treating "comfort food restaurant" as a generic brief, I anchored the whole page to that single hearth: An interactive hearth centerpiece. Right after the hero, there's a hand-drawn CSS/SVG fire pit you can click to "stoke." The flame flares, embers burst upward, and a small honest counter tracks how many times you've stoked it this visit — no fake global numbers, just a real, session-based response to your click. Four dishes, each with real cultural identity. Ramen, warm pies, a cheesy pasta bake, and gulab jamun — each with its own hand-drawn SVG illustration and a border motif pulled from its own cuisine (a jade-and-gold double line for the ramen, a scalloped pastry edge for the pies, an Italian tricolor accent for the pasta, gold paisley tones for the gulab jamun) rather than one generic card style stretched across all four. Living detail, not static photos. Steam rises off the ramen, pies, and pasta bake using the same wisp animation as the hero's hearth, so the whole page reads as one consistent "warmth" language. The gulab jamun gets a syrup shimmer and drip instead, since steam isn't the right detail for a syrup-soaked sweet. Price tags that hang like real kitchen tickets — pinned by a string, swaying gently, and giving a small "flicked" swing on hover instead of sitting flat on the card. Mira, an illustrated host in the corner who offers a rotating table tip when you click her — a small personal touch instead of a static "contact us" widget. Built for actual use, not just to look good in a screenshot: keyboard-focusable tab filters, a skip-to-content link, aria-live regions on the interactive parts, and full prefers-reduced-motion support that disables every animation without breaking the page. Dem
AI 资讯
I spent 11 days optimizing a search ranking that only I could see
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry . The symptom: good numbers, no users I publish small automation tools on a marketplace. By August I had 23 of them live. Store search looked fine — measured repeatedly, from a real browser, against the real production endpoint: Search term My rank (store UI, Aug 2) sitemap checker #3 google play audit #1 Real numbers after 89 days: 1 active user across all 23 tools. $0 revenue. A #1 ranking and one user is not a rounding error. It is a contradiction, and I spent a week and a half resolving it in the wrong direction. Eleven days of correct answers to the wrong question If ranking is fine and users are zero, the fault must be downstream — that was the reasoning. So I went looking for it, carefully: Demand analysis. Pulled 3,655 listings, then went deeper to 12,834 to check for sampling bias in the first pass. (There was one. I found it and corrected it.) Naming analysis. Split the corpus by whether the title contained a well-known platform name. Median users: 5 vs 2. Age-cohort analysis. Measured the base rate for new listings: only 11% (n=9) get their first user within 0–3 days of publishing, against 74% at 14–30 days. Mine were young. The zeros were, statistically, unremarkable. Acted on all of it. Renamed 5 tools. Added output schemas across the board — the platform's own quality score went from 74 to 78–79. Every one of those produced a defensible number. Not one of them changed anything. That pattern is the actual signal, and I missed it for too long: when every hypothesis confirms and nothing moves, stop testing hypotheses and start testing the instrument. "It reproduced" is not "it's correct" I had re-measured the ranking several times over those days. Same answer each time. I read that as confirmation. It isn't. Re-running a measurement under identical conditions reproduces the same bias just as faithfully as it reproduces the same truth . Repetition rules out transient noise and
AI 资讯
My security hook silently stopped guarding. The bug was one line of encoding.
This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry . Project Overview I run a set of local policy guards around an AI coding agent. They are ordinary PreToolUse hooks: before the agent is allowed to perform an action, the proposed tool call is handed to a small Python script as JSON on stdin . The contract is two exit codes. exit 0 → allow exit 2 → block, and send the reason back to the agent as feedback There are several. One refuses access to credential paths. One intercepts destructive shell commands. One enforces a directory boundary. And one — malformed-read-guard.py — blocks the agent from reading files that contain corrupted tool-call syntax, because reading that syntax makes the model start emitting it too, and the session locks up. They had been working for weeks. One of them had also, for some of that time, been doing nothing at all. Bug Fix or Performance Improvement The symptom Same file. Same bytes. Two locations. Placed at an ASCII path → guard fires, exit 2 , read blocked. Placed under a directory whose name contains Japanese characters → exit 0 , read allowed. No exception. No stack trace. No log line. Nothing anywhere said a decision had been skipped. The hook ran, the hook returned "allow", and the agent read a file it was supposed to be protected from. The mechanism Three steps, and the ugly part is that each one is individually defensible. 1. The payload is UTF-8. The reader is not. Hook input is always UTF-8. But on Windows, Python opens sys.stdin using the locale encoding — on this machine, cp932 . So this line data = json . load ( sys . stdin ) decodes UTF-8 bytes as cp932. 2. Mojibake does not raise. That is the whole problem. cp932 is permissive enough that UTF-8 bytes map onto some sequence of characters. You do not get a UnicodeDecodeError you can catch and log. You get a string that is merely wrong, and it flows onward as valid data: 'C:\\...\\self-catering\\_\udc85部\\再開メモ.md' ← what the guard actually rec
AI 资讯
Reading .xlsx in the browser without a spreadsheet library
I run a small site that converts bank CSV exports into the file format QuickBooks Desktop accepts. The whole thing runs client-side, and the privacy claim it makes is unusually literal: every page ships a Content Security Policy with connect-src 'none' , so the browser refuses to let the page make any network request at all. Open the Network tab while you convert a file and it stays empty. That's the feature, not a nice-to-have on top of it. When I added Excel support last week, the obvious choice was SheetJS. I decided against it, and the reason wasn't bundle size. The claim I want to be able to make is "your file never leaves the browser, and here is the policy that enforces it." Pulling in a large third-party parser turns that into "…and also trust this dependency," which is a materially weaker claim for a tool that handles people's bank statements. So I wanted to find out how much of the format I actually needed. Less than I expected. An .xlsx file is a ZIP archive containing XML: xl/workbook.xml lists the sheets, xl/worksheets/sheet1.xml holds the cells, xl/sharedStrings.xml is a deduplicated string pool that cells reference by index, and xl/styles.xml carries the number formats. Reading that needs three capabilities, and the browser already provides two of them. Unzipping means walking the ZIP central directory, which is about forty lines. Decompression is DecompressionStream('deflate-raw') , which is native. For the XML I hand-rolled a tag scanner rather than reaching for DOMParser , because my tests run in Node where DOMParser doesn't exist, and I would rather have one code path than two. Dates The part that took the most care was dates, because Excel doesn't store them as dates. A cell holding 5 January 2024 contains the number 45296 , and whether that number should be displayed as a date depends on the cell's number format — which lives in a different file inside the archive. So the parser has to read styles.xml , work out which style indexes correspond to
AI 资讯
Building "112 for Dogs": How I Combined Gemini AI, Solana, and Voice Agents to Save Strays
This is a submission for Weekend Challenge: Dog Days Edition What I Built PawID & Care is an enterprise-grade, multi-role emergency response and biometric identification platform built for community animal welfare and stray management. Operating as a "112-for-dogs" system, the platform bridges cutting-edge artificial intelligence, distributed ledgers, enterprise analytics, and autonomous voice agents into a single unified workflow. The core goal is to solve the fragmentation in animal rescue: pet owners lose dogs, street animal injuries go unreported, and cities lack real-time community health tracking. PawID & Care provides instant biometric triage, role-based portals for Owners, Rescuers, and Vets, and real-time emergency voice dispatching. Demo 📹 Watch the Demo Video: https://youtu.be/_B-2dL2fDX4 Code GitHub Repository: [ https://github.com/GamersStop/paw-id-care ] bash # Clone the repository git clone [https://github.com/GamersStop/paw-id-care](https://github.com/GamersStop/paw-id-care) # Install dependencies npm install # Start the server npm start
AI 资讯
web page hosting
How to Host a Website Using GitLab Pages If you have a website made with HTML and CSS, you can host it for free using GitLab Pages . GitLab Pages takes the files from your GitLab repository and publishes them as a website. For this, you need to create a .gitlab-ci.yml file. This file tells GitLab how to deploy your website. After pushing the file to your repository, GitLab creates a pipeline. When the pipeline finishes successfully, GitLab Pages gives you a URL which you can open in a browser to see your live website. Understanding the Pipeline A pipeline is the process GitLab uses to run the instructions written in .gitlab-ci.yml . If the pipeline fails, the website will not be deployed correctly. Sometimes the pipeline can fail because of an invalid YAML file, incorrect indentation, or a problem in the deployment commands. Another common problem is trying to create a public folder when the folder already exists. For a simple HTML and CSS website, the important thing is that the public folder contains your website files and index.html should be directly inside it. For example, the structure should look like this: public/ ├── index.html ├── style.css └── images/ The index.html file is important because it is the main page GitLab Pages looks for when someone opens the website. Hosting More Than One Website You can host multiple websites using GitLab Pages, but if the websites are completely different projects, it is better to create a separate GitLab project for each website . For example, you can have one project called youtube-clone and another project called portfolio . Each project can have its own HTML, CSS, .gitlab-ci.yml , pipeline and Pages deployment. This makes the projects easier to manage and prevents one website from affecting another website. So, GitLab is not only a place to store your code. With GitLab Pages and CI/CD pipelines, you can also use it to turn your HTML and CSS project into a live website that can be accessed through the internet.
AI 资讯
Caninography
This is a submission for Weekend Challenge: Dog Days Edition I built Caninography, a small digital archive for exploring dog breeds from around the world. I wanted it to feel more like a digital museum than a normal dog website. You can explore breeds, their origins, history, countries, characteristics and connections between them. The whole design is dark, clean and visual. I also kept it silent, so there is no distracting audio or player UI. Live Demo: canonigraphy.vercel.app GitHub: https://github.com/maisamabbas0323/canonigraphy.git How I Built It I built it with React, Vite and TypeScript. For the visual side, I focused a lot on typography, photography, smooth transitions and responsive layouts. I also added an interactive world atlas and a constellation-style view to explore breed relationships. For the content, I used Google Gemini to help create short and interesting breed information. I didn't wanted to make another chatbot. Instead, Gemini stays behind the experience and helps make the archive content more rich while people simply explore it. Prize Categories Best Use of Google AI Caninography is submitted for Best Use of Google AI. I used Google Gemini to generate concise, breed-specific information based on the archive data. The idea was to use AI in the background, not put a chatbot in front of the user. Built With React Vite TypeScript Google Gemini CSS SVG Canvas A Little About The Idea I always felt dog breed information is mostly shown as simple lists. So I thought: What if a dog archive felt like a museum? That small idea became Caninography. A place to explore their stories, origins and history — one breed at a time.
AI 资讯
I verified 51 sets of US tax rules by hand and turned them into a static site
Run the same salary through three different paycheck calculators and you'll get three different answers. None of them explain why. That bothered me enough to spend three weeks building an alternative. The result is payculate.org — a paycheck calculator for all 50 US states and DC where every deduction line opens up and shows its own arithmetic . The interesting problem wasn't the code The tax math itself is straightforward: progressive brackets are a loop, FICA is two multiplications with a cap. I had a working federal calculator in an afternoon. The hard part was that every state is a special case , and a generic model breaks on most of them: Wisconsin has a standard deduction that shrinks as you earn more — it starts at $13,230 and falls by 12 cents per dollar above a threshold, reaching zero around $126,000. Alabama lets you deduct your entire federal income tax before calculating state tax. The more federal tax you pay, the less Alabama income you have. Utah looks flat at 4.5%, but gives a taxpayer credit that phases out with income — so the effective rate climbs while the headline rate never moves. Ohio taxes nothing on the first $26,050, then a flat 2.75%. South Carolina rewrote its entire income tax in March 2026: six brackets became two (1.99% / 5.21%), and the federal standard deduction was replaced by a state-specific deduction that phases out above $40,000 of AGI. That last one I only caught during a routine data check last week. Most calculators I checked are still showing the old six-bracket system. The lines nobody counts The bigger discovery was what national calculators leave out entirely: employee-paid state payroll premiums . Washington charges no income tax at all. But Paid Family & Medical Leave (0.807%) and WA Cares (0.58%, uncapped) still take about $1,040 a year from a $75,000 salary . Most tools show $0 on that line. California's SDI lost its wage cap in 2024 and now takes 1.3% of every dollar — on a $200,000 salary that's $2,600 that appears
AI 资讯
How Do I Send Password Reset Emails from a Backend App Using an Email API?
Here's the full flow the way I've built it, using Notify as the email API. The shape of this is the same regardless of which provider you pick — generate a token, send a link, verify it on submit — so most of this applies no matter what you're using; I'll flag the one part that's specific to Notify. The Flow, End to End User requests a password reset Your backend generates a secure, short-lived reset token Your backend stores a hashed version of that token Your backend sends an email with the reset link, through an email API User clicks the link and submits a new password Your backend verifies the token, updates the password, and invalidates the token Step 1: Generate the Reset Token Use a cryptographically secure random value, not anything guessable, and store only a hashed version in your database — if your database ever leaks, the raw tokens aren't exposed alongside it: const crypto = require ( ' crypto ' ); function generateResetToken () { const token = crypto . randomBytes ( 32 ). toString ( ' hex ' ); const tokenHash = crypto . createHash ( ' sha256 ' ). update ( token ). digest ( ' hex ' ); return { token , tokenHash }; } Give it a short expiration — 15 to 60 minutes is typical. Step 2: Build the Reset URL https://yourapp.com/reset-password?token=RESET_TOKEN The token goes in the link the user clicks; the hash is what you store and check against later. Step 3: Send the Email This is the Notify-specific part. There's no SDK to install — it's a single HTTP request with your API key in the header: async function requestPasswordReset ( email ) { const user = await findUserByEmail ( email ); // Don't reveal whether the email exists if ( ! user ) return ; const { token , tokenHash } = generateResetToken (); const expiresAt = new Date ( Date . now () + 1000 * 60 * 30 ); // 30 minutes await saveResetToken ( user . id , tokenHash , expiresAt ); const resetLink = `https://yourapp.com/reset-password?token= ${ token } ` ; await fetch ( ' https://notify.cx/api/email/send
AI 资讯
🐾 PawSafe: An AI-Powered Food Safety Checker for Dogs
This is a submission for Weekend Challenge: Dog Days Edition What I Built PawSafe is an AI-powered web application that helps dog owners answer a simple but important question: "Can my dog eat this?" Users can enter the name of a food, upload a photo, or provide both. PawSafe then analyzes the information using Google's Gemini API and provides a simple safety assessment. The result is categorized into four levels: 🟢 Generally Safe 🟡 Use Caution 🔴 Not Safe ⚪ Unable to Determine Along with the result, PawSafe provides explanations, potential warnings, and safer alternatives when appropriate. My goal was to build something that was useful, simple to understand, and approachable for dog owners rather than making users search through multiple sources every time they encounter an unfamiliar food. Demo Live Demo Code GitHub Repository How I Built It PawSafe is a full-stack application built with: Frontend React Vite Tailwind CSS Lucide React Backend Node.js Express Multer CORS Google Gemini API Deployment Render GitHub The basic flow looks like this: User ↓ Food name / Image / Both ↓ React Frontend ↓ Express API ↓ Google Gemini ↓ Structured Analysis ↓ PawSafe Result Card One of the main technical decisions I made was to keep the Gemini API integration on the backend rather than exposing the API key in the frontend. The frontend sends the user's food information to the Express API. The backend then communicates with Gemini and returns the structured analysis to the frontend. I also wanted the application to support both text and images independently, while still allowing users to provide both when additional context is useful. Prize Categories Best Use of Google AI PawSafe is submitted for the Best Use of Google AI prize category. Google's Gemini API is the core intelligence behind the application. It is used to analyze both text-based and image-based food information and generate a structured safety assessment. The AI response is then presented through PawSafe's interface
AI 资讯
I run a surf forecast for 20 breaks in Morocco on EUR 0/month. Here's the stack.
I live on the Taghazout coast in Morocco - a strip of Atlantic between Agadir and Imsouane that's basically one long right-hand point break after another. Two years ago the only way to know if tomorrow was worth it was to check three different global forecast sites, none of which knew the difference between Anchor Point and the beach break 400m south of it. So I built taghazout.io . It now covers 20 named breaks, runs in 10 languages, and costs me nothing per month. Here's how it's actually put together - including the parts I'd do differently. The stack is deliberately boring Hand-rolled PHP. No framework, no build step, no node_modules. About 4,800 files, server-rendered, no hydration. That sounds like a confession, but it was the right call for one reason: my readers are on phones, on cafe Wi-Fi, often on 3G. A server-rendered page that ships HTML and a little CSS beats anything I could have built with a client-side framework in that environment. Time-to-content is the only metric that matters when someone is standing on the beach deciding whether to paddle out. The hosting is a cheap shared plan. The forecast data is free and open. The whole thing runs at EUR 0/month recurring , which was a hard constraint from day one. The interesting part: two ocean models that disagree The forecast blends two sources: Open-Meteo (CC BY 4.0) - the primary, with a marine endpoint that covers our coastal cells. NOAA WaveWatch III via PacIOOS - the second opinion. Here's the thing nobody tells you: they disagree, a lot. On the same hour at the same break I've seen WaveWatch read ~55% higher than Open-Meteo (1.36m vs 0.88m). Offshore models resolve coastal bathymetry badly, and our points are exactly the kind of close-in, shallow-reef setups where that bias shows up. The wrong fix is to pick one and pretend. What I did instead: Run both, cache both. Compute agreement over a 72-hour window - a Pearson correlation on the swell rhythm plus a circular difference on direction (you can'
AI 资讯
One terminal, two trust levels — running Claude Code against a real subscription and a cheap proxy
Part of an ongoing series on model routing and trust tiering for agentic coding tools. This one's the boring, working half — no bug hunt, just a setup that's been running clean across two machines. The problem Claude Code does one thing well: careful, scoped edits with a real plan-then-execute loop behind them, backed by a subscription you're already paying for. Not every task needs that. Exploratory reads, "summarize this directory," draft-and-discard scratch work — most of that doesn't need the most capable model watching every token. The fix is a second, cheaper backend for that category of work. The catch: Claude Code only speaks Anthropic's Messages API. It has no built-in notion of "same tool, different model." So the question is how to point it somewhere else without giving up the interface. The stack Trusted agent: claude — real Anthropic subscription, default session Cheap agent: claude-cheap — same CLI, routed through a self-hosted proxy Proxy: LiteLLM, translating Anthropic-format requests to DeepSeek V4 (pro for Sonnet-tier calls, flash for Haiku-tier) served through an OpenRouter API Transport: a persistent SSH tunnel from a small VPS back to each machine The proxy itself wasn't new. It's the same LiteLLM instance already routing a separate content pipeline I run. The actual work here was wiring Claude Code to it: a shell function and a few environment variables. The core trick and it took me a few week to learn this is to point ANTHROPIC_BASE_URL at LiteLLM's /v1/messages endpoint, not the OpenAI-compatible path LiteLLM also exposes. Claude Code only understands the Anthropic shape, so the OpenAI-shaped endpoint fails in ways that look like a client bug and aren't. Once LiteLLM sits on the right endpoint and translates underneath, Claude Code has no idea it isn't talking to Anthropic. The one bug worth flagging Claude Code's Plan Mode attaches a context_management parameter to its requests. Anthropic's API handles it. Most other backends don't recogniz
AI 资讯
😸Catbot Integration, AI Office, Cat Mode (AI Avatar v17: VS Code and Chrome Extension)
Intro AI Avatar is a free app where your VRoid (VRM) avatar cheers you with all its might .🤗 It lives in your VS Code sidebar (reacts to Claude Code / GitHub Copilot) or browser side panel (reacts to ChatGPT / Claude). Animations and speech bubbles all run without AI too. This time I have three main topics. 🤝Catbot Integration 🏢AI Office 😺Cat Mode Let's see how they are! Catbot Integration I was asked to collaborate with my DEV Community friend @annavi11arrea1 Catbot . Catbot is A galactic robot cat you can talk to from any device — and a harness that lets you switch between (or combine) all of your AI models. https://github.com/AnnaVi11arrea1/catbot I was happy about this offer because I loved Anna's creativity and cool designs. I added the features below to AI Avatar to integrate Catbot. Launch Cat button: With this button, AI Avatar can run Catbot. Catbot with button: This makes Catbot stay beside AI Avatar. Cat Boss button: This changes the AI Office boss from a VRM avatar to Catbot. Cat Mode Many people feel that animals are healing and soothing. It is close to the AI Avatar concept of cheering people up. So I decided to add Cat Mode . I added the features below to make it look like a cat. Cat-like text, "Meow/Purrr" in English and "にゃ~" in Japanese Cat emojis Cat pose animations A new avatar with cat ears and cat whiskers. To tell the truth, the hardest part of making this mode was adding whiskers to the avatar using Blender . I can do basic things in Blender, but it is too difficult for me, even with the help of AI, just to add whiskers. It would be more fun if I added other animal modes too. AI Office AI Avatar displayed only one avatar. I thought it could do more things if it displayed several avatars at once. So I added AI Office mode. Two avatars are displayed and talk and move around when idle, and they also make a communication animation when using AI or clicking. I made one avatar a boss and one a worker. The hard part of making this mode was the timin
AI 资讯
Banx Walk Safe: same sidewalk, two heat loads
This is a submission for the DEV Weekend Challenge: Dog Days Edition . What I Built Same sidewalk. Two bodies. Two completely different heat loads. Banx is my French Bulldog. Born October 5, 2022. He weighs 35 pounds — seven above the 28-pound ceiling in the French Bull Dog Club of America conformation standard. I call him my XL. He is purebred and he has never had airway surgery. The face that makes him Banx is also the conformation that puts French Bulldogs at higher risk of obstructed breathing and heat-related illness. Dogs cool themselves mostly by panting. Flat-faced dogs can do it less efficiently, and how much varies a lot between individual dogs. So the same afternoon — same sun, same pavement, same humidity — is a walk for one dog and something else entirely for him. Nothing on the outside tells you that. Enter a location. It pulls temperature and humidity, computes a heat index, and shows the load on a flat-faced dog beside a longer-muzzle dog across the day. Then it helps me think through the question I actually have when he's standing at the door: how stressful do the conditions look right now, how does that change with activity, and when does the environment get more favorable? It does not medically answer that for him, and the section below says exactly why it can't. Demo Live: https://banx-walk-safe.vercel.app Geolocation or city search. Works if you deny location. No API key. Code Vanilla HTML / CSS / JS. No framework. Repo is the project folder on the machine that built it; the production artifact is the Vercel deploy above. Weather: Open-Meteo . Heat index: NOAA/NWS Rothfusz / Steadman family. Why I Built It When I first got him I didn't know how any of this worked. We started at Ledge Street Park in Nashua and took the trails toward Main Street. First ten minutes he's got everything — all over the place, into everything, full Banx. Then he changes. He stops being all over it and starts just observing. Walking straight forward, taking it in, calm.
产品设计
PawMatch: Finding the Dog That Matches Your Personality 🐾
This is a submission for Weekend Challenge: Dog Days Edition What I Built Dogs have...
AI 资讯
What are you working on? #01
What are you working on? I hear these words in my day-to-day. And sometimes, when I hear them, there’s this little brain freeze that happens because my brain is probably trying to put into words the amount of things that have wandered through my head in the last 24 hours. 😂 So I thought, okay, let me try something. I want to take some of those wandering thoughts, explorations, things I'm trying out and things I'm learning, and put them into writing. This is going to be a series where I come and talk about what I'm working on — software engineering, product, work, people, faith, relationships, rest, and whatever else happens to be taking up space in my head at the moment. So, what am I working on? I recently started writing backend code, and there’s a bit of a backstory to that. I built this frontend commerce store years ago where people can come and shop for furniture. At the time, I used a backend-as-a-service to handle the backend side of the application. Now, I’m coming back to that same system and writing the backend myself with NestJS. I wanted to go beyond just consuming a backend and actually understand what is happening behind the scenes. The learning process is a bit stretching at the moment because I’m getting familiar with a lot of new concepts. Tiring and frustrating? Yes. But the feeling when I finally understand the reason behind something is always refreshing. That has been really rewarding lately. I'm also in the middle of launching a mobile application at my workplace, going through system design classes, figuring out how to get the best out of my engineers (AI sub-agents, by the way 😅), and occasionally imagining that dream job where you get to build products that serve millions of people and work with really brilliant minds. Also, I discovered the productivity rush that comes with using large monitors. 😂 Then there's learning how to rest while also trying to close out all the open loops in my head. Building reading habits. Figuring out what to pri
AI 资讯
Our AI Persona Passed Every Test, Then Started Doing Code Reviews
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. A quick note...
AI 资讯
Designing a referral system that can't be gamed by throwaway accounts
I just shipped a referral system for Adsyte , my free directory for indie projects, and the design decision behind it is worth sharing because it's a pattern that applies to any growth loop with a token reward attached. The obvious version, and why it's broken The naive implementation: give the recruiter tokens the moment someone signs up through their link. Simple, but it has an exploit built in. Signing up costs nothing, and OAuth makes throwaway accounts trivial. Anyone can self-refer through five Discord accounts and walk away with free reward tokens without bringing a single real user to the platform. What I did instead The payout only fires when the recruit publishes their first listing, not when they sign up. This one change closes the loop: A fake account costs nothing, but a real listing needs an actual project with a real URL The listing already has to pass duplicate-URL detection and hCaptcha, so faking one is meaningfully harder than faking a signup Every token paid out corresponds to a listing the directory actually gained, which is the metric that matters, not signups Implementation notes Referral code is an HMAC of the user's id, derived deterministically rather than stored as a random token, so there's nothing extra to generate or leak The code lives in a cookie set on landing ( ?ref=CODE ), read once at OAuth callback, and tied to the account via a Redis SETNX so it can only ever be set once, self-referral excluded outright Payout uses SETNX again on a per-recruit key so double-firing (retries, race conditions) can't double-pay A daily cap per recruiter stops a single compromised or bot-driven account from draining the reward pool in one sitting Nothing here is novel, it's the standard "pay for the outcome, not the action" principle, but I don't see it applied to referral systems as often as it should be. Most implementations I've seen reward signup because it's the easy event to hook into, and then bolt on fraud detection after the abuse shows up.