Toss

72 posts

toss.tech

Filter by tag

toss4 min readCurated summary

Applying Post-Quantum Cryptography for the Quantum Computing Era: Why Implement It 10 Years Early?

Toss Payments’ hardest legacy-modernization challenge was not replacing old systems, but improving security across tens of thousands of merchants with diverse, outdated environments. Over four years, it gradually introduced HTTP/3, removed vulnerable cipher suites, deployed TLS 1.3, and ultimately adopted post-quantum cryptography (PQC) in April 2026. The central lesson is that security upgrades must begin early and be introduced gradually, with merchant support and backward compatibility built in. ## Breaking the Inertia of Legacy Systems - Mission-critical payment services tend to follow the principle: “If it works, don’t touch it.” - Security protocol changes are particularly difficult because they can affect every merchant integration and may be hard to troubleshoot or roll back. - Many merchants still operate decades-old server-side systems that cannot support modern security policies. - Documentation alone is often insufficient, especially for merchants without dedicated development teams. - Because every API, SDK, payment window, and server connection is part of the security boundary, Toss Payments could not improve security independently of its merchants. ## Why Existing Encryption Must Evolve - Modern HTTPS, banking, and payment systems rely heavily on RSA and ECDSA. - These algorithms are considered secure because factoring large numbers and solving elliptic-curve problems is impractical for classical computers. - Quantum computers could solve these problems efficiently, making current public-key cryptography vulnerable. - The anticipated point at which quantum computers can break these systems is often called “Q-Day.” - The “Harvest Now, Decrypt Later” threat means attackers can collect encrypted payment data today and decrypt it years later when quantum computers become practical. ## A Four-Year Security Upgrade Program Toss Payments chose a gradual migration strategy to improve security without abruptly disrupting merchant payments: - **2022:** Introduced HTTP/3, which requires TLS 1.3. - **2022–2025:** Removed vulnerable TLS cipher suites. - **2022–2025:** Enabled TLS 1.3 across all endpoints. - **April 2026:** Introduced post-quantum cryptography. ## HTTP/3 as a Low-Impact Starting Point - HTTP/3 improves speed and reliability on unstable networks. - Because it requires TLS 1.3, enabling HTTP/3 also raised security standards. - Modern browsers automatically select HTTP/3, so merchants required no configuration changes. - This made HTTP/3 an effective first step with minimal migration risk. ## Gradual Cipher Suite Removal - A cipher suite defines the algorithms used by a client and server to establish encrypted communication. - Some legacy merchant servers supported only vulnerable suites, such as `TLS_RSA_WITH_AES_128_CBC_SHA`. - Removing them immediately could stop payments for affected merchants, while delaying removal would leave the wider ecosystem exposed. - Toss Payments used: - Merchant-by-merchant compatibility analysis - Individual notifications six months to a year in advance - Environment-specific documentation and configuration guidance - Technical consulting where necessary - The Technical Account Manager team was essential in coordinating these changes and communicating with merchants in accessible language. ## TLS 1.3 Deployment - TLS 1.2 remained the minimum supported version, while TLS 1.3 was added alongside it. - Clients capable of TLS 1.3 automatically use the stronger protocol. - Older clients continue using TLS 1.2 without forced changes. - TLS 1.3 was enabled endpoint by endpoint from 2022 and supported across all endpoints by 2025. - The process demonstrated that ecosystem-wide security improvements require more time helping merchants migrate than technically changing the servers. ## Post-Quantum Cryptography - Toss Payments began preparing for PQC in 2025 and completed deployment in April 2026. - Modern browsers and clients that support PQC automatically use stronger quantum-resistant channels. - Unsupported environments continue using established encryption methods, preserving compatibility. - Merchants do not need to change configurations or update their integrations. - The approach provides stronger protection against future quantum attacks while minimizing present-day disruption. ## Cross-Team Collaboration - **Infra Team:** Applied PQC within Toss Payments’ private data-center infrastructure and physical hardware. - **Server Platform Team:** Integrated PQC into live traffic paths in AWS. - **TAM Team:** Used its experience from the cipher-suite migration to guide merchants and assess integration environments. - The result was a large-scale, proactive security deployment across the private payment ecosystem. Toss Payments’ experience suggests that organizations should start security migrations well before threats become immediate. Compatibility layers, staged enforcement, and sustained technical support allow legacy ecosystems to adopt stronger security without sacrificing availability.

Read original(opens in new tab)
toss5 min readCurated summary

Extending Real-time Ad Frequency Capping Aggregation to One Week with Apache Flink + RocksDB Tuning

