今日已更新 328 条资讯 | 累计 20300 条内容
关于我们

标签:#EV

找到 2965 篇相关文章

AI 资讯

Scaling a Static Site to 4,400 Pages Without Breaking Google

I built Luxury Hotel Offers , a fully static site with 3,400+ listings that generates 4,400 HTML pages at build time. No SSR, no database at runtime. Here are the four hardest scaling problems I hit. 1. Googlebot's 2 MB HTML Limit With 3,400 hotels on one listing page, the naive approach (render all cards in HTML) produced a 9 MB page. Googlebot truncates at 2 MB and ignores the rest. The fix: cap the initial HTML at 400 cards. The remaining 2,500+ cards are generated as a separate HTML fragment file at a predictable URL ( /data/cards/{slug}-remaining/ ). A "Load More" button injects 48 cards at a time from the fragment. The first search or filter interaction loads the entire fragment so all cards are available for client-side filtering. This keeps every page under 2 MB for crawlers while giving users access to everything. 2. Content-Aware Lastmod with Cascading A site with 4,400 pages can't update every lastmod on every build. Search engines treat that as spam, and IndexNow has rate implications. Instead, the build hashes each hotel's SEO-relevant fields and compares against a persisted store. Only pages with actual content changes get their lastmod bumped. The interesting part is cascading: when a hotel in Paris changes, the Paris city page, France country page, and Europe region page all get their dates updated too, since their content changed (they list that hotel). Changed URLs feed into IndexNow so only genuinely modified pages get pushed to search engines. 3. DOM Filtering Breaks on Mobile at Scale The site started with pure DOM filtering: every card has data-* attributes for region, country, brand, and perks. JavaScript reads attributes and toggles visibility. Zero network requests, instant results. Great on desktop. On a mid-range phone with 2,500+ cards in the DOM, filtering took 2-3 seconds per interaction. textContent traversal across 20-40 nodes per card means ~60,000 DOM visits per keystroke. Layout thrashing with 10,000+ nodes made every show/hide cyc

2026-07-12 原文 →
AI 资讯

Designing a Multi-Tenant Storefront With Wildcard Subdomains

At my workplace, I worked on an ERP platform used by fashion businesses to manage customers, body measurements, products, orders, invoices, inventory, staff, and other day-to-day operations. Each business also had a public storefront where customers could browse products and check out. The storefront started as a simple sharing feature. Businesses could publish products, copy a link, and send it to customers outside the main workspace. That worked well because the storefront was mostly a product catalogue, and most of the sales process still happened after the customer contacted the business. As the platform evolved, the storefront became much more than a catalogue. Customers were discovering businesses through shared links, browsing products, placing an order, and tracking orders directly from the storefront. That introduced new technical requirements around branded storefronts, SEO, server-rendered metadata, public checkout, pricing, and analytics. This article explores how I designed the storefront around wildcard subdomains, immutable shop identities, server-side shop resolution, and a scalable analytics pipeline. Table of Contents Giving the Storefront Its Own Identity Business Names, Reserved Names, and Subdomains Resolving a Storefront Active and Inactive Storefronts Location and Currency Product Pages and Share Previews Storefront Event Ingestion Processing Raw Events Counting Unique Visitors With HyperLogLog Domain Routing and Local DNS 1. Giving the Storefront Its Own Identity The original storefront was fairly simple. It was a React application that fetched a business and rendered its products. Beyond that, there wasn't much to it. There were no branded storefronts, analytics, subdomains, or even a separate identity beyond the business itself. Introducing those capabilities meant the storefront needed its own data model. I introduced a dedicated shop entity to represent the public storefront. The business remained the source of operational data such as cu

2026-07-12 原文 →
AI 资讯

Designing an Async Image API Client That Does Not Lie About Completion

