AI 资讯
How Be Recommended by Inithouse Scores AI Visibility 0 to 100 Across ChatGPT, Perplexity, Claude and Gemini
Your product might rank on page one of Google and still be invisible to AI. When someone asks ChatGPT "what's the best project management tool for small teams," does your product show up? For most SaaS companies under 50 employees, the answer is no. At Inithouse, we built Be Recommended to answer that question with a number: a single AI visibility score from 0 to 100 that tells you exactly where you stand across four major AI engines. Here is how the scoring works under the hood. What the score measures The Be Recommended score captures how often, how prominently, and how positively AI engines mention your product when users ask category-relevant questions. A score of 0 means no AI engine mentions you at all. A score of 100 means every tested prompt across all four engines names your product as a top recommendation. The four engines we test against: ChatGPT (OpenAI), Perplexity , Claude (Anthropic), and Gemini (Google). Step 1: Prompt generation We start by building a bank of 50+ real prompts that a potential customer would actually type into an AI assistant. These are not keyword-stuffed test queries. They mirror how real people ask for recommendations. For a CRM product, that looks like: "What CRM should a 10-person startup use?" "Best alternatives to Salesforce for small businesses" "Compare CRM tools with good API integration" "Which CRM has the best free tier in 2026?" We group prompts into three categories: direct (user names the product category), comparative (user asks for alternatives or comparisons), and situational (user describes a problem without naming a category). Each category tests a different signal: brand recognition, competitive positioning, and contextual relevance. Step 2: Multi-engine querying Each prompt gets sent to all four AI engines through their APIs. We capture the full response text, not just a yes/no for whether your product appeared. The raw responses go into a structured analysis pipeline. We run queries from neutral accounts with n
AI 资讯
How to Get Your First Tool Online
TL;DR - A finished app that only runs on one laptop is a private demo. Getting it online means connecting three things: a place to store the code (version control), a place to run it (a host), and an address people can type (a domain). The same AI tool that helped build the app can walk a beginner through all three, often without ever opening a terminal. An important step you don’t want to skip is the security check before going live, because the fastest way to ruin a launch is to ship with the database wide open. So you’ve done it. You built your first tool. And it works. The button does the thing. Now’s the moment. It’s time to get your tool online, but how? A project running on a laptop is real, but it lives in exactly one place, the machine it was built on. Nobody else can open it. Getting that project online is its own small skill, separate from building, and it trips up more beginners than the building did. A new coder can finish a working photo booth app in an afternoon and still have no idea how to hand it to a friend short of pulling up the GitHub link while sitting together over coffee. The good news is that the part that used to eat a whole weekend now takes a conversation. Three Things Every App Needs to Go Live Almost every deployment, whatever the tool, comes down to three things working together. Version control: This is a place to store the code and track every change made to it. For most people that means GitHub, which we’ve talked about before. The same way Google Docs keeps a version history, GitHub keeps one for a project. This piece does not re-explain it; the GitHub walkthrough covers the whole thing. A host: A host is really just a computer that stays powered on and connected to the internet with a public address of its own. When a visitor types in the app's address, their browser sends a request across the internet to that machine, the machine runs the code, and it sends the finished page back. A laptop was quietly doing both jobs during the
AI 资讯
You don't need NextJS: here's why
This is the public, sanitized version of an internal proposal I wrote to move our production app off Next.js. Next.js is the default answer to "I want to build a React app." It's a great framework. But default and necessary aren't the same word. The gap between them quietly cost us speed, debuggability, and a surprising amount of cross-team friction. We were building an authenticated, data-heavy product: dashboards, filters, charts. Almost every screen lived behind a login and updated in response to clicks. For that shape of app, server-side rendering wasn't buying us much, and it was charging us a lot. First, the only question that matters The right architecture depends on what you're building. Content-first: Marketing sites, blogs, storefronts, docs. Mostly public, SEO matters, lots of static content. SSR/SSG is a genuinely great fit. Use Next.js. Seriously. Application-first: Internal tools, dashboards, admin panels, SaaS consoles. Behind auth, highly interactive, bottlenecked by your API and DB — not by React rendering. Put an application-first product on a content-first framework and you pay for machinery you never use. That was us. What SSR actually cost us Production debugging got harder Server-rendered errors don't map cleanly to the components you wrote, so root-causing took longer every single time. Client-side, the error happens in the browser with a stack trace that points at your component. Boring and fast to fix. Server components fought our tests You can't cleanly unit test a server component that renders other server components. Tools like React Testing Library expect renderable elements, not the serialized output a server component produces. We ended up making design choices purely to stay testable. Tail wagging the dog. Authentication became a distributed-systems problem This was a big one. If you gate protected pages on the server, the server must read and validate the token on every request, then propagate auth state through hydration. That singl
AI 资讯
Stop Hand-Designing Open Graph Images: Automate Link Previews for Every Page
Open Graph images are the single biggest factor in whether your shared links look credible or broken. Yet most sites ship one generic image on every page because making a unique one by hand is tedious. Here is a more sustainable approach: treat preview images as generated data, not hand-made design. The problem, concretely When you share a link, the receiving platform reads your page's og:image meta tag and renders a card. If that tag is missing, points to a low-res logo, or is the same image on all 200 pages, your links look generic in every feed, Slack channel, and group chat. Studies of social sharing consistently show that posts with a clear, relevant preview image get meaningfully more engagement than those without. The reason teams skip it is not ignorance. It is friction. Opening a design tool, duplicating a template, swapping the title text, exporting at the right dimensions, and uploading the file takes 10 to 20 minutes per page. Nobody keeps that up across a real publishing schedule. So the back catalog stays bare and new posts get whatever the default is. The insight: it is template work Look at a typical preview card and ask what actually changes between pages. Usually just the title, maybe the author and a category tag. The layout, background, logo, and fonts are constant. That is the textbook definition of a job you should template once and generate programmatically, not redo by hand each time. How to solve it The cleanest pattern is to generate the image at build time or on first request, then cache it. Conceptually: // During your build or in an API route async function getOgImage ( post ) { const params = new URLSearchParams ({ title : post . title , author : post . author , tag : post . category , }); // Returns a ready Open Graph image URL return `https://getcardforge.dev/api/card? ${ params } ` ; } // In your page head // <meta property="og:image" content={getOgImage(post)} /> You can build this yourself with a headless browser plus an HTML templ
AI 资讯
How I built a Minecraft server list that ranks by real player votes (not bots)
Hi, I'm Hugo. I built MinecraftServers-List.com — a Minecraft server directory that ranks servers by genuine player votes and uptime. Why I built it Most existing Minecraft server lists have the same problem: the rankings are easily gamed. Server owners run scripts to inflate their vote counts, and players searching for a good server end up with a list that reflects who has the best bots, not which servers are actually worth playing on. I wanted to fix that. What makes it different Vote integrity — votes are tied to real player sessions and IP validation, making bot voting significantly harder Uptime monitoring — servers that go offline lose ranking visibility automatically Player reviews — verified players can leave reviews with star ratings, giving prospective players real signal Java & Bedrock — both editions listed and filterable by gamemode, version, and country The tech stack Built with TanStack Start (React SSR), Supabase for the database, and deployed on Cloudflare Workers. The SSR approach was important for SEO — server listing pages need to be fully rendered for Googlebot to index individual server pages properly. What I've learned so far Getting a new directory site indexed by Google is genuinely hard. The challenge isn't technical — it's convincing Google that hundreds of server listing pages are individually worth indexing when they all share a similar template structure. The solution has been enriching each server page with structured data (VideoGame schema with AggregateRating), genuine user reviews, and making sure every page has a meaningfully unique meta description generated from real server data — version, gamemode, player count, country. Still a work in progress but the site is live, servers are actively listed, and players are voting daily. Try it If you run a Minecraft server, you can list it free at https://minecraftservers-list.com If you're looking for a server to join, the SMP list and survival list are good starting points. Happy to answe
AI 资讯
Your structured data is probably broken, and your crawler isn't telling you
Most on-page audits catch the obvious stuff: a missing title here, a duplicate meta description there. The thing that quietly costs you rich results is structured data that exists but is invalid, and most flat-list crawlers either skip it or bury it. Here is why it happens and how to catch it. The problem, concretely You add FAQ schema to a product page to win that expandable rich result in Google. You paste a JSON-LD block into the head, ship it, and move on. Six weeks later the rich result never showed up, and nobody knows why. The usual culprits are small and silent: A @type that does not match the content (FAQPage with no mainEntity ). A required property missing ( acceptedAnswer without text ). A trailing comma or a stray character that makes the JSON parse fail entirely. Schema that contradicts what is actually on the page, which Google can flag as spammy and ignore. None of these throw a visible error. The page renders fine. The schema is just dead weight, and a standard "issues" crawl that only counts titles and headings walks right past it. How to catch it First, validate the JSON itself. A block that does not parse is invisible to search engines. Even a quick local check surfaces the dumb-but-fatal errors: // Pull every JSON-LD block and check it parses + has a @type const blocks = [... document . querySelectorAll ( ' script[type="application/ld+json"] ' )]; blocks . forEach (( b , i ) => { try { const data = JSON . parse ( b . textContent ); if ( ! data [ " @type " ]) console . warn ( `Block ${ i } : missing @type` ); } catch ( e ) { console . error ( `Block ${ i } : invalid JSON ->` , e . message ); } }); If that logs an error, the schema was never going to work, no matter how perfect the markup looked. Second, check required properties for the specific type you are using. FAQPage needs mainEntity with Question items, each carrying an acceptedAnswer . Article needs headline , author , and datePublished . Validating "it parsed" is not the same as "it is c
AI 资讯
The New Standard for NPM Package Discovery: Deep Dive into LibPilot
As web developers, engineering workflows are heavily dependent on the NPM registry. However, the traditional process of searching, auditing, and integrating packages remains highly fragmented. Developers are routinely forced to hop between npmjs.com, GitHub source repositories, and external documentation tabs simply to verify bundle sizes, check dependency trees, or generate setup boilerplate. Following a strong reception on LinkedIn, X, and Facebook, the Motion Mind Team has introduced LibPilot to the dev.to community. LibPilot is not a traditional registry interface; it is an AI-powered search engine and discovery hub engineered to index, track, and analyze over 4,000,000 NPM packages in real time. Here is an architectural breakdown of how LibPilot restructures package exploration for modern developers and autonomous AI code agents. Intent-Based Discovery and Global Search Architecture Traditional search engines require users to input the exact name or strict keyword of a library. LibPilot introduces a dual-input architecture on its home page to eliminate this constraint: Direct Registry Querying: Users can input full or partial package names into the global search bar to instantly surface clean, structured, and typed suggestions directly from the live NPM ecosystem database. Contextual AI Recommendations: For scenarios where the ideal package is unknown, developers can type out a complete description of their project architecture or system constraints (for example: "a lightweight, typed state management engine that handles server-side rendering natively"). LibPilot's internal AI agent processes the functional requirements and suggests production-ready libraries suited for that stack. Continuous Context AI and Interactive Onboarding A core goal of the platform is reducing developer friction and maintaining deployment momentum. LibPilot transitions static package documentation into an interactive environment: Unlimited AI Chat Architecture: Once a library is select
AI 资讯
Legacy code não envelhece como vinho: quanto mais espera, pior fica
Semana passada eu passei três horas debugando um bug que deveria levar 20 minutos. O problema? Um módulo de validação escrito em 2019 que ninguém mexe "porque funciona". Spoiler: não funcionava mais, e quando finalmente abri o arquivo, encontrei um // TODO: refactor this datado de 2020. Por que legacy vira bola de neve A indústria trata código legado como se fosse dívida técnica opcional — algo que você paga "quando tiver tempo". Mas código legado se comporta mais como mofo: se espalha, contamina áreas adjacentes, e quanto mais você ignora, mais cara fica a limpeza. O ciclo é previsível: você herda um projeto ou feature antiga, vê que está "meio bagunçado mas roda", adiciona sua feature com um if a mais, e segue em frente. Seis meses depois, outra pessoa faz o mesmo. Um ano depois, aquele arquivo tem 800 linhas, cinco níveis de if aninhados, e zero testes. Ninguém mais entende o fluxo completo, então cada mudança vira uma sessão de especulação: "se eu mexer aqui, quebra ali?" O custo real de esperar Esse código "que funciona" tem um custo oculto que aparece em três formas: Velocidade de desenvolvimento despenca. Features que deveriam levar dois dias levam uma semana porque você passa mais tempo entendendo o contexto do que escrevendo código novo. Bugs aumentam exponencialmente. Código sem testes e com lógica embolada é um gerador de regressões. Você corrige um edge case e quebra outro que nem sabia que existava. Onboarding vira tortura. Novo dev no time? Boa sorte explicando por que aquele service tem três formas diferentes de fazer autenticação, ou por que a mesma validação está copiada em sete lugares. Sinais de que você está sentado em cima de uma bomba Nem todo código antigo é legacy tóxico. Aqui estão os red flags que indicam que você precisa agir agora: // Red flag #1: comentários mentirosos ou inúteis function processPayment ( order ) { // Process the payment const user = order . user ; // TODO: fix this later // HACK: don't touch this, breaks prod if ( user
AI 资讯
How to Fetch Real-Time Options Chain Data in Python (Without Paying $99/mo)
If you've ever tried to pull live options data into a Python script, you've probably hit the same wall I did: the cheapest real-time providers start at $99/mo. Here's how to do it for $20/mo — or free if you stay within 1,000 credits/day. What You'll Need Python 3.8+ requests library ( pip install requests ) An API key from market-option.com (free tier available, no card required) Fetching a Full Options Chain import os import requests API_KEY = os . environ [ " MARKET_OPTIONS_KEY " ] BASE_URL = " https://market-option.com/api/v1 " def get_chain ( ticker : str ) -> list [ dict ]: res = requests . get ( f " { BASE_URL } /options/chain/ { ticker } " , params = { " apiKey " : API_KEY }, ) res . raise_for_status () return res . json ()[ " results " ] contracts = get_chain ( " SPY " ) print ( f " { len ( contracts ) } contracts returned " ) print ( contracts [ 0 ]) Each contract in results looks like this: { "details" : { "contract_type" : "call" , "strike_price" : 530 , "expiration_date" : "2026-01-17" , "ticker" : "O:SPY260117C00530000" }, "last_quote" : { "bid" : 3.45 , "ask" : 3.50 , "midpoint" : 3.475 }, "greeks" : { "delta" : 0.42 , "gamma" : 0.031 , "theta" : -0.18 , "vega" : 0.29 }, "implied_volatility" : 0.182 , "open_interest" : 12418 } Filtering by Expiration and Strike def get_near_the_money ( ticker : str , expiration : str , spot : float , width : float = 0.05 ): """ Return contracts within ±width% of spot price. """ contracts = get_chain ( ticker ) low = spot * ( 1 - width ) high = spot * ( 1 + width ) return [ c for c in contracts if c [ " details " ][ " expiration_date " ] == expiration and low <= c [ " details " ][ " strike_price " ] <= high ] atm = get_near_the_money ( " SPY " , " 2026-01-17 " , spot = 530 ) for c in atm : print ( c [ " details " ][ " strike_price " ], c [ " details " ][ " contract_type " ], c [ " last_quote " ][ " bid " ], c [ " greeks " ][ " delta " ], ) Scanning for High IV Contracts def high_iv_scan ( ticker : str , iv_threshold :
AI 资讯
Stokado: A Zero-Dependency Proxy Wrapper That Makes Browser Storage Feel Like a Plain Object
If you've shipped anything to the browser, you've used localStorage . And if you've used it for more than five minutes, you've also written this exact line more times than you'd like to admit: const user = JSON . parse ( localStorage . getItem ( ' user ' ) || ' null ' ) The Web Storage API has aged remarkably well for something so small, but it carries three persistent pain points that every frontend codebase ends up papering over by hand. Pain point #1: everything is a string. localStorage.setItem('count', 0) doesn't store the number 0 — it stores the string "0" . Read it back and typeof is "string" . Booleans become "true" / "false" , Date objects collapse into ISO strings (if you're lucky) or "[object Object]" (if you're not), and undefined becomes the literal string "undefined" . So every project grows a thin serialization layer of JSON.parse / JSON.stringify wrappers, plus a pile of defensive try/catch blocks for the day a malformed value sneaks in. Pain point #2: the API is verbose and stringly-typed. getItem , setItem , removeItem — three method calls and a string key for what is conceptually just reading and writing a property. It reads nothing like the rest of your code. Pain point #3: reactivity is broken in the tab you actually care about. The native storage event only fires in other tabs of the same origin. The tab that performed the write never hears about it. So if you want to react to your own storage changes — the overwhelmingly common case — the platform gives you nothing. Stokado is a small, zero-dependency library that addresses all three by wrapping any storage object in a Proxy . It's framework-agnostic, TypeScript-friendly, and works equally well with localStorage , sessionStorage , cookies, async backends like localForage, and a handful of mini-program runtimes. This article walks through what it actually does, feature by feature, with runnable code. Quick start npm install stokado import { createProxyStorage } from ' stokado ' const storage =
AI 资讯
I ran one API response through two JSON-to-Zod converters. One silently turned every field into z.string().
You have an API response. You want a Zod schema. So you paste the JSON into a JSON-to-Zod converter, copy the output, and ship it. Here's the trap: a lot of those converters infer basic types only . Your email , your uuid , your url , your ISO timestamp — they all come out as z.string() . The schema compiles, the types look right, and your validator quietly accepts "not-an-email" , "ftp://nope" , and "2026-99-99" forever. I wanted to see exactly how much gets lost, so I ran the same payload through two tools and diffed the output. Everything below is real, copy-pasteable output — nothing edited. The input A pretty ordinary user object: { "id" : "3f2a9c1e-5b7d-4e8a-9f1c-2d3e4f5a6b7c" , "email" : "ada@example.com" , "website" : "https://ada.dev" , "age" : 34 , "rating" : 4.7 , "created_at" : "2026-03-04T10:15:30Z" , "is_active" : true , "address" : { "city" : "Lyon" , "zip" : "69001" }, "tags" : [ "early-adopter" , "beta" ] } Tool 1 — json-to-zod (npm) const user = z . object ({ id : z . string (), email : z . string (), website : z . string (), age : z . number (), rating : z . number (), created_at : z . string (), is_active : z . boolean (), address : z . object ({ city : z . string (), zip : z . string () }), tags : z . array ( z . string ()), }); Structurally correct. But every meaningful field is a bare z.string() / z.number() . This schema will happily validate email: "lol" and created_at: "yesterday" . Tool 2 — TypeMorph import { z } from " zod " ; export const userAddressSchema = z . object ({ city : z . string (), zip : z . string (). regex ( /^ [ A-Z0-9 ][ A-Z0-9 \s\-]{1,8}[ A-Z0-9 ] $/i ), }); export type UserAddress = z . infer < typeof userAddressSchema > ; export const userSchema = z . object ({ id : z . uuid (), email : z . email (), website : z . url (), age : z . number (). int (). min ( 0 ). max ( 150 ), rating : z . number (). min ( 0 ). max ( 5 ), created_at : z . iso . datetime (), is_active : z . boolean (), address : userAddressSchema , tags :
AI 资讯
TypeScript Tips That Actually Matter in Real Projects (including the satisfies operator)
Most TypeScript tutorials teach you the language. This article teaches you how to use it. There's a difference. The language has hundreds of features. A real project uses maybe twenty of them regularly, and about eight of them make up the difference between TypeScript that fights you and TypeScript that helps you. These are those eight. Each one comes from a pattern I've seen repeatedly in real codebases: first as an antipattern, then as a realization, then as a habit. The goal isn't to show off advanced type gymnastics. It's to show you the specific things that make your code safer, more readable, and less painful to maintain. TL;DR Most TypeScript pain comes from fighting the type system instead of working with it, any , manual casting, and loose types are the usual culprits. A small set of features, discriminated unions, utility types, satisfies , as const , generics, solve the majority of real-world typing problems. The best TypeScript isn't the most complex. It's the most precise. Table of Contents Tip 1: Use Discriminated Unions Instead of Optional Fields Tip 2: Stop Writing Types Twice with Utility Types Tip 3: Use satisfies to Validate Without Losing Inference Tip 4: Use as const for Literal Types That Don't Drift Tip 5: Write Type Guards Instead of Casting Tip 6: Use Generics to Write Functions Once Tip 7: Use ReturnType and Parameters to Stay in Sync Tip 8: Use unknown Instead of any for External Data Honorable Mentions Final Thoughts Tip 1: Use Discriminated Unions Instead of Optional Fields This is the tip that changes how you model data in TypeScript. Once you see it, you'll spot the antipattern everywhere. The antipattern // ❌ A type that tries to represent multiple states with optional fields interface ApiResponse { data ?: User error ?: string isLoading : boolean } The problem: this type allows impossible states. Nothing stops you from having both data and error set at the same time, or neither set, or isLoading: false with no data and no error . The
AI 资讯
Why I Stopped Picking AI Models by Hype and Started Picking by Speed
Why I Stopped Picking AI Models by Hype and Started Picking by Speed Three months ago I almost lost a $14,000 retainer because my chatbot felt sluggish. The client didn't say "your TTFT is too high." They said "it feels dumb." That's freelancer code for "users are bouncing and I'm about to find someone else." I rebuilt that bot in a weekend using a model I'd never even heard of six weeks earlier, dropped average response time from 1.4 seconds to under 300ms, and the client renewed for another six months. That single pivot paid for my rent. So I went down a rabbit hole. I ran the same speed test on every model I could get my hands on through Global API's unified endpoint. Fifteen models. Same prompt. Same regions. Ten iterations each. I'm writing this up because if you're billing by the hour or running a side hustle on a shoestring, speed isn't a vanity metric — it's a profit metric. Let me show you what I found. The Setup (How I Actually Ran the Tests) I'm not a researcher with a rack of GPUs. I'm a guy with a M2 MacBook, a $19/mo Hetzner box, and a stopwatch in the form of Python's time.perf_counter() . Here's how I kept it honest. Date window: All tests run on May 20, 2026 Regions tested: US East (Ohio) and Asia (Singapore) Prompt used: "Explain recursion in 200 words" — boring on purpose, because boring prompts are where most apps actually live Output length: Roughly 150 tokens per run Iterations: 10 runs per model per region, average recorded Streaming: Yes, SSE throughout Endpoint: Global API at https://global-apis.com/v1 I measured two things: TTFT (time to first token — the lag before the user sees anything move) and sustained tokens per second (how fast the words actually arrive after that). Both matter. TTFT is the "is this thing broken?" feeling. Tokens per second is the "is this thing fast?" feeling. Here's the script I used, stripped down to the essentials: import time import requests from statistics import mean API_KEY = " your-global-api-key " BASE_URL
AI 资讯
The SEC has a free financial data API that nobody talks about
Every quarterly earnings number for every US public company going back to 2009 is sitting in a free, well-documented JSON API run by the US government. No API key. No rate limit for normal use. No paywall. Almost nobody in the dev community seems to know it exists. It's at data.sec.gov , and it's the same data Bloomberg charges $24k/year for. What's in it The SEC requires all US-listed companies to file financial reports in XBRL — a structured XML format where every number is tagged with a standardised concept name. The EDGAR system has been collecting these since around 2009. The companyfacts endpoint exposes all of it as clean JSON: GET https://data.sec.gov/api/xbrl/companyfacts/CIK{cik}.json Where CIK is the company's SEC identifier (10 digits, zero-padded). For Apple, that's 0000320193 . The response is a large JSON object with every concept the company has ever reported, broken down by period. The other endpoint you need is the ticker-to-CIK map: GET https://www.sec.gov/files/company_tickers.json This gives you a flat list of all US-listed companies with their CIK, ticker, and name. Load it once and cache it. One gotcha: concept names vary by company Companies don't all use the same GAAP concept names to report the same thing. Apple reports revenue as RevenueFromContractWithCustomerExcludingAssessedTax . Older companies use Revenues . Some use SalesRevenueNet . If you just look up one concept name, you'll get blanks for most companies. The fix is a concept alias map: try each name in order, use the first one that has data. const CONCEPT_MAP : Record < string , string [] > = { revenue : [ ' Revenues ' , ' RevenueFromContractWithCustomerExcludingAssessedTax ' , ' RevenueFromContractWithCustomerIncludingAssessedTax ' , ' SalesRevenueNet ' , ' SalesRevenueGoodsNet ' , ], netIncome : [ ' NetIncomeLoss ' , ' NetIncomeLossAvailableToCommonStockholdersBasic ' , ' ProfitLoss ' , ], operatingCashFlow : [ ' NetCashProvidedByUsedInOperatingActivities ' , ' NetCashProvidedB
AI 资讯
MongoDB Indexes Finally Clicked for Me: Understanding Indexes, Compound Indexes & the Prefix Rule 🚀
While working on a MERN project, I came across these indexes: transactionSchema . index ({ user : 1 , date : - 1 }); transactionSchema . index ({ user : 1 , type : - 1 }); transactionSchema . index ({ user : 1 , category : - 1 }); My first reaction was: "Why are we creating 3 different indexes for the same schema? Isn't one index enough?" At that time, my understanding was: "Indexes help MongoDB find records faster." Which is true, but it wasn't enough to explain why multiple indexes existed for the same collection. That simple doubt led me down a rabbit hole of learning about indexes, compound indexes, how MongoDB stores them, and the famous Prefix Rule. Here's what I learned. What is an Index? Imagine a collection with millions of transactions. db . transactions . find ({ user : " Aarthi " }); Without an index, MongoDB may need to inspect every document until it finds the matching records. This is called a Collection Scan . Think of it like searching for a chapter in a book without a table of contents. You'd have to flip through page after page until you find it. An index works like a book's table of contents. Instead of scanning every document, MongoDB can jump directly to the relevant records. Example: db . transactions . createIndex ({ user : 1 }); Now MongoDB can quickly locate all transactions belonging to a specific user. What is a Compound Index? A compound index contains multiple fields. Example: db . transactions . createIndex ({ user : 1 , date : - 1 }); This means MongoDB organizes the index by: user └── date Conceptually, it looks something like: Aarthi 2025-08-10 2025-08-09 2025-08-08 John 2025-08-10 2025-08-05 The data is first grouped by user , and within each user, it is ordered by date . Now queries like: db . transactions . find ({ user : " Aarthi " }). sort ({ date : - 1 }); become very efficient. MongoDB can jump directly to Aarthi's records and retrieve them in date order. The Prefix Rule: The Concept That Finally Made It Click Consider this i
AI 资讯
10 Free PDF Tools Every Developer Should Bookmark in 2026
PDF work shows up in dev life more often than we'd like to admit — exporting docs, compressing build artifacts, merging client deliverables, or converting a spec sheet someone sent as a scanned PDF into something you can actually search. Paid suites like Adobe Acrobat are overkill for most of these one-off tasks. Here are 10 free, no-signup tools that get the job done, ranked roughly by how often you'll reach for them. 1. ToolTiny — PDF to Word/Excel/PowerPoint ToolTiny converts PDFs into editable DOCX, XLSX, or PPTX files directly in the browser, alongside the usual merge/split/compress/watermark/password toolkit. No account, no watermark on output. What's actually useful for dev workflows: it handles presentation-style PDFs (think exported slide decks or design-heavy one-pagers) reasonably well — most converters flatten these into a single unreadable text blob, but ToolTiny keeps the layout intact while still giving you editable text. Good for the "client sent a PDF, I need it as a Word doc by EOD" scenario. 2. Smallpdf The OG in this space. Smallpdf's PDF-to-Word conversion is excellent at preserving layout — it renders the page as a background image and overlays editable text boxes at the correct coordinates, which is why it handles complex layouts better than most. Free tier caps you at 2 tasks/day though. 3. iLovePDF Similar feature set to Smallpdf, slightly more generous free tier. Their "Organize PDF" drag-and-drop page reordering is one of the smoother UX implementations out there if you need to quickly reshuffle a multi-doc PDF before sending it out. 4. PDF24 A German tool that's been around forever and quietly does everything — OCR, forms, signing, comparison. Less polished UI than the others but the OCR accuracy on scanned technical docs is genuinely strong. 5. Stirling-PDF If you want something self-hosted, Stirling-PDF is the open-source answer. It's a Docker container you spin up yourself, giving you a full PDF toolkit (split, merge, compress, OCR, wa
AI 资讯
I got a merged PR into a YC startup before they ever replied to my job application
I applied to a YC W25 startup the normal way. Filled out the form, wrote a decent cover letter, hit submit. Silence. While waiting, I found their open-source repo on GitHub. Read through the codebase out of genuine curiosity I wanted to understand what they were actually building. Found a bug. Fixed it. Opened a PR. It got merged in 2 days. They still hadn't replied to my application. Here's what that taught me about job hunting in 2025: A cover letter tells someone what you claim you can do. A merged PR shows them. One of those gets read. The other gets filed under "maybe later" -which is just "no" with extra steps. I'm not saying cold applications are dead. I'm saying they're the last resort, not the first move. If a company has a public repo, you have a backdoor that most applicants don't even think to try. Read the code deep and find something small but real. Fix it and Open a PR. Now you're not a stranger in their inbox you're someone who already ships for them. The reply came eventually, by the way. But by then, the maintainers already knew my GitHub handle. That matters more than you think. Have you ever landed something through a contribution instead of an application? Drop it in the comments curious how many people have done this.
AI 资讯
Verify Nylas webhook signatures to trust your data
A webhook endpoint is a public URL sitting on the internet, and anything on the internet can send it a POST . If your app acts on whatever lands there, an attacker who guesses the URL can forge events: fake an inbound email, trigger a workflow, or feed your system garbage. The fix is to confirm two things before you trust a request, that you own the endpoint and that Nylas actually sent the payload, and both are built into how webhooks work. This post covers verifying webhooks from two angles: the HTTP mechanics your endpoint implements, and the nylas CLI for testing a signature without standing up a server. I work on the CLI, so the terminal commands below are the ones I reach for when I'm debugging a signature mismatch. Two layers of webhook trust There are two separate checks, and they happen at different times. The first is a one-time endpoint challenge: when you register or activate a webhook, Nylas sends your URL a request with a challenge value you echo back, proving you control the endpoint. The second runs on every notification afterward: each delivery carries a cryptographic signature you verify against a shared secret, proving the payload is genuine and wasn't tampered with. You need both because they defend against different things. The challenge stops you from accidentally registering an endpoint you don't own and confirms the URL is live. The signature stops anyone else from posting forged events to that URL once it's known. Skip the signature check and your public endpoint will trust any POST that reaches it, which is the most common webhook security mistake. Pass the endpoint challenge The first time you set up a webhook or flip one to active , Nylas sends a GET request to your endpoint with a challenge query parameter. Your endpoint has to return the exact value of that challenge in the body of a 200 OK response, within 10 seconds, or the webhook won't verify. It's a quick handshake that proves the URL is yours and reachable. // Express: echo the ch
AI 资讯
GEO: Wie du dafür sorgst, dass ChatGPT & Co. deine Seite zitieren
Dein bestes Google-Ranking ist wertlos, wenn die Antwort schon vor dem Klick gegeben wurde. Genau das passiert gerade: Nutzer fragen ChatGPT, Claude oder Perplexity – und bekommen eine fertige Antwort mit drei, vier zitierten Quellen. Bist du nicht darunter, existierst du in diesem Moment nicht. Kein Ranking, kein Klick, keine zweite Chance. Die Disziplin, die das adressiert, heißt Generative Engine Optimization (GEO) . Und sie ist – anders als der Marketing-Lärm vermuten lässt – zu großen Teilen ein Engineering-Problem. Crawler-Zugang, Rendering, strukturierte Daten. Lauter Dinge, über die ein Entwickler entscheidet, nicht das Content-Team. SEO optimiert auf den Klick. GEO optimiert auf das Zitat. Der Unterschied ist nicht kosmetisch. Klassisches SEO will, dass du auf Platz eins rankst, damit jemand klickt. GEO will, dass ein Sprachmodell deinen Absatz wörtlich in seine Antwort übernimmt – inklusive Quellenangabe. Der Klick ist nur noch Bonus. Daraus folgt ein anderer Tech-Stack an Signalen: Aspekt Klassisches SEO GEO / KI-Sichtbarkeit Ziel Top-10 in Google Zitat in ChatGPT, Claude, Perplexity Relevante Bots Googlebot, Bingbot GPTBot, ClaudeBot, PerplexityBot Index-Hinweis sitemap.xml llms.txt + sitemap.xml Strukturierte Daten Rich Snippets Entity-Linking ( Organization , sameAs , @graph ) Rendering Google rendert JS (verzögert) viele KI-Bots rendern kein JS → SSR Pflicht Erfolgskontrolle Search Console, Rank-Tracker Citation- & Mention-Tracking in LLMs Die Hebel überschneiden sich – sauberes HTML, schnelle Antwortzeiten, valides Markup helfen beidem. Aber die Bots, die Index-Signale und die Erfolgskontrolle sind eigenständig. Wer GEO als „SEO mit neuem Namen" abtut, übersieht genau die Stellen, an denen es klemmt. Schritt 1: Lass die Bots überhaupt rein Bevor du über Content-Qualität nachdenkst, klär die banale Frage: Kommt der Crawler durch? Erstaunlich oft lautet die Antwort nein – und niemand merkt es, weil ein Browser die Seite ja problemlos lädt. Die drei Use
AI 资讯
How Solana Processes Transactions — And How to Make Them Faster
If you've ever sent a transaction on Solana and wondered why it landed instantly one time and struggled another, you're not alone. Solana is incredibly fast, but how your transaction enters the network matters just as much as what you're sending. In this article, we'll break down Solana transaction processing in plain English — no developer jargon — and explain why landing services like Lunar Lander and Astralane can dramatically improve speed and reliability. The Big Picture: How Solana Handles Transactions At a high level, Solana works like this: You submit a transaction The network decides which transactions get processed first A validator includes your transaction in a block The transaction is finalized on-chain The key detail most users don't see is step #2 — how Solana decides which transactions get priority when the network is busy. That decision is driven by something called Stake-Weighted Quality of Service (QoS) . Stake-Weighted QoS (Explained Like You're Not a Developer) Solana has a built-in traffic management system. Think of it like traffic control for a highway. A Simple Analogy Imagine a highway with two lanes: 🚗 Fast lane (priority access) 🚙 Regular lane (everyone else) Solana prioritizes transaction traffic based on stake, meaning traffic originating from or routed through high-stake validators is more likely to be processed during congestion. Why? Because validators that stake SOL are financially invested in keeping the network healthy. Giving them priority helps protect Solana from spam and overload. What This Means for You Transactions that enter Solana through stake-backed paths have a much higher chance of landing quickly Transactions that enter through generic or overloaded RPCs compete for a smaller slice of capacity During congestion, non-priority transactions are more likely to be delayed or dropped This is the core idea behind Solana's stake-weighted QoS system. Where Transactions Usually Go Wrong Most wallets and apps send transactions t