The post describes Toss’s expansion of real-time advertising frequency-capping from short Flink windows to periods of up to seven days. The new system provides accurate sliding counts from one minute to seven days through a single Redis lookup, while treating Flink state as the authoritative source and Redis as its projection. The migration addressed architectural complexity, backfill consistency, and distinct RocksDB bottlenecks across three specialized Flink applications. ## Frequency Capping and Its Business Impact - Frequency capping controls how many times an individual user sees an advertisement. - Incorrect counts can: - Waste an advertiser’s budget through excessive exposure. - Prevent valid impressions when the system believes a limit has already been reached. - Different products require different windows, such as: - Three impressions per day. - One impression over the previous seven days. - The target system therefore needed accurate, real-time sliding counts from one minute through seven days. ## Limitations of the Previous Batch-Oriented System The original architecture combined three Airflow-managed layers: - **Head** - Stored current-day and previous-day events in Redis through a Spring Kafka consumer. - Updated counts immediately per event. - **Mid** - Used daily Spark jobs to pre-aggregate data from D-2 through D-7. - **Tail** - Added hourly correction data around the boundary between Head and Mid. - Airflow workflows ran approximately 75 times per day. At serving time, the API could perform up to four Redis lookups and combine the results. - This structure was difficult to maintain because of the dependencies and boundary conditions between Head, Mid, and Tail. - Time-based truncation made precise event-level sliding windows difficult. - The architecture remains useful for longer windows such as 30 days and fixed daily aggregates, especially when data exceeds Kafka retention and must be recovered from batch storage. - Extending the existing short-window Flink system was chosen to simplify serving and reduce DAG complexity. ## Three Flink Applications Rather than place all windows in one Flink job, the team split processing into three applications with shared code but independent RocksDB configurations: - **Minutes** - Handles one- to 30-minute windows. - Frequent event expiration creates heavy write traffic. - Its main concern is RocksDB Write Buffer Manager pressure and resulting Write Stalls. - **Hours** - Handles windows up to 12 hours. - Maintains many more advertisement IDs in state. - Filter Block Cache misses can saturate CPU. - Redis synchronization requires an O(N) scan over advertisement IDs in each window. - Filter Block tuning and additional managed memory are important. - **Days** - Handles the largest state volume. - A seven-day window can produce approximately 68 GB of live SST files and 220–230 GB savepoints. - Checkpoint I/O becomes the primary bottleneck, motivating a Flink Changelog design. Separating the applications allowed each workload’s RocksDB and runtime bottlenecks to be optimized independently without affecting the others. ## Backfill and Catch-up Architecture The most difficult migration problem was maintaining correctness at the transition point between historical data and live processing. - **Backfill** - Loads seven days of historical events. - Only increments counts. - Does not register expiration timers. - Synchronizes the initialized values to Redis once and then finishes. - **Catch-up** - Re-reads historical events from Kafka. - Rebuilds both counts and expiration timers. - Begins writing to Redis after reaching the historical scan end. - Enables each window only after sufficient lookback data has been reconstructed. The two phases cannot safely share one pipeline: - Backfill must only add historical counts. - Live or catch-up processing must both add new events and subtract events that leave the sliding window. - If expiration timers ran while backfill was incomplete, decrements could occur before all historical increments had been applied, producing incorrect results. - Flink batch mode was rejected because state is discarded when the job finishes. - A Spark and Hive-based approach was also rejected because it would introduce additional systems and complicate the single-source-of-truth model. Separate Kafka consumer groups were required so that backfill offsets would not cause catch-up events to be skipped. ## State as the Single Source of Truth - Flink state stores the authoritative aggregate. - Redis is treated only as a serving projection. - If Redis becomes inconsistent, it can be reconstructed from Flink state. - This design preserves correctness during failures, restarts, and Redis resynchronization. ## Maintaining Transition Consistency Three mechanisms were combined to make the backfill-to-catch-up boundary reliable: - **Redis write condition** - Writes are based on each event’s `eventTime` being after the backfill completion point. - Using the global watermark directly could block all writes because one slow or idle partition can hold back the watermark. - **`withIdleness` set to 60 seconds** - Excludes inactive Kafka partitions from watermark progression. - A longer timeout avoids falsely marking a partition idle just before a bounded source emits `MAX_WATERMARK`. - **Timer state TTL** - Must exceed the sliding-window expiration period. - If the timer fires after its associated state has expired, `timerState.get()` returns null and the decrement is skipped. - This would leave counts artificially high after delays or recovery. - The state is manually cleaned up after timer processing. ## RocksDB and Flink Runtime Tuning Once the system was serving real-time results, operational metrics exposed different bottlenecks in each application. - The minutes application initially experienced RocksDB Write Stalls caused by pressure on the shared Write Buffer Manager. - RocksDB first stores writes in MemTables and flushes them into SST files organized across levels L0–L6. - Flink maps managed state types such as `MapState` and `ValueState` to separate RocksDB Column Families. - Because multiple Column Families share the Write Buffer Manager’s memory budget, write-heavy workloads require careful tuning of RocksDB memory and write paths. - The hours and days applications require different optimizations focused on cache misses, CPU usage, checkpoint I/O, and level management. ## Practical Conclusion For real-time frequency capping, a unified Flink-based design can simplify serving and improve sliding-window accuracy, but long windows should not automatically be combined with short ones in a single job. Separate applications, state-as-SSOT, distinct backfill and catch-up pipelines, and workload-specific RocksDB tuning are essential for maintaining correctness and operability at scale.

Read original(opens in new tab)
toss3 min readCurated summary

It Almost Ended Up Ugly - The Making of Toss Front 2

Toss redesigned its Front 2 payment terminal by addressing real-world usability problems rather than settling for technically workable solutions. The redesign moved NFC to the front, made the card reader field-replaceable, and reworked the internal structure to simplify removal. The result was a smaller, cleaner device that improved both customer experience and repairability. ## Moving NFC to the Front - The first-generation terminal placed NFC on the right side because other components interfered with the signal. - This was inconvenient in narrow retail spaces, where users had little room to tap cards or phones. - Several alternatives were tested: - Moving the card reader upward made card insertion awkward and strained users’ wrists. - Enlarging the top made the vertically oriented terminal look excessively long and displaced the camera, complicating barcode and face-payment use. - Placing NFC around the camera caused interference, producing camera shake and reducing recognition accuracy. - The team reframed the problem by asking whether the display’s metal backing could be replaced. - A customized plastic backing allowed NFC signals to pass through while reinforced glass preserved the display’s rigidity. - Despite higher manufacturing complexity and cost, the design was successfully mass-produced, enabling reliable front-facing NFC without sacrificing appearance. ## Designing a Replaceable Card Reader - The first-generation card reader was integrated into the main body, so failures required repairing or replacing the entire terminal. - Repairs took more than a week on average, forcing stores to use backup devices and distributors to maintain extra inventory. - Front 2 introduced a docked, replaceable card reader designed for easy on-site replacement. - A USB-C connector was selected because users already understand how to connect and disconnect it. - The connector provided stable attachment without exposing additional brackets or mechanisms, preserving the product’s clean appearance. ## Making Removal Simple - Once the reader used USB-C, the team needed a way to remove it without adding buttons, levers, or protruding parts. - The simplest approach was to insert the reader from the front and push it out from behind, but existing power and network connections blocked the necessary space. - Instead of adding another mechanism, the team redesigned the internal layout from scratch. - The circuit board and connectors were tilted toward the top of the device, requiring redesigned and inverted cable components. - This created enough room to remove the reader without tools. - The revised layout also made the cables easier to see and connect. ## Results of Front 2 - Front-facing NFC made payments more natural on crowded counters. - The USB-C dock reduced the difficulty of replacing a failed card reader. - The terminal became smaller while retaining its visual simplicity and design quality. - Front 2 surpassed the first generation’s sales immediately after launch, while previous customer complaints shifted toward positive feedback. ## Building Quality Through Persistent Questions - The article argues that product quality comes from repeatedly challenging an acceptable technical solution. - The team focused on finding answers that were right for users and the overall product experience, not merely answers that functioned. - For similar design problems, the recommended questions are: - Can everyone use the design easily, including in edge cases? - What is the fundamental problem? - Is the current solution truly the best one? - If not, can the problem and solution direction be redefined? The practical lesson is to keep revisiting the problem until the solution is not only feasible, but genuinely appropriate for users.