Image generation is where a seemingly simple API client starts to accumulate production bugs. A request may finish inline for one model, return a task for another, or take a longer path when the input includes edits and uploaded files. Treating every successful HTTP response as a completed image is the fastest way to ship broken retry logic and incorrect user-facing status. This post adapts the TokenLab article TokenLab Async Image Generation Tasks for Production Apps . The canonical article contains the full implementation discussion; this version focuses on the contract decisions that matter when building an integration. The response is a delivery decision, not just a payload An image endpoint can return either a completed representation or an asynchronous task. The client should inspect the response envelope and normalize the delivery mode before it touches application state: type Delivery = | { mode : " sync " ; terminal : true } | { mode : " async " ; task_id : string ; status : string ; terminal : false }; The important invariant is that mode and terminal state come from the API contract. Do not infer completion from a missing progress field, a truthy data property, or a fast response time. Progress is useful when present, but it is not the completion signal. Poll by task identity, not by the original request When the server returns an async task, persist the task ID and the provider-neutral status. A worker can then poll the task endpoint with bounded backoff: async function waitForTask ( id : string ) { for ( let attempt = 0 ; attempt < 60 ; attempt += 1 ) { const task = await getTaskStatus ( id ); if ( task . status === " succeeded " ) return task . result ; if ([ " failed " , " cancelled " , " expired " ]. includes ( task . status )) { throw new Error ( `Media task ${ id } ended as ${ task . status } ` ); } await sleep ( Math . min ( 1000 * 2 ** Math . min ( attempt , 5 ), 30 _000 )); } throw new Error ( `Media task ${ id } exceeded the polling budget` );

2026-07-12 原文 →
AI 资讯

I Built a Browser From Scratch, and It Finally Renders the World's First Website Like Chrome Does

A while back I set myself a slightly unhinged goal: build a web browser from scratch in Node.js and Electron no external HTML/CSS/layout libraries, everything hand-rolled. URL parser, TCP/TLS socket, HTTP pipeline, HTML tokenizer, DOM builder, CSS tokenizer, CSS parser, style matcher, layout engine, canvas renderer. All of it, from zero. so,I called it Courage Browser . This week, after dozens of daily sessions, I hit a milestone that felt disproportionately satisfying: Courage now renders info.cern.ch the very first website ever put on the internet almost pixel-for-pixel identical to real Chrome. It sounds small. It is not small. Getting there meant chasing down bugs across nearly every layer of the browser. Why info.cern.ch If you haven't seen it, info.cern.ch is CERN's preserved copy of Tim Berners-Lee's original website. It's about as simple as HTML gets — one heading, a paragraph, a bulleted list of links. No CSS file, no JavaScript, no styling of any kind beyond what a browser applies by default. Which is exactly why it's a great test case. If your browser can't get a page with zero author CSS to look right, it has no business trying to render anything more complex. Default styling headings being bold, links being blue and underlined, bullets showing up in the right place has to work before anything else does. The bugs I found by just... comparing screenshots I put a screenshot of Courage's render side-by-side with Chrome's and started listing differences. Two jumped out immediately: The <h1> wasn't bold in Courage, even though it clearly should be. The links had underlines but weren't blue , they were rendering in the default text color. Neither of these had anything to do with what I was originally working on that day (CSS attribute selectors, for an upcoming GitHub-rendering push). But they were visible, they were wrong, and they were small enough to fix in one sitting. So I did. Bug #1: styles computed before they were applied Courage has a defaultRules ar

2026-07-12 原文 →
开发者

The Key That Unlocks Everything: Prototype Pollution in JavaScript

Imagine a hotel where every room key is cut from a master template. When a guest checks in, the front desk hands them a key that opens only their room. Simple enough. Now imagine a guest who, during check-in, sneaks a tiny modification into the key-cutting machine itself — changing the template so that every new key cut from that moment on also opens the manager's office, the safe, and the server room. The guest didn't break a lock. They didn't clone anyone's key. They changed the factory that makes all keys. That factory is JavaScript's Object.prototype . And the attack is called Prototype Pollution .

2026-07-12 原文 →
AI 资讯

PassionQA: Turning My Passion for Software Quality into AI-Powered Test Intelligence

This is a submission for Weekend Challenge: Passion Edition What I Built As a QA engineer, I spend a lot of time reading requirements, questioning unclear business rules, and thinking about what could break before a feature reaches users. That part of quality engineering is something I genuinely enjoy, and it inspired me to build PassionQA . PassionQA is an AI-powered quality intelligence platform that turns product requirements into practical QA insights and executable test cases. The workflow is simple: Upload or paste a BRD (Excel or text) Run AI-assisted quality analysis Review the complete QA output in one dashboard: Requirement health and release readiness Missing rules and ambiguous requirements Positive, negative, boundary, security, and accessibility test cases Bug-risk insights and heatmap Requirements Traceability Matrix (RTM) Excel and PDF exports My goal was to reduce the repetitive part of requirement analysis so testers can spend more time thinking critically about product risk and quality. Demo Try it quickly Live app: https://passion-qa.vercel.app Click Explore Demo Preset to analyze the built-in insurance example. The application uses Gemini when available and automatically falls back to the local analysis engine if Gemini is unavailable. Or click Launch Platform (Free) , upload your own BRD, and select Run Quality Analysis . For my demo, I used an insurance Policy BRD. PassionQA analyzed the requirements, highlighted quality gaps, and generated executable positive, negative, boundary, security, and accessibility test scenarios across the policy workflow. Video Demo The demo shows the complete flow from Policy BRD upload to AI analysis, test-case generation, risk insights, RTM, and report export. Demo video: https://drive.google.com/file/d/1sAoOauTGCk66xAzY46zF8_lWBQbVM8Gr/view?usp=sharing Code GitHub repository: https://github.com/DhanashriQAEngineer/PassionQA/ Some of the key parts of the project are: src/lib/gemini.ts --- Gemini analysis and loc

2026-07-12 原文 →
AI 资讯

How to clone a Keycloak realm on the same instance (fixing "duplicate key value violates unique constraint")

If you've ever tried to duplicate a Keycloak realm on the same server — say, to spin up a myrealm-dev realm alongside your existing myrealm — you've probably hit this wall: Export the realm from the Admin Console ( Realm settings → Action → Partial export , with clients and groups/roles included). Rename it in a text editor, or in the import dialog's "realm name" field. Import it back into the same Keycloak instance. Watch it fail with: ERROR: duplicate key value violates unique constraint "constraint_a" Detail: Key (id)=(51e1a26d-c24f-4454-9a34-708f1fc14917) already exists. Why this happens A realm export isn't just configuration — it's a snapshot of database rows. Every role, client, user, protocol mapper, component, and authentication flow in the export carries the same internal UUID it has in the live database. Renaming the realm field changes what the realm is called , but it does nothing to the dozens (often hundreds) of UUIDs referenced throughout the file. Import that JSON into the instance it came from, and Keycloak tries to insert rows whose primary keys already exist. Every single one collides. This is a known limitation, tracked upstream as keycloak/keycloak#24770 . Keycloak's exporter was never designed to produce an import-anywhere-including-here artifact — it assumes you're moving the realm to a different instance (dev → staging → prod), where the UUID space is independent. The manual fix (and why it doesn't scale) In principle you can fix this by hand: open the export JSON, find every UUID, and replace it with a fresh one, while keeping track of which old UUID maps to which new UUID so that references between objects (a role's containerId , a client's serviceAccountClientId , a flow's execution list) still point at the right thing after the rewrite. For a small realm with a handful of clients this is tedious but doable in an editor with careful find-and-replace. For a realm with custom roles, several clients, an identity provider, and a full set of a

2026-07-11 原文 →
AI 资讯

How to Add Evals to an LLM Feature

Learning how to add evals to an LLM feature is the difference between shipping a demo and shipping a reliable product. When you embed an LLM into a real feature — a chatbot, a voice agent, a document summarizer — you’re not just calling a model. You’re betting your user’s experience on a non‑deterministic system that can silently break with every prompt tweak, model update, or edge case. That’s why we instrument every LLM feature we build with a purpose‑built eval suite. Here’s how we did it for an outbound AI calling agent and how you can do the same. Why Evals Are Not Optional LLMs are non‑deterministic: give them the same input twice, and you’ll get two different responses. That means unit tests that check for exact string matches are useless. As Pragmatic Engineer notes , you need evals to verify that the solution works well enough — because there’s no guarantee it will. When you’re building a feature that speaks to real customers, like the AI Calling Agent dashboard we built, a regression in tone or missed booking intent can cost revenue immediately. Evals turn that uncertainty into signal. How to Add Evals to an LLM Feature: A 4‑Step Workflow We’ll walk through the exact process we followed, from defining success to automating checks in CI, using the DeepEval framework as an example. You can swap in Evidently AI or build your own, but the pattern is the same. Step 1: Define Success for Your Feature Takeaway: Before you pick a metric, write down the one thing that makes the feature “done” — usually a business outcome, not a technical measure. For the AI Calling Agent, the core feature was an outbound call that books a meeting. The success criterion wasn’t “the LLM replied politely.” It was “the agent scheduled a meeting with the right time and date.” This is a reference‑based evaluation: you compare the output to a known ground truth. Evidently AI’s guide calls this pattern out as essential for regression testing and experimentation. From that criterion, we der

2026-07-11 原文 →
AI 资讯

What a Refinery Taught Me About CI Pipelines

I’m currently relearning the Core Three — HTML, CSS, and JavaScript — as I work toward becoming a full-stack JavaScript developer. Before I came back to learning software, I spent 22 years working industrial turnarounds. One lesson from that world has followed me into software engineering: Never trust a single point of failure. In industrial maintenance, there’s a safety practice called double block-and-bleed . Instead of trusting one isolation valve, you use two independent valves with a bleed point between them. If one valve leaks, you know immediately. The entire system assumes individual components can fail. Safety doesn’t come from perfect parts. It comes from independent layers of protection. That idea completely changed how I think about CI pipelines. When I first started relearning web development, my mindset was simple: Run Lighthouse. Everything green? Great. 100 across the board locally? Even better. Ship it. Different results after deployment? Uh-oh. Now I see Lighthouse as one checkpoint — not the finish line. A fast website can still have accessibility issues. An accessible site can still have broken metadata. Good SEO won’t catch rendering bugs. Passing unit tests won’t tell you if the generated HTML is malformed. Every tool has blind spots. No single tool should get the final vote. So instead of asking: “Did my tests pass?” I ask: “What kinds of failures could still slip through?” That question naturally leads to layered validation. Formatting Linting Type checking Accessibility checks Performance audits HTML validation SEO analysis Manual review None of these tools is perfect. Together, they’re much stronger than any one of them alone. The more I learn about software, the more I find myself applying lessons from heavy industry. Different environment. Different risks. The same engineering mindset. Assume components will fail. Design systems that fail safely. That’s becoming the philosophy behind every test matrix and CI pipeline I’m designing. What’s

2026-07-11 原文 →
AI 资讯

The Ultimate Claude Masterclass: 13 Power Features Changing the AI Game

The Ultimate Claude Masterclass: 13 Power Features Changing the AI Game Artificial Intelligence is no longer just about asking questions and getting text answers. Anthropic’s Claude has evolved from a simple chatbot into a fully autonomous, visual, and connected AI ecosystem. If you are still using it just to draft emails, you are barely scratching the surface. Whether you are a developer, content creator, or business professional, here is your definitive guide to the 13 powerhouse features of Claude, packed with practical examples, formatted specifically for Dev.to. 🧩 Part 1: Smart Onboarding & Personalization 1. Introduction to Claude Claude stands out in the crowded AI landscape because of its advanced reasoning, high emotional intelligence, and natural, human-like writing style. From parsing complex codebases to writing creative narratives, Claude feels less like a machine and more like a brilliant colleague. 2. Import Memory From ChatGPT To Claude Switching platforms shouldn't mean losing your progress. With this feature, you can instantly migrate your entire persona, past context, and custom instructions from ChatGPT straight into Claude with a single click. Example: If ChatGPT already knows your coding style or specific brand rules, importing it means Claude hits the ground running without you having to re-explain everything. 3. Add User Preferences Tired of typing "Act as a Senior Developer" or "Keep it casual" in every single prompt? User Preferences lets you set permanent system-level instructions that Claude remembers across all new conversations. Example: You can set a preference like: I manage a technology brand. Always keep explanations direct, modular, and optimized for scalability. 🎨 Part 2: Visuals, Coding & Apps 4. Create Apps & Artifacts Using Claude For Free Claude’s Artifacts feature opens a dedicated, interactive window right next to your chat. When you ask Claude to write code, a webpage, or a game, it doesn't just show you lines of text—it re

2026-07-11 原文 →
AI 资讯

How to Thrive (Not Just Survive) as a Developer in the Age of AI

The narrative around Artificial Intelligence and software engineering has shifted dramatically. We are no longer asking if AI will change development, but rather how we change with it. If your value as a developer is tied solely to how fast you can churn out boilerplate code, write standard API endpoints, or memorize syntax, the landscape is becoming challenging. AI can do those things in seconds. However, this isn't a death sentence for the engineering career—it is an evolution. The industry is moving away from pure "code generation" and shifting toward system architecture, integration, and governance. To remain indispensable, you need to know exactly where to direct your energy and what pitfalls to avoid. Where to Focus Your Energy To stay relevant, you must position yourself in the areas where AI struggles: high-level abstraction, complex contextual reasoning, and human leadership. 1. System Design and Enterprise Architecture AI is excellent at writing isolated functions, but it struggles with massive, interconnected systems. Focus on how components interact at scale. Understanding how to slice a monolithic application into resilient microservices, orchestrate microfrontends, or design cloud-native solutions is where the high-value work lies. 2. Code Governance and Quality Assurance With AI generating code at unprecedented speeds, codebases are expanding faster than ever. The world doesn't just need people who can create code; it needs gatekeepers who can validate it. Your role will increasingly focus on setting quality standards, establishing robust CI/CD pipelines, and ensuring that AI-generated code adheres to strict security, compliance, and performance metrics. 3. Mentorship and Team Leadership The influx of AI tools means junior engineers can produce code much earlier in their careers, but they often lack the foundational experience to spot subtle architectural flaws or security vulnerabilities. Senior developers must step up as leaders, guiding less experi

2026-07-11 原文 →
AI 资讯

A RabbitMQ Upgrade Exposed the Reliability Assumptions Hidden in Our Messaging System

The RabbitMQ upgrade looked like a straightforward infrastructure task: move from RabbitMQ 3.X to 4.X, provision the new broker, review the client setup, confirm queues still declare correctly, restart consumers, watch the logs, and move on. But infrastructure upgrades rarely test only infrastructure. They also test the assumptions your application has been making for years. In this case, the upgrade forced a more important question: is our messaging system reliable by design, or has it simply been relying on stable conditions? That distinction matters because a message queue can appear healthy when the broker is running, the network is stable, consumers are alive, and messages are acknowledged quickly. But production systems are not judged only by how they behave when everything is fine. They are judged by how they behave during restarts, closed channels, slow handlers, bad configuration, deployment windows, and partial failure. The RabbitMQ upgrade exposed those edges. It revealed assumptions around connection lifecycle, acknowledgements, dead-letter routing, retry behavior, observability, and operational simplicity. The real lesson was not just how to upgrade RabbitMQ. The real lesson was how to build a messaging layer that is easier to operate, easier to reason about, and safer to fail. Simplicity Is an Operational Feature One of the first things the upgrade exposed was complexity. Over time, messaging code can quietly become a small internal framework. A connection helper becomes a connection manager. A consumer wrapper becomes a consumer framework. Retry helpers appear, dead-letter helpers appear, failure handlers appear, and monitoring logic gets layered on top. Each addition may have been reasonable when introduced, but during an incident, complexity has a cost. Every abstraction becomes another place to inspect. Every helper becomes another assumption to validate. Every unused file becomes a possible source of false confidence. RabbitMQ integration code doe

2026-07-11 原文 →
AI 资讯

GDPR retention and erasure for an agent mailbox

Most "AI email" demos never think about deletion. The agent reads, replies, files things away, and the inbox just grows. That's fine in a demo. It is a problem the first time a real person emails your agent, because the moment that mailbox holds someone else's name, address, order history, or support complaint, you've taken on a data-protection obligation — and "we kept everything forever" is not a defensible retention policy. An Agent Account on Nylas accumulates personal data you have to be able to purge. It's a mailbox the agent owns — support@yourcompany.com answering to a model instead of a human — and every inbound message lands in it. Under GDPR that data needs two things you can prove: a retention window so it doesn't live forever, and an erasure path so you can delete a specific person's mail when they ask. This post builds both, with the curl and the CLI for each step. A quick, honest caveat before any of it: this is a docs-and-demo walkthrough, not legal advice. The Nylas primitives below cover the mail held in the mailbox . Any derived copy you made — rows in your own database, lines in your application logs, a vector store you embedded the message into — is yours to purge separately. The API can delete the message; it can't reach into your Postgres. Keep that in mind throughout. What the platform gives you Nothing new to learn on the data plane. An Agent Account is just a grant with a grant_id , so everything you already know about Messages and Threads applies directly — listing, reading, and deleting mail run against the same grant-scoped endpoints any other Nylas integration uses. Retention and erasure split cleanly into two layers: Retention is a control-plane setting. It lives on a policy — an application-scoped resource that bundles limits and spam settings — attached to the workspace your Agent Account belongs to. Two fields cap how long mail survives: limit_inbox_retention_period and limit_spam_retention_period . Set them once and Nylas deletes a

2026-07-11 原文 →
AI 资讯

Keep your agent's mail out of spam traps

Spam traps are the failure mode nobody puts in the demo. A bounce is loud — you get a 5.x.x back, your code logs it, you move on. A complaint at least gives you a webhook. A spam trap gives you nothing . The message gets accepted, no error comes back, and somewhere a mailbox provider quietly writes your domain down as a spammer. By the time you notice, your inbox placement has already cratered and you have no single bounce to point at. That's the trap, literally. And it's the one that bites autonomous agents the hardest, because the whole appeal of an agent is that it acts without a human watching every send. Point a model at a list it scraped, let it loop, and it'll happily mail a recycled address that's been a trap for two years. The agent never sees a problem. You only see the aftermath in your deliverability dashboard a week later. I work on the Nylas CLI, so the terminal commands below are the exact ones I reach for when I'm wiring up an Agent Account to not do this. The good news is that an Agent Account is just a grant — a grant_id that works with every grant-scoped endpoint you already know — so there's nothing new to learn on the data plane. The defense is mostly discipline: validate before you send, honor every complaint, and age out the addresses that never wanted to hear from you. What a spam trap actually is, and why it's not a bounce It's worth being precise here, because the three things people lump together behave completely differently. A bounce is a rejected delivery. The receiving server tells you the address is bad, you get a message.bounced event, and you stop. Bounce handling is a solved problem — you listen, you suppress, you're done. A complaint is a recipient hitting "report spam." The mailbox provider relays that back as a feedback loop, and you get a message.complaint event. The address is real and reachable; the human just doesn't want your mail. If you keep mailing them, you're training the provider to filter you. A spam trap is neither.

2026-07-11 原文 →
AI 资讯

Every Sports App Resets Your Streak Eventually. Mine Can't. 🔒⚡

This is a submission for Weekend Challenge: Passion Edition What I Built Loyalty Ledger — a fan loyalty tracker where your check-in streak, badges, and history live on Solana instead of some app's database. Live app: https://loyalty-ledger-blond.vercel.app Here's the problem I kept coming back to. Every sports app wants you to check in, engage, "prove your loyalty" — collect points, build a streak, unlock a badge. Cool. Except every single one of them throws that history away the second you stop opening the app. Switch apps and your streak resets to zero. Get banned, or the app shuts down, or they just quietly decide to wipe inactive accounts one day — and your history is just... gone. Because it was never actually yours. It was a number sitting in someone else's database, and they could reset it, inflate it, or delete it whenever they felt like it. You had zero say in it. And that bugged me way more than it probably should have. Like — we figured out how to make ownership portable for money, for domain names, for digital art. But "I've supported Argentina since 2019" 🇦🇷 still lives and dies inside one company's backend, and nobody's really questioned that. So I kept the weekend scope deliberately small: prove one fan's loyalty to one team, for real, end to end — instead of sketching ten features that are all half-fake. You connect a wallet, pick a sport and team, and check in. FIFA World Cup is the fully working path here ⚽ — that check-in sends an actual transaction that creates or updates a program-owned account, not a row in my database somewhere. Your streak count, your badge tier, the actual badge tokens — none of it exists anywhere I control. Which honestly felt a little weird to build, in a good way. Once that core loop worked, I built the rest of the identity around it: a Fan Passport that shows your streak, a derived "Fan Score," your tier (Rookie → Devoted → Veteran → Legend 🏆), a progress bar toward the next tier, an achievements grid with locked/unlocke

2026-07-11 原文 →
AI 资讯

Designing the data model for a trading journal

Every trader I know starts journaling in a spreadsheet, and every one of them abandons it within a month. Not because journaling is useless, but because the spreadsheet can't answer the questions that actually matter: "which of my rules costs me the most money?" or "am I cutting winners too early?" A flat sheet of rows can't tell you. Tools like RizeTrade solve this with a proper data model, and in this post I'll walk through how to design one yourself. The problem is almost always the data model. If you design the schema well up front, the hard reports fall out of it for free. Here's how I'd structure it. * Start with the trade, but don't overload it * The instinct is to make one giant trades table with fifty columns. Resist it. A trade has a small core of facts: CREATE TABLE trades ( id BIGSERIAL PRIMARY KEY , symbol TEXT NOT NULL , side TEXT NOT NULL CHECK ( side IN ( 'long' , 'short' )), entry_price NUMERIC NOT NULL , exit_price NUMERIC , quantity NUMERIC NOT NULL , entry_at TIMESTAMPTZ NOT NULL , exit_at TIMESTAMPTZ , stop_loss NUMERIC , take_profit NUMERIC , commission NUMERIC DEFAULT 0 , strategy_id BIGINT REFERENCES strategies ( id ) ); Everything else (emotions, notes, screenshots, rule checks) hangs off this in separate tables. That separation is what lets you slice the data later without schema migrations every time you want a new report. * R multiples belong in the model, not the UI * The single most useful number in trading isn't dollar P&L. It's the R multiple: profit or loss expressed in units of the risk you planned to take. A +2R win and a +2R win are comparable across a $500 account and a $50,000 account; two dollar figures aren't. Planned risk is defined the moment you enter, by your stop: planned_risk_per_unit = |entry_price - stop_loss| planned_R = (exit_price - entry_price) / planned_risk_per_unit (for longs) Store the stop at entry time. If you only record the realized exit, you lose the ability to detect stop loss violations, which is the who

2026-07-11 原文 →
AI 资讯

Invisible DevTools: Why the Best Tools Disappear

The best developer tools share one quality: you forget you are using them. Think about it. Your IDE fades into the background when you are in flow. Your terminal becomes muscle memory. These tools are invisible because they match your mental model so perfectly that there is zero friction between thought and action. This is exactly what online developer utilities should aspire to. The Problem with Fragmented DevTools Most developers have a bookmarks folder full of single-purpose websites: One for JSON formatting One for timestamp conversion One for Base64 encoding One for URL decoding Every switch between these tabs is a context loss. Every tool has a slightly different UI, different copy-paste format, different quirks. The Invisible Toolkit Opennomos Json (opennomos.com/en/project/01KJ850Z7PNGXHXESBM68HE12Y) consolidates timestamp conversion, JSON formatting, and Base64 encoding into a single workspace. No install. No accounts. No pricing tiers. Just open a tab and work. This is the north star for developer tools: make them so simple that the user never has to think about the tool itself — they only think about their actual task. The Trend Is Clear We have seen this pattern across the dev ecosystem: GitHub Codespaces made local IDE setup invisible Vercel made deployment invisible Replit made runtime environment invisible The next frontier is utility tools. The sooner they become invisible, the better. Try it: opennomos.com/en/project/01KJ850Z7PNGXHXESBM68HE12Y Part of the Nomos Build-in-Public series.

2026-07-11 原文 →
产品设计

A tasty RPG that will make you very hungry

Roleplaying games are often defined by excess. Storylines that span dozens of hours, side quests so big they could be their own game, massive worlds that require complex maps to explore, and casts so big you start forgetting character names. That's part of what makes these games feel like epic adventures, but it can also […]

2026-07-11 原文 →