开发者
How NestJS Handles Secure Transactions in Banking Applications
Banking software cannot afford to be casual about anything. Every transaction needs to be verified, logged, protected from tampering, and traceable if something goes wrong. This is exactly the kind of environment where NestJS quietly shines, since its architecture was built around structure and discipline from the start, not added on as an afterthought. Financial institutions and fintech companies increasingly choose NestJS for banking applications, investment platforms, and trading systems, largely because it gives teams a consistent, testable structure for handling something as sensitive as money moving between accounts. Here is what that actually looks like underneath. Why structure matters more in banking than almost anywhere else In most applications, a messy folder structure or inconsistent error handling is annoying. In a banking application, it is a liability. If five different developers write five different ways of validating a transaction, you end up with five different ways something could slip through unnoticed. NestJS solves this by enforcing a consistent pattern across the entire application, modules, controllers, providers, all following the same shape no matter who wrote them. A new developer joining a banking backend built with NestJS already knows where to look for validation logic, where authorization happens, and where a transaction actually gets processed, because the framework itself dictates that structure. Guards, the first line of defense Every request that touches a bank account should be verified before it does anything else. NestJS handles this through guards, which run before a request ever reaches your actual business logic. @ Injectable () export class TransactionAuthGuard implements CanActivate { canActivate ( context : ExecutionContext ): boolean { const request = context . switchToHttp (). getRequest (); const user = request . user ; if ( ! user || ! user . isVerified ) { throw new UnauthorizedException ( ' Account verification req
AI 资讯
How I Turned My Personal Storage Accounts Into a Massive S3 Bucket for $0
As developers, we’ve all been there: you’re building a hobby project, a side hustle, or a microservice, and you need object storage. You look at AWS S3 or dedicated cloud providers, and the costs start adding up. Meanwhile, most of us have hundreds of gigabytes of idle, wasted space sitting in our personal Google Drive, Dropbox, or Mega accounts. I wanted to find a way to use that personal cloud storage programmatically—specifically as an S3-compatible bucket—without paying premium storage fees. But I had one strict rule for myself: The solution had to be 100% stateless. No caching files on my servers, no data retention, and zero storage costs on my end. Security and privacy meant that files had to exist on my infrastructure only in-flight as streaming data packets. Here is a deep technical breakdown of the architecture I built to make this happen using NestJS, Fastify, OpenDAL, and BullMQ in a monorepo structure. 1. The Core Architecture: A Monorepo Approach To keep performance blazing fast and maintain a clean separation of concerns, I broke the system down into three distinct, decoupled services inside a monorepo, sharing underlying core modules. Because raw Node.js HTTP overhead can become a bottleneck when proxying heavy streams, I swapped out Express for Fastify as the underlying HTTP provider for NestJS. ┌────────────────────────────────────────┐ │ Main API Server │ │ (Handles Auth, Web Dashboard, OAuth) │ └───────────────────┬────────────────────┘ │ │ (Pushes Sync/Heavy Tasks) ▼ ┌───────────┐ │ BullMQ │ └─────┬─────┘ │ ▼ ┌────────────────────────────────────────┐ │ Worker Server │ │ (Processes Heavy Background Jobs) │ └────────────────────────────────────────┘ ───────────────────────────────────────────────────────────────────────── ┌────────────────────────────────────────┐ │ S3-Compatibility Server │ │ (Streams Data / Translates S3 XML) │ └────────────────────────────────────────┘ The Main API Server: Handles user authentication, the web dashboard manageme
AI 资讯
From Scaling Data to Transcribing Voices: Building Resilience Under Pressure
As my backend engineering internship wraps up, I’ve been reflecting on the tasks that pushed me the hardest. Building minimum viable products is one thing, but making them resilient, scalable, and fault-tolerant is an entirely different beast. Here are two of the most memorable tasks from my time here—one solo dive into system scaling, and one team effort tackling asynchronous voice processing. Task 1: Scaling the Insighta Labs+ Query Engine (Individual) What it was Insighta Labs+ is a demographic intelligence platform where analysts and engineers run structured queries on user profiles via a CLI and a Web Portal (backed by GitHub OAuth and RBAC). My task was to take a functional MVP and evolve it into a robust query engine capable of handling tens of millions of records and hundreds of concurrent queries per minute. The problem it was solving The initial architecture worked flawlessly for a few thousand records, but under scale, it started showing cracks. Latency : Without indexing, every filter query triggered a full-table scan. Redundancy : Identical queries from different users wasted CPU and DB cycles. Write-Pressure : Users needed to bulk-upload CSVs containing up to 500,000 rows. Processing these synchronously locked the database, bringing read operations to a halt. How I approached it Instead of blindly throwing more server power at the problem, I focused on doing less work. Targeted Indexing : I added indexes only to frequently filtered columns. Caching & Normalization : I introduced Redis for TTL-based caching. To maximize cache hits, I built a query normalization layer. Whether a user queried "young males" or "men under 30" , the parser normalized the filter object into a canonical form before hashing the cache key. Connection Pooling : I set up PgBouncer to manage database connections and prevent exhaustion under high concurrency. Chunked Ingestion : For the massive CSV uploads, I implemented chunked streaming. Rows were validated individually; valid row
AI 资讯
Boosting Observability in NestJS with RedisX Metrics
Observability isn't just a buzzword; it's a necessity, especially when diving into distributed systems. If you're using NestJS, you might want to take a look at RedisX. It's a modular toolkit that can boost the observability of your applications. A standout feature? The Metrics Plugin. It meshes well with Prometheus, delivering insights into Redis operations in your NestJS setup. Getting RedisX Metrics Rolling in NestJS So, first things first. To harness the power of RedisX Metrics, you need to set up your NestJS app with RedisX. This means installing some packages and configuring the RedisModule with the MetricsPlugin. Hit your terminal and run: npm install @nestjs-redisx/core @nestjs-redisx/metrics Now, let's tweak your AppModule . You want it to use RedisModule with MetricsPlugin: import { Module } from ' @nestjs/common ' ; import { ConfigModule , ConfigService } from ' @nestjs/config ' ; import { RedisModule } from ' @nestjs-redisx/core ' ; import { MetricsPlugin } from ' @nestjs-redisx/metrics ' ; @ Module ({ imports : [ ConfigModule . forRoot ({ isGlobal : true }), RedisModule . forRootAsync ({ imports : [ ConfigModule ], inject : [ ConfigService ], plugins : [ new MetricsPlugin ({ prefix : ' redisx_ ' , endpoint : ' /metrics ' , defaultLabels : { service : ' my-service ' } }) ], useFactory : ( config : ConfigService ) => ({ clients : { host : config . get ( ' REDIS_HOST ' , ' localhost ' ), port : config . get ( ' REDIS_PORT ' , 6379 ), }, }), }), ], }) export class AppModule {} Prometheus Metrics: What You Get With MetricsPlugin set up, your app now exposes a /metrics endpoint. Prometheus can scrape this endpoint, dishing out detailed metrics about your Redis operations. Here's a snapshot of what you get: redisx_cache_hits_total : Tracks total cache hits. redisx_lock_acquired_total : Total locks acquired. redisx_redis_commands_total : Total Redis commands run. Making Prometheus Work for You To get those insights, set up Prometheus to scrape your /metrics end
AI 资讯
Two HNG Tasks That Taught Me More Than the Spec: OAuth for Three Clients, and Shipping AI on a Team Deadline
Two HNG Tasks That Taught Me More Than the Spec This is my Stage 9B write-up for the HNG internship . No new code just two tasks that stuck: one I owned solo across multiple repos, and one I shipped inside a team product under real deadline pressure. If you've ever had auth work almost done for three days straight, or watched an LLM politely ignore your JSON schema, you'll recognize these stories. Task 1 (Individual): Insighta Labs — One API, Three Clients, One Auth System Stage: 3 (Technical Requirements Document / TRD track) Why I picked it: Auth looked "done" on paper. It wasn't. Web portal, CLI, and graders all needed to log in differently, and every environment (localhost, Railway, preview URLs) found a new way to break. What it was Insighta Labs is a queryable profile-intelligence API I built during HNG. By Stage 3 the backend wasn't just CRUD anymore it needed GitHub OAuth with PKCE , JWT access + refresh with rotation , RBAC ( admin vs analyst ), rate limits, API versioning, and three first-class clients : Client Repo How it authenticates Backend API HNG_STAGE-1 Issues tokens, sets cookies Web portal Insighta-WebPortal HTTP-only cookies + CSRF CLI Insighta-Cli PKCE + local callback + Bearer tokens Every /api/* route required X-API-Version: 1 and a valid session. Access tokens expired in 3 minutes ; refresh tokens in 5 minutes with rotation. That sounds harsh, it was intentional, and it surfaced bugs fast. The problem it was solving Reviewers and real users had to prove identity without sharing one login mechanism. Browsers should never see raw tokens in JavaScript. The CLI can't use cookie redirects the same way a React app does. Automated graders needed a test path that didn't depend on GitHub's OAuth exchange. One auth design. Three runtimes. Zero "works on my machine only." How I approached it I split auth into explicit paths instead of one generic "login" handler: Web flow GET /auth/github — server stores PKCE verifier, redirects to GitHub GET /auth/gith
AI 资讯
Nestjs — Stop burning AI credits to write Swagger docs, let the CLI do it!
Last Sunday I shared nestjs-docfy, a small library to move Swagger decorators out of NestJS controllers into companion *.controller.docs.ts files. The reception was better than I expected, and a lot of the feedback pointed in the same direction: the separation is nice, but writing those docs files by hand is still tedious. So I spent some time on that, and there's quite a bit new in this release. A CLI that writes the boilerplate for you The biggest addition is a generate command that reads your project with static analysis (no code execution, no ts-node overhead) and produces a pre-filled docs file for every controller: npx nestjs-docfy generate The generated file comes with inferred summaries, response types, and common error responses already in place. You edit from there instead of starting from scratch. It's idempotent by default, running it again won't touch files that already exist. When you add a new endpoint and want to merge only the new method block without losing your existing edits: npx nestjs-docfy generate --force The CLI auto-detects your project layout, so monorepos (Nx, Nest CLI, generic packages/ or apps/ structures) work without any configuration. There's also a --dry-run flag if you want to preview output before writing anything to disk. A check command for CI The other side of the workflow is keeping docs in sync as the codebase evolves. The check command exits with code 1 if any controller has undocumented methods or no companion file at all: npx nestjs-docfy check Output looks like this when something is out of sync: ✖ UsersController, undocumented methods: updateProfile, deleteAccount → run nestjs-docfy generate --force to merge new methods ✖ 2 controller(s) out of sync. Drop it into your pipeline and docs drift gets caught before it reaches main. Type-safe method keys The docs() function now enforces that every key in config.methods actually exists on the controller class. Typos are a compile error, not a silent runtime warning: docs ( User
AI 资讯
What Happens When a Database Operation Fails Midway? NestJS Transactions to the Rescue
Imagine a simple money transfer scenario. John sends money to his friend Sarah. The system successfully deducts money from John's account, but before it can credit Sarah's account, the application crashes. Without proper safeguards, John's money would disappear from the system, creating inconsistent and unreliable financial records. To prevent this type of problem, database transactions are used. Transactions ensure that a group of related database operations either complete successfully together or fail together. If any part of the process encounters an error, all changes are reverted, ensuring that the database remains consistent. Transactions make database operations atomic. Atomicity means that all operations inside a transaction are treated as a single unit of work. Either every operation succeeds and is committed to the database, or all operations fail and are rolled back. Partial updates are never permanently stored. A database transaction is a group of one or more database operations executed as a single unit. Either all operations succeed together or all operations fail together. This guarantees database consistency even if an application crashes, a network failure occurs, or an unexpected error is encountered during execution. It is important to understand that a transaction is not simply a single database query. While individual queries such as save, update, or delete interact with the database, a transaction wraps multiple queries inside a controlled all-or-nothing boundary. This prevents partial updates and ensures data integrity throughout the process. Prerequisites Before starting, make sure you have the following: Basic knowledge of NestJS Basic understanding of TypeORM Basic knowledge of PostgreSQL Understanding of basic database operations (save, update, delete) in TypeORM Project Setup In this article, we will create a simple NestJS application to demonstrate the importance of transactional queries when multiple database write or update operations
AI 资讯
Integrating Webpay Plus into a modern stack
If you've ever worked on an e-commerce project in Chile, sooner or later you bump into Transbank. There's no avoiding it. I built a reference template that use NestJS on the backend and Next.js 16 on the frontend, and in this post I want to walk you through the whole thing: what Webpay Plus actually is, why the integration looks the way it does, and how each piece fits together. Github Repository Reference: Link A bit of context Webpay Plus is one of the most important online payment methods in Chile. The user experience is straightforward: your customer enters an amount on your site, gets redirected to Transbank's branded payment page, fills in their card details there, and comes back to your site with a result. From a UX perspective it's not as slick as Stripe Elements or a fully embedded checkout — the user always sees Transbank's domain in the address bar during the payment — but from a developer's perspective that's actually a feature. You never touch card numbers. PCI scope stays minimal. Transbank handles 3D Secure, fraud rules, and bank routing. The trade-off is that the integration model is what you might politely call classical . It's built around full-page redirects and form POSTs, not modern APIs with JSON responses and webhooks. That's important to understand up front, because it shapes every decision you'll make in the code. The integration flow, step by step Before looking at any code, it helps to have a clear mental model of what's happening . There are three distinct moments where your system talks to Transbank's system, and each one has a specific shape. First Step: When the customer clicks "Pay", the backend asks Transbank to create a transaction (amount, order ID, return URL) . Transbank returns a transaction token and a redirect URL where you must send the user. Second Step: Transbank requires the redirect to be an HTTP POST with the token in a token_ws form field, so you must generate an HTML form with a hidden token_ws input and submit it prog