Read original(opens in new tab)
toss3 min readCurated summary

Layers of your time : Celebrating the time spent with Toss

The article argues that effective internal branding is not about making attractive company merchandise, but about designing meaningful experiences around employees’ time and contributions. Through an eight-month redesign of Toss’s work-anniversary gift, the designer created a layered light that visually represents accumulated years, protected quality despite production delays, and carefully designed the delivery experience. The project concludes that strong internal branding requires a clear reason, end-to-end experience design, and unwavering standards. ## From Merchandise to a Celebration of Time - Toss celebrates employees’ work anniversaries with annual gifts such as medals, wine, and cubes. - Over time, some employees began giving the gifts away, suggesting they had become clutter rather than meaningful keepsakes. - The redesign aimed to: - Sincerely celebrate each employee’s time at the company. - Show appreciation for the six-month gap while the gift was being redesigned. ## Three Criteria for the New Gift The new product had to: - Avoid being immediately stored away in a drawer. - Physically show the accumulation of time. - Remain beautiful whether celebrating one year or ten years. A layered lamp was chosen because employees could add one disk for each anniversary. As the disks accumulated, the layers of light became deeper, making the passage of time visible through the object’s structure. ## Hardware Development and Quality Control - The designer had no previous hardware or lighting-production experience. - The team repeatedly tested: - Disk thickness, including differences as small as 0.5 mm. - The spacing between the lamp body and disks. - Light intensity as more disks were added. - The product was divided into two versions: - White for years 1–10. - Black from year 11 onward, symbolizing the beginning of a new period. - Dozens of defects appeared during final factory inspection. - Rather than compromise quality to meet the schedule, distribution was delayed. - Approximately 5,000 lamps were individually inspected and improved. ## Giving the Product a Warm Voice - The lamp was named **Layered Lighting**. - The phrase **“Layers of your time at toss”** was engraved on the lamp and packaging. - The communication emphasized remembrance and celebration rather than corporate motivation. - Serif typography, carefully matched packaging, and handwritten name cards created a warmer, more personal experience. ## Designing the Moment of Delivery - Instead of asking employees to pick up their gifts, the team placed them directly at employees’ desks. - The redesigned process gave employees the correct number of disks for their accumulated tenure. - The intended experience was: - Discovering the gift on a Monday morning. - Opening the box and reacting with surprise. - Taking photos and sharing the moment with colleagues. - Over one weekend, the team placed gifts at 2,500 desks among approximately 3,900 employees. - The operation took 26 hours. - Employee photos and reactions spread across Slack and Instagram, including one memorable comment: “I now have a reason to stay another year.” ## Principles of Good Internal Branding - **Start with the reason:** Every object or graphic should clearly communicate why it exists. - **Design the experience, not just the object:** The interaction begins before the product is opened and includes how it is received and shared. - **Protect the standard until the end:** Internal projects are easy to compromise because their results may not be immediately visible, making a clear standard essential. Good internal branding helps employees feel that they belong to a good team. That sense of belonging can strengthen engagement and ultimately improve the quality of the work they create.

Read original(opens in new tab)
toss3 min readCurated summary

Why Toss reduced its design roles to two

On April 1, Toss’s Design Chapter consolidated six design roles into two: Product Designer and Visual Designer. The change reflects how role boundaries had already blurred as designers crossed disciplines and technology reduced the importance of tool-specific expertise. Toss’s central argument is that designers should be organized around judgment and user problems—not the tools, media, or screens they work with. ## Why Role Boundaries Became a Problem - The previous structure separated designers by tools and outputs rather than by the decisions they made. - Ambiguity emerged in areas such as: - Whether interaction in a design system belonged to Platform or Interaction Designers - Whether interactive graphics should be handled through Lottie, code, or UI design - Whether expanding a PC product to mobile belonged to a Tools Product Designer or Product Designer - These divisions sometimes determined ownership based on medium instead of capability or context. ## Designers Were Already Crossing Disciplines - Tools Product Designers began designing mobile products. - Interaction Designers worked on parts of internal design tools. - Graphic Designers created semantic icon systems. - Platform Designers built interactive web pages. - Brand Designers with visual-design backgrounds worked on lighting products. - AI and other tools have shortened the time needed to learn formerly specialized skills, including: - Video and Lottie production - Figma prototyping - Coding interactive experiences - As tool proficiency becomes less differentiating, the ability to judge what creates a good experience becomes more important. ## Product Designer - Product Designer and Tools Product Designer were merged into one role. - The distinction between mobile and PC disappeared. - The role now focuses on: - Understanding the user’s context and problems - Deciding how those problems should be solved - Designing across screen sizes and product environments ## Visual Designer - Platform, Interaction, Graphic, and Brand Designers were combined into Visual Designer. - Visual Designers are expected to work across media and produce what the experience requires, such as: - Building interactions within systems - Creating icons for prototypes - Designing interactive web experiences - The defining capability is visual judgment: deciding what is beautiful, appropriate, and correct. - The title was chosen to emphasize visual decision-making rather than a specific medium or technique. ## Lessons from Other Industries - Disney animation reduced many physical and intermediate production steps through software while preserving stages requiring important creative judgment. - Digital audio workstations allow artists such as Billie Eilish and Finneas to compose, perform, record, and mix with a laptop, but human judgment about what sounds good remains essential. - Digital cinema and streaming weakened the historical distinction between film and television production. - Across these industries, tools converged while the value of creative judgment increased. ## What Comes Next - The new job structure will not immediately change how people work. - Toss still needs to redesign hiring standards, onboarding, and career-development paths. - The consolidation is intended to give designers broader ownership and more room to make decisions across disciplines, ultimately improving the experiences delivered to users.

Read original(opens in new tab)
toss3 min readCurated summary

97% Smaller, 2x Faster: How es-toolkit Reached 10 Million Weekly Downloads

es-toolkit is a modern, TypeScript-first JavaScript utility library designed as a faster and smaller alternative to lodash. Built around ES Modules and independent functions, it can reduce bundle sizes by up to 97% and improve runtime performance by more than 2x. Its `es-toolkit/compat` package provides a 100% lodash-compatible migration path with little or no code changes. ## Why es-toolkit was created - Toss’s frontend team saw an opportunity to modernize the utility-library ecosystem. - lodash was designed before ES Modules, advanced JavaScript engines, TypeScript, and bundle size became central concerns. - es-toolkit was built from scratch with: - Native ES Module support - Tree-shaking-friendly independent functions - Built-in TypeScript definitions - Modern runtime optimizations ## Bundle size and runtime performance - lodash-es can include internal helper dependencies even when importing a single function. - es-toolkit functions are designed to be independent, avoiding hidden dependencies. - A sample set of five functions—`groupBy`, `keyBy`, `pick`, `omit`, and `debounce`—adds roughly: - 30 KB with lodash-es - 1 KB with es-toolkit - The library reports up to 97% smaller bundles and more than 2x faster execution. - Specific benchmarks include: - `sample`: approximately 2,000 bytes in lodash versus 88 bytes in es-toolkit - `omit`: approximately 11.8x faster at runtime ## Adoption and ecosystem support - es-toolkit surpassed 10 million weekly npm downloads within 18 months. - It has been adopted by Microsoft, Yarn, Storybook, IBM, Recharts, Ink, and Dify. - The article emphasizes that adoption came through independent evaluations and benchmarks rather than major promotional campaigns. ## Migration from lodash - Most imports can be changed directly: ```ts import { pick } from 'es-toolkit'; ``` - `es-toolkit/compat` provides a drop-in lodash replacement with full compatibility, validated against lodash’s test suite. - Existing projects can redirect the `lodash` dependency without changing source code: ```json { "dependencies": { "lodash": "npm:es-toolkit@^1.44.0" } } ``` - Teams can later migrate from compatibility imports to native es-toolkit imports for additional bundle and performance benefits. - An official `@es-toolkit/codemod` tool is available to automate migration. ## TypeScript and maintenance - Type definitions are shipped alongside the implementation and are kept synchronized. - This avoids the version mismatches and inaccuracies possible with lodash’s separately maintained `@types/lodash` package. - The project is actively maintained, with regular additions and responsive issue and pull-request handling. ## Project direction - es-toolkit is part of Toss’s broader open-source initiative. - Related projects include: - `overlay-kit` for Promise-based React overlays - `use-funnel` for type-safe multi-step flows - `suspensive` for React Suspense primitives - The library is MIT licensed and installable with `npm install es-toolkit`. For most lodash users, the recommended approach is to start with the compatibility alias for an immediate, low-risk upgrade, then progressively adopt native es-toolkit imports to maximize bundle-size and performance improvements.

Read original(opens in new tab)
toss3 min readCurated summary

Metric Review, Driving Execution

Metric Review is Toss Place’s weekly operating system for turning data insights into product and business action. By connecting OKRs to a hierarchy of driver metrics, analysts continuously detect risks, test hypotheses, and encourage execution rather than merely reporting results. The approach has improved data literacy and helped teams contribute directly to company-level Key Results. ### Building a Data-Literate Organization - Toss Place aims for everyone—not only analysts—to perform effective analysis. - The Data Platform Team strengthens data quality and infrastructure, while the Data Analysis Team provides domain knowledge and delivery capabilities. - Analysts are expected to develop three complementary skills: - Technical expertise with data and analysis tools - Logical communication - Deep product and business knowledge ### Why Metric Review Matters - Metrics serve as a shared language for aligning teams around organizational goals. - Metric Review helps teams identify: - Whether goals are on track - Emerging risks - New opportunities - Analysts act as **Metric Owners**, providing insights that support better decisions and following through until actions and outcomes are verified. ### Operating Model #### OKR-Linked Metric Hierarchy - Company-level Key Results flow down to team and silo-level Key Results. - The levers that influence each team’s KR become its driver metrics. - This hierarchy provides the structure for identifying opportunities and threats. #### A Continuous Analysis Cycle - The operating cycle is: - Goal setting → hypothesis formation → validation and execution → insight discovery - Metric Review translates this into: - Metric analysis → hypothesis testing → insight sharing → driving action - Exploratory data analysis (EDA) is also conducted when metric movements suggest deeper questions. #### Weekly Consistency - Reviewing metrics weekly helps teams detect small changes before they become significant. - Regular analysis also builds domain knowledge by requiring analysts to understand why metrics rise or fall. - Monthly or occasional reporting may explain past performance but often misses the window for timely action. ### Examples of Business Impact #### Growth Tribe: Establishing Shared Metrics - Weekly metric reviews initially focused on reporting performance and interpretation. - Over time, the practice changed how teams worked: - Designers defined product hypotheses around target metrics and incorporated logging requirements into designs. - Backend developers collaborated with analysts on analysis-friendly data structures. - Client developers prioritized measurable events when implementing logs. - Product Owners combined qualitative feedback with quantitative results to determine whether goals were on track. - This created a feedback loop that contributed to successful product launches and improved company metrics. #### POS Tribe: Segment-Specific Solutions - POS adoption varied significantly across partner dealerships. - Analysts used clustering to identify groups with different adoption patterns. - Product teams combined cluster analysis with interviews to design tailored interventions: - Low-adoption groups received stronger education and onboarding. - High-adoption groups received simplified store creation and installation flows. - Segment-specific actions accelerated POS expansion more effectively than a single broad solution. #### Supply Chain: Forecast-Based Optimization - Because Toss Place manufactures and distributes hardware, supply-chain metrics are strategically important. - Analysts and the SCM team monitored: - Device shipments - Market installation rates - Inventory and ordering forecasts - Potential improvement areas - Hypothesis-driven actions helped optimize distribution and reduce costs. ### How the Organization Changed - Analysts became Metric Owners rather than report writers. - Product teams began asking, “Which metric should we move?” before asking what to build. - Business teams increasingly aligned strategies using quantitative evidence. - Repeated Metric Reviews strengthened organization-wide data literacy and contributed to meaningful company Key Result achievement. The practical recommendation is to evaluate analysis by whether it leads to measurable action. Teams should structure problems, create testable hypotheses, define follow-up metrics, and maintain a consistent review rhythm until the execution loop is closed.

Read original(opens in new tab)
toss3 min readCurated summary

Automating Service Vulnerability Analysis using LLM #2

The post explains how Toss Security Research improved AI-driven vulnerability analysis in a research network. Its main challenges were efficiently providing large codebases to an AI and making analysis results consistent and complete. The solution combined a custom code-browsing MCP server with SAST tools used not to identify vulnerabilities directly, but to enumerate all input-to-function paths that the AI must review. ## Efficiently Providing Large Codebases - Tools such as Cursor and Claude Code can search large projects, but primarily rely on pattern matching with tools like ripgrep. - Without prebuilt indexes, they may miss relevant code or waste tokens exploring unnecessary files. - The team built an MCP server that: - Uses **ctags** to index symbol definitions. - Uses **tree-sitter** to parse function boundaries. - Allows AI to access code remotely, similar to IDE features such as “Go to Definition” and “Find References.” ### SourceCode Browse MCP The MCP server provides four main tools: - **`find_references()`** - Searches for symbols or patterns using ripgrep. - Returns file paths, line numbers, snippets, total matches, and whether results were truncated. - **`read_definition()`** - Looks up definitions through the ctags index. - Returns metadata such as file, line, symbol type, language, signature, and scope. - Uses tree-sitter to include the complete function body when requested. - **`read_source()`** - Reads a configurable number of lines before and after a target line. - Lets the AI retrieve only the relevant local context instead of entire files. - **`get_project_structure()`** - Returns the indexed project’s directory structure. - Provides the AI with a project “blueprint,” which is especially important in remote environments where it cannot inspect the repository locally. The MCP workflow is to locate relevant symbols with `find_references()` and `read_definition()`, inspect nearby code with `read_source()`, and use `get_project_structure()` to understand the overall project. ## Improving Consistency and Accuracy - AI analysis produced inconsistent results: for example, it might find all 10 XSS vulnerabilities in one run but only 8 in another. - This variability made the results difficult to trust. - The team combined AI analysis with SAST tooling to ensure complete coverage. ## Using SAST to Enumerate Review Candidates - Rather than passing SAST-detected vulnerabilities directly to the AI, the team used SAST as a candidate-generation tool. - This avoids limiting the AI to vulnerabilities that the SAST engine itself knows how to detect. - SAST extracts every location where untrusted input enters the application and tracks its possible flow to function calls. - Custom Semgrep taint rules identify sources such as: - Spring `@RequestParam` - `@PathVariable` - `@RequestHeader` - Fields read from `@RequestBody` DTOs - `@RequestPart` - `@ModelAttribute` - `@RequestAttribute` - Potential sinks include generic function calls and object method calls. - The AI then reviews every extracted source-to-sink path, combining the completeness of static analysis with the broader reasoning ability of an LLM. The overall approach is to use deterministic indexing and SAST for coverage, while relying on AI for deeper vulnerability interpretation.

Read original(opens in new tab)
toss3 min readCurated summary

Embracing the Software 3.0 Era

Software 3.0 replaces hand-written rules with natural-language instructions to LLMs, but models alone cannot reliably perform real-world work. The missing piece is the harness: tools, context, and environments that connect an LLM to codebases, commands, databases, and users. Claude Code illustrates how familiar Software 1.0 architecture can guide agent design while adding a new capability—asking humans for judgment when uncertainty arises. ## From Software 1.0 to Software 3.0 - **Software 1.0:** Developers explicitly write logic using languages such as Python, Java, or C++. - **Software 2.0:** Data and training produce neural-network weights that function as the program. - **Software 3.0:** Prompts and natural-language instructions direct LLM behavior. - Karpathy’s central claim is that Software 3.0 is increasingly absorbing both traditional code and trained models. ## Harnesses Make LLMs Useful - A raw LLM cannot independently read a codebase, execute commands, modify files, or access databases. - A **harness** supplies the tools and environment needed to turn model capability into practical work. - Claude Code is presented as a harness for Claude: it transforms a language model into an agent capable of completing and shipping tasks. ## Mapping Agent Concepts to Layered Architecture The terminology of agent systems can be understood through familiar Software 1.0 design patterns: - **Slash commands → Controllers** - They serve as entry points for user requests, such as `/review` or `/refactor`. - **Sub-agents → Service layer** - They coordinate multiple skills to complete a workflow. - Each sub-agent has an independent context and acts as a self-contained unit of work. - **Skills → Domain components** - Each skill should have one focused responsibility, such as reviewing code, generating tests, or writing documentation. - **MCP → Infrastructure or adapters** - MCP provides abstraction boundaries for external systems such as APIs and databases. - **CLAUDE.md → Project constitution** - It records stable project information: technology choices, conventions, and build commands. - Frequently changing task details should be provided through the conversation or injected into an agent’s context instead. ## Agent Design Has Familiar Anti-Patterns Traditional code smells also apply to agent systems: - **Feature Envy:** A skill relies excessively on another skill’s data. - **Duplication:** Prompts are copied across multiple skills. - **Long Method:** A single sub-agent performs an overly long sequence of many skills. - Clear boundaries, single responsibility, and limited coupling remain valuable. ## The Difference: Agents Can Ask Humans Layered architecture generally requires every failure and edge case to be handled through predefined exceptions, policies, or branches. - Traditional code must decide what to do when an unusual case occurs. - An agent using human-in-the-loop interaction can pause and ask the user for clarification. - In this model, exceptions become questions, allowing the agent to continue after receiving a decision. Agents should ask when: - An action is difficult to reverse, such as deletion or deployment. - Several valid options exist without a clear best choice. - The decision has significant consequences. They should proceed automatically when: - The operation is safely repeatable. - Existing conventions provide a clear answer. - The action is easy to undo. ## What Carries Forward into Software 3.0 The new paradigm does not make established engineering practices irrelevant. - Move away from explicitly coding every possible rule and edge case. - Do not reduce LLMs to simple autocomplete tools. - Preserve layered design, single responsibility, abstraction, dependency management, and interface design. - Continue emphasizing testability, debugging, code review, and iterative improvement. The practical approach is to combine Software 3.0’s flexible reasoning with Software 1.0’s architecture and engineering discipline, while giving agents a clear way to involve humans when decisions require judgment.

Read original(opens in new tab)
toss3 min readCurated summary

Foreign User Research: Why

Toss investigated why many foreign users struggle to use Korea’s financial services, even after signing up. Research showed that confusing identity verification, name formatting, and address entry often prevented users from completing registration, forcing them to visit bank branches for routine tasks. By redesigning the name-entry and authentication process, Toss increased the foreign-user verification completion rate by about 15% and eliminated the gap with Korean users. ## Investigating Foreign Users’ Financial Experiences - Foreigners often perceive Korea’s banking system as complex and difficult to navigate without assistance. - Toss wanted to make its “finance for everyone” vision include foreign residents. - The team suspected that several verification steps caused users to abandon registration: - Preparing a foreigner registration card - Mismatches in telecom-provider information - One-won account verification - Difficulties entering names and personal details ## Field Research with Blue-Collar Workers - The team focused especially on blue-collar foreign workers, whose financial habits were less understood than those of students or white-collar workers. - Initial attempts to arrange factory interviews failed, so researchers visited the Siheung Industrial Complex during lunch hours. - Street interviews were difficult because formal clothing, identification badges, and consent documents made passersby cautious. - A more casual approach helped the team conduct several interviews. - Researchers later visited a multicultural center in Pocheon, where they met foreign residents from different countries and with varying lengths of stay. ## Why Foreign Users Rely on Bank Branches - Mobile banking often felt like a complicated system that users could access only after repeated trial and error. - Many users abandoned the process before reaching any financial-service features. ### Name Entry and Identity Verification - Users were unsure how to format their names: - Where to place spaces - Whether to enter family names first - Whether to match their foreigner registration card, bank account, or telecom records - A name such as “BRAD PITT” might need to be entered in an unexpected format, such as “BR AD.” - Some users repeatedly failed verification because their name format differed across institutions. - One participant had never successfully completed online identity verification under their own name in eight years. - Error messages rarely explained the actual cause of failure. - After five or more failed attempts, users could no longer continue. ### Address Entry - Entering Korean addresses was another major barrier, especially for users unfamiliar with typing Korean. - Users tried postal codes, English addresses, and lot numbers, then searched through address lists. - Search results often displayed too many options, making the correct address difficult to locate. - Repeated unsuccessful searches led some users to abandon registration and visit an offline branch instead. ## Improving the Authentication Funnel - Research identified name entry and authentication as the primary causes of foreign-user drop-off. - Toss’s product team redesigned the name-input structure and authentication flow. - The changes increased the foreign-user authentication completion rate by approximately 15%. - The completion-rate gap between Korean and foreign users was ultimately eliminated. Toss’s research demonstrates that inclusive financial services require understanding users who are often overlooked. Removing small but fundamental barriers in registration and authentication can make digital banking accessible to a much broader population.

Read original(opens in new tab)
toss3 min readCurated summary

From Intern to Solo Designer: Growth

As a Toss Bank product design intern, Jeon Nuri designed experiments to improve non-member sign-up conversion. She prioritized the funnel using speed and impact, studied previous experiments, and learned that clear, narrowly defined hypotheses were more valuable than constantly generating new ideas. The experience showed that failed experiments can still guide better decisions when they produce actionable learning. ## Prioritizing the Right Funnel Stage - The largest drop-offs occurred in the intro, consent, and identity-verification screens. - Consent and identity verification were shared modules requiring legal and compliance review, making rapid iteration difficult. - The intro screen could be changed more quickly and had the potential to affect the greatest number of users. - Based on this speed-versus-impact assessment, she chose the intro screen as the starting point. ## Learning from Previous Experiments - Instead of immediately designing new concepts, she reviewed existing experiments, including both winners and unsuccessful variations. - She examined: - The problem each experiment addressed - The reasoning behind its hypothesis - How the test variation was designed - Experiments from unrelated screens were also useful because their problem definitions and hypothesis structures could be adapted. - The main lesson was that inexperienced experimenters benefit more from systematically analyzing existing learning than from rushing to create new ideas. ## First Experiment: A Counselor Concept - The first variation presented benefits as if they were being recommended by a counselor and offered a small number of choices. - The hypothesis was vague: fewer choices would increase conversion. - The result was negative: - Click-through rate fell by more than 10%. - Conversion rate fell by more than 3%. - The design actually introduced more choices than the original, which had only one CTA button. - The experiment also failed to consider why users had entered the screen and whether they needed recommendations. - This led her to analyze the existing screen and user context before creating a hypothesis. ## Identifying and Solving Concrete Problems - Rather than inventing an entirely new design, she identified two specific weaknesses in the existing version: - The copy did not clearly communicate benefits users cared about. - Images loaded slowly, taking two to three seconds on low-end devices. - Previous experiments showed that users responded well to messages about high interest rates and receiving interest daily. - She incorporated those themes into the copy and optimized the visuals with newer graphics and lower-weight image formats. - Both click-through rate and conversion rate increased, demonstrating that a hypothesis grounded in clear problems can provide a stable direction for design. ## Making Benefits Easier to Imagine - Building on the earlier results, she changed functional wording into language that helped users imagine a concrete situation and immediate benefit. - Instead of simply explaining that interest could be earned after depositing money for one day, the revised copy foregrounded the moment when users would experience the benefit. - Copy alone increased CTR by 5% and also produced a meaningful improvement in CVR. - The result reinforced that different expressions of the same information can create significantly different first impressions. ## Principles for Designing Experiments - Break the funnel into stages and prioritize opportunities by speed and potential impact. - Understand the existing context before defining the core problem. - Study previous experiments through their hypotheses and problem definitions, not just their numerical outcomes. - Establish a clear hypothesis and success metric before designing the variation. - Make sure the experiment visibly tests the stated hypothesis. - Treat failure as input for the next decision rather than as wasted effort. A practical starting point for new designers is to begin with a small, focused experiment—but make the hypothesis precise enough to guide both the design and the next iteration.

Read original(opens in new tab)
toss3 min readCurated summary

Easy-to-use Toss Front SDK

The post argues that an SDK’s stability depends not only on its internal implementation but also on how safely users can interact with it. Low-level APIs may expose every operation clearly, yet still allow human errors such as missing event handlers or cleanup. The recommended solution is an intent-driven Facade interface that simplifies common workflows, prevents misuse, and still provides low-level escape hatches for advanced cases. ## Designing an SDK That Is Easy to Use - Toss Place develops an external SDK for Toss Front payment terminals. - The SDK allows third-party developers to build plugin apps that integrate with Toss services and run on the terminal. - A simple-looking server API might require users to: - Open a server. - Register connection, message, and error handlers. - Remove handlers. - Close the server. - This approach exposes implicit responsibilities to SDK users: - A message callback might never be registered after a connection. - Handlers might not be removed before shutdown. - Improper cleanup can cause memory leaks and operational issues. - Therefore, third-party implementation mistakes can directly affect platform reliability. - A safer interface hides unnecessary internal steps: ```ts const server = await sdk.start({ onConnection, onMessage }); await server.stop(); ``` ## Facade as an Intent-Driven Interface - The Facade pattern is commonly described as wrapping a complex subsystem with a simpler interface. - In SDK design, its deeper purpose is to reorganize complexity around user intent rather than merely hide functionality. - Users should express goals such as: - “Start a server” - “Upload a file” - “Request a payment” - Internal concerns—including authentication, retries, state management, listener registration, and cleanup—should be handled by the SDK. - AWS CDK illustrates this distinction: - **L1 constructs** closely represent raw CloudFormation resources and provide fine-grained control. - **L2 constructs** provide intent-based APIs, such as creating a versioned S3 bucket with `versioned: true`, while handling the underlying configuration automatically. - The goal of a Facade is to reduce cognitive load and coupling, not simply to conceal every lower-level capability. ## Combining High-Level and Low-Level APIs - A well-designed SDK should provide both abstraction levels: - **High-level Facade:** Handles the roughly 80% of common use cases through complete workflows. - **Low-level APIs:** Serve as escape hatches for the roughly 20% of specialized cases requiring precise control. - In the example: - The Facade’s `start()` method opens the server, registers listeners, coordinates connections, and returns a unified server handle. - Low-level APIs separately expose operations such as `open`, `close`, `send`, `disconnect`, and event listeners. - This layered design improves immediate developer experience while preserving long-term compatibility and extensibility. ## Trade-offs and Escape Hatches - Higher-level abstractions inevitably reduce some flexibility. - Specialized requirements—such as keeping one connection while closing others—may not fit the Facade workflow. - As orchestration becomes more sophisticated, the SDK maintainers inherit additional implementation and maintenance costs. - Low-level escape hatches are therefore essential: users should be able to bypass the Facade when they need detailed control. ## Practical Recommendation Design SDK APIs around user intent and automate error-prone lifecycle management wherever possible. Offer a concise Facade for common workflows, but retain well-defined low-level interfaces so advanced users are not blocked by the abstraction.

Read original(opens in new tab)
toss4 min readCurated summary

The Software 3.0

The post argues that teams using the same LLM can achieve very different results because individual knowledge of context engineering varies widely. Claude Code’s plugins and marketplace could help turn personal LLM techniques into shared, executable team workflows, raising the organization’s productivity floor. The author presents this as a forward-looking hypothesis rather than a proven success story. ## The Frictionless Harness - LLM adoption loses effectiveness when developers must switch between terminals, browsers, and chat tools. - Claude Code’s terminal-based TUI reduces context switching by combining natural-language instructions and code in the developer’s existing environment. - This low-friction experience makes it easier to distribute standardized workflows across a team. ## Executable Single Source of Truth - Wikis and Notion pages become outdated because they are designed primarily for human reading. - Claude Code plugins can serve as “executable SSOT”: - Humans can read them as guidelines and manuals. - LLMs can interpret them as precise system instructions. - Updating a plugin can immediately change how team agents behave, keeping operational knowledge aligned with current practices. ## Raising the Team’s Productivity Floor - Teams have significant differences in LLM literacy, independent of coding ability. - Generic open-source plugins can provide shared best practices, but they lack company- and domain-specific context. - Each domain needs its own rules for: - Tasks the AI can perform autonomously. - Tasks requiring human approval through HITL processes. - The goal is to minimize human intervention while preserving approval at critical points. ## Extending Platform Engineering into Software 3.0 - AI workflows resemble traditional internal platform components such as authentication, logging, and payment libraries. - The analogy is: - Common software modules → AI workflow plugins - Library distribution → Marketplace publishing - The implementation changes from traditional code to prompts and agent logic. - AI workflows should receive the same quality practices as software modules, including review, optimization, and feedback on token usage and failure cases. - Marketplace-based collaboration could turn individual prompting techniques into shared organizational intelligence. ## Why Use a Marketplace Instead of Only RAG? - RAG systems can make it difficult to predict which context will be retrieved due to search, reranking, and indexing behavior. - Plugins provide more explicit and controllable instructions and code. - Developers can modify and test workflows locally in the TUI without deploying a server. - With the Claude Agent SDK, workflows validated locally could also run in server environments, improving development-production parity. - The marketplace could become the shared source of truth between experimentation and production. ## Marketplace as a Workflow Distribution Platform - Teams could package coding conventions, Git strategies, lint rules, and testing policies into private plugins or registries. - Hooks could actively correct behavior rather than merely reject violations—for example, preventing commits on `main` and creating a `feature/` branch instead. - Slash commands could distribute the best engineer’s workflow to everyone: - `/new-feature` gathers requirements. - Creates a Jira issue and branch. - Produces an implementation plan for approval. - Implements the feature and opens a pull request. - This allows less experienced users to follow a reliable, high-quality process without reproducing it manually. ## Layered Context Architecture The author proposes separating plugin knowledge into three layers: - **Global layer:** Organization-wide security rules and coding standards. - **Domain layer:** Business-specific knowledge for areas such as payments, settlement, or membership. - **Local layer:** Repository-specific implementation details and conventions. This structure avoids overwhelming the LLM with irrelevant information and creates a “living knowledge base” made of maintainable prompts and code rather than static documents. ## The Data Flywheel Hypothesis - Standardized plugins could generate high-quality instruction-tuning data. - Accumulated workflow data might eventually support domain-specific model fine-tuning. - Existing workflows could also provide evaluation criteria for those models. - Success would require sustained data collection, quality controls, and long-term organizational investment. - The proposed flywheel is: more usage creates more data, better data improves models, and better models encourage further usage. The practical recommendation is to treat LLM expertise as an organizational system rather than an individual skill. Teams should begin packaging their implicit knowledge, approval rules, and proven workflows into versioned, domain-aware plugins that can be tested, reviewed, and distributed through a marketplace or private registry.

Read original(opens in new tab)
tossOriginal article

From Perimeter Security to Zero (opens in new tab)

Toss Payments transformed its security infrastructure from a vulnerable, single-layered legacy system into a robust "Defense in Depth" architecture spanning hybrid IDC and AWS environments. By integrating advanced perimeter defense, internal server monitoring, and container runtime security, the team established a comprehensive framework that prioritizes visibility and continuous verification. This four-year journey demonstrates that modern security requires moving beyond simple boundary protection toward a proactive, multi-layered strategy that assumes breaches can occur. ### Perimeter Defense and SSL/TLS Visibility * Addressed the critical visibility gap in legacy systems by implementing dedicated SSL/TLS decryption tools, allowing the team to analyze encrypted traffic for hidden malicious payloads. * Established a hybrid security architecture using a combination of physical DDoS protection, IPS, and WAF in IDC environments, complemented by AWS WAF and AI-based GuardDuty in the cloud. * Developed a collaborative merchant response process that moves beyond simple IP blocking; the system automatically detects malicious traffic from partners and provides them with detailed vulnerability reports and remediation guides (e.g., specific SQL injection points). ### Internal Network Security and "Assume Breach" Monitoring * Implemented **Wazuh**, an open-source security platform, in IDC environments to monitor lateral movement, collect centralized logs, and perform file integrity checks across diverse operating systems. * Leveraged **AWS GuardDuty** for intelligent threat detection in the cloud, focusing on malware scanning for EC2 instances and monitoring for suspicious process activities. * Established automated detection for privilege escalation and unauthorized access to sensitive system files, such as tracking instances where root privileges are obtained to modify the `/etc/passwd` file. ### Container Runtime Security as the Final Defense * Adopted **Falco**, a CNCF-hosted runtime security tool, to protect Kubernetes environments by monitoring system calls (syscalls) in real-time. * Configured specific security rules to detect "container escape" attempts, unauthorized access to sensitive files like `/etc/shadow`, and the execution of new or suspicious binaries within running containers. * Integrated **Falco Sidekick** to manage security events efficiently, ensuring that anomalous behaviors at the container level are instantly routed to the security team for response. ### Zero Trust and Continuous Verification * Shifted toward a Zero Trust model for the internal work network to ensure that all users and devices are continuously verified regardless of their location. * Focused on implementing dynamic access control and the principle of least privilege to minimize the potential impact of credential theft or device compromise. Organizations operating in hybrid cloud environments should move away from relying on a single perimeter and instead adopt a multi-layered defense strategy. True security resilience is achieved by gaining deep visibility into encrypted traffic and maintaining granular monitoring at the server and container levels to intercept threats that inevitably bypass initial defenses.

tossOriginal article

6 Principles to Increase Marketing (opens in new tab)

Toss, a leader in the Korean fintech space, demonstrates that high marketing performance can be achieved without resorting to aggressive or deceptive copy. By analyzing hundreds of A/B tests within their app, they have identified specific UX writing patterns that prioritize user trust while significantly boosting engagement. The core conclusion is that clarity, psychological ease, and guaranteed rewards consistently outperform complex value propositions and exaggerated claims. ### The Power of One Core Message * Focusing on a single, immediate action is more effective than listing multiple service benefits. * In one test, replacing a complex benefit-driven headline with a simple "Take a 10-question test" resulted in a 10x increase in click-through rates (CTR). * Complexity creates friction; users are more likely to engage when they understand exactly what the next step entails without distractions. ### Prioritizing Guaranteed Rewards * Users show a stronger preference for "guaranteed small wins" over "potential big wins." * A campaign promising a "Minimum 100 won" reward saw 20x more exposure than one promising "Up to 1 million won," as large numbers can trigger skepticism or feel unattainable. * Phrases like "You will definitely get 1" outperform "Get as many as you want" because they provide a concrete promise rather than a vague possibility. ### Reducing Cognitive Load Through "Light" Language * The choice of verbs significantly impacts the perceived effort of a task. * Using "Prepare for travel insurance" instead of "Sign up for travel insurance" reduces the psychological burden, as "sign up" implies a long, bureaucratic process. * "Light" verbs make the service feel faster and easier to complete, encouraging immediate action. ### Strategic Information Framing * Clearly defining the nature of information—whether it is a "collection," a "list," or "new"—helps users categorize the value quickly. * Highlighting that a feature is "new" rather than explaining the specific benefits of the feature increased CTR by 6x. * Using terms like "View collection" for loan products provides a sense of organized efficiency that appeals to users looking for consolidated information. ### Specificity in Action and Conditions * Ambiguity leads to hesitation; providing exact numbers (e.g., "4 missions" or "8 blanks") increases conversion rates. * Specifying the number of tasks makes a goal feel attainable and removes the fear of an open-ended time commitment. * Quantifying the effort required (e.g., "takes 3 minutes") allows users to make an instant, friction-less decision to participate. ### Utilizing Intuitive, Everyday Experiences * Copy that mirrors real-life physical actions is more intuitive for users. * Changing a button from "View answer" to "Pick an answer" (accompanied by a stamp emoji) for an OX quiz significantly increased engagement by making the digital action feel more tactile and familiar. * Leveraging common vocabulary ensures that users do not have to "translate" marketing speak into practical reality. To maximize conversion, designers and writers should move away from broad marketing claims and toward radical specificity. By removing ambiguity and promising certain, low-effort outcomes, you can build a more effective and honest user experience.