AI 资讯
Your Redis Leaderboard Is Probably Breaking Ties Wrong
A leaderboard looks like a one-command problem: ZADD weekly 100 alice ZADD weekly 100 bob ZREVRANGE weekly 0 -1 WITHSCORES While building Podium , an open-source Redis-backed leaderboard service, we discovered that the difficult part begins when two players have the same score. We are sharing the design because this edge case can silently turn player IDs into ranking rules. TeneficGames / podium High-performance, Redis-backed leaderboards for games and competitive applications. Podium High-performance, Redis-backed leaderboards for games and competitive applications. Podium provides ready-to-run HTTP and gRPC APIs for scores, ranks, seasons, and player-relative views. It is designed for backend teams operating large fleets of independent leaderboards without provisioning each leaderboard in advance. Fair, deterministic ordering when scores are equal. Single and bulk score updates, including multi-leaderboard fan-out. Standalone Redis and real Redis Cluster integration coverage. Deploy one multi-architecture OCI image with Docker, containerd, Kubernetes or another OCI-compatible runtime. Quickstart · Performance · API · Documentation · Helm chart · Docker Hub · GHCR Quickstart Start Redis 8.2 and the latest stable Podium image: docker network create podium docker run --detach --name podium-redis --network podium redis:8.2-alpine docker run --detach --rm --name podium \ --network podium \ --publish 8880:8880 \ --publish 8881:8881 \ --env PODIUM_REDIS_HOST=podium-redis \ --env PODIUM_REDIS_PORT=6379 \ trungdlp/podium:latest start Verify the service: curl http://localhost:8880/healthcheck WORKING Submit two equal scores: curl --request … View on GitHub Both players have 100 points. Alice arrived first, so most game designers would expect: 1. alice: 100 2. bob: 100 But that is not what the data model says. Redis sorted sets order members with equal scores lexicographically. With a reverse range, that secondary ordering is reversed too. Your "fair" tie may therefore be de
AI 资讯
Адаптируйся или будешь не нужен: что ждёт разработчиков в эпоху AI
Разберёмся, к чему нас приведут нейросети и что будет дальше. Это хайп, пузырь или новая реальность? Взгляд разработчика и дорожная карта для входа в AI. Хочу провести небольшой анализ и понять, какие сценарии развития нейросетей могут быть и к чему мы можем подготовиться. Я разработчик, и последние пару лет моя лента — это бесконечный хайп вокруг AI. Но если отключить эмоции и включить холодный анализ, возникает ощущение дежавю. Давайте ненадолго погрузимся в историю. Прошлое. Что мы уже пережили Мы, поколение миллениалов и зумеров, стали свидетелями уникального явления: технологии начали сменять друг друга с огромной скоростью. Каждые два-три года появлялось что-то. Вспомним главные тренды: • Социальные сети (2007–2012) — пугали, что мы перестанем общаться вживую, а приватность умрёт навсегда. Стали рекламным рынком, появились SMM-щики и таргетологи. Кто не пошёл в digital — остался на обочине. • Big Data (2010–2015) — кричали «Большой брат следит за тобой», аналитиков заменят алгоритмы. Сегодня это стандартный слой систем, дата-инженеры — обычная роль. • Облака (2010–2018) — боялись, что данные украдут, а сисадмины вымрут как класс. Облака стали коммунальной услугой. DevOps и SRE — must-have, сисадмины просто переквалифицировались. • IoT (2014–2018) — пугали тем, что хакеры взломают ваш чайник, а вещи станут умнее людей. Технология ушла в промышленность, быт не перевернула. • 3D-печать (2012–2015) — паника «заводы закроются, каждый напечатает пистолет». Прижилась в прототипировании и стоматологии, пистолеты печатают только в новостях. • VR (2016) — боялись, что люди уйдут в виртуал и перестанут различать реальность. Стало игрушкой для геймеров и тренажёром для пилотов. • Метавселенные (2021–2023) — говорили, что жизнь окончательно переедет в цифру, а без аватара на работу не выйдешь. Хайп прошел. • Блокчейн (2015–2018) — страх, что банки исчезнут, а юристы и нотариусы станут не нужны. Web3-революция не случилась, но разработчики были на вес золота. • Крипта (2017
AI 资讯
The Modern API Gateway: Beyond Simple Routing
The API Gateway Has Grown Up When API gateways first entered the enterprise architecture conversation, the value proposition was straightforward: put a reverse proxy in front of your APIs, enforce authentication, and add basic rate limiting. Problem solved. That framing was adequate for 2012. It's dangerously incomplete for 2026. Today's API gateway sits at the intersection of integration, security, observability, and increasingly AI — and the organizations that still treat it as a simple routing layer are leaving significant capability on the table while accepting operational risk they don't have to carry. The modern API gateway is an integration hub in its own right, and understanding its full capabilities is essential to building a resilient, scalable API strategy. What Traditional API Gateways Got Right (and Wrong) The first generation of API management platforms — Layer 7, Apigee, legacy enterprise API managers, early Kong — nailed the fundamentals. Authentication enforcement, basic transformations, developer portals with API keys, rudimentary analytics. For the REST API era, this was genuinely valuable. But these platforms had structural limitations that became more painful as API ecosystems scaled: Static configuration : Policy changes required deployment cycles, not dynamic updates Monolithic architecture : The gateway itself became a single point of failure and a scaling bottleneck Reactive observability : Dashboards showed what happened; they didn't predict or prevent problems Protocol silos : REST gateways couldn't route gRPC, GraphQL, or WebSocket traffic without additional infrastructure No integration context : The gateway was blind to the systems it was protecting — it enforced policies without understanding the business logic behind the APIs The Modern API Gateway: A Capability Map Authentication and Authorization — Now Much More Than Token Validation Modern gateways don't just validate that a token exists and hasn't expired. They implement the full
AI 资讯
If Claude Code is expensive or hard to access for you, try OpenCode
If Claude Code is expensive or hard to access for you, try OpenCode . It’s an open-source AI coding agent that works in the terminal, desktop, and as a VS Code extension. Free models available: DeepSeek V4 Flash Free (best option) MiMo v2.5 Free Nemotron 3 Ultra Free North Mini Code Free Big Pickle Ling-3.0-flash Free Laguna S 2.1 Free These free models work well for most daily coding tasks. Note: They have daily usage limits (they reset every day). How to install (Windows): First, make sure Node.js is installed on your system. Then run: npm install -g opencode-ai After installation, run: opencode You can also install the VS Code extension for a smoother experience. OpenCode lets you use free models or connect any API key you want. It’s flexible, open-source, and a solid alternative to Claude Code. I tested it myself. Setup is easy and the free models are usable for real work. Link: https://opencode.ai/
AI 资讯
How StayPresent's Logging Works (Without Breaking Yours)
A guide to python isolated logging with StayPresent's dedicated logger — no root logger mutation, what gets logged, and how to configure it. How StayPresent's Logging Works (Without Breaking Yours) A surprisingly common way for a third-party package to quietly break your application's logging is by calling logging.basicConfig() somewhere in its own code — which mutates the root logger and can silently change formatting, duplicate output, or override handlers you already configured for your own loggers. StayPresent avoids this entirely through python isolated logging : everything it logs goes through its own dedicated logger, never the root one. Table of Contents The Problem with logging.basicConfig() StayPresent's Dedicated Logger What Gets Logged, and at What Level Adjusting Verbosity Attaching Your Own Handler Logging During Multi-Bot Runs Logging During Shutdown Full Example Best Practices Common Mistakes FAQs Conclusion The Problem with logging.basicConfig() logging.basicConfig() configures the root logger, which every other logger in your process falls back to unless it's explicitly configured otherwise. If your bot calls it once at startup, and a dependency somewhere else in your stack calls it again, whichever call happens first usually "wins" silently — no error, just unexpected formatting or duplicate log lines that are hard to trace back to their cause. A well-behaved library avoids touching the root logger at all, and instead logs through its own named logger. StayPresent's Dedicated Logger StayPresent logs exclusively through a logger named "staypresent" , configured with a single dedicated StreamHandler and logger.propagate = False . It never calls logging.basicConfig() , and it never touches the root logger in any way. This means it cannot clobber, duplicate, or reformat log output your own script has already configured for its own, unrelated loggers — StayPresent's logs and your bot's logs coexist without interfering with each other. What Gets Logged,
AI 资讯
# What I Learned from Building with GIS Data and the Copernicus API at the KijaniSpace Hackathon
As software developers, we often spend most of our time building APIs, databases, authentication systems, and web applications. That's certainly been my focus recently, especially working with Go, JWT authentication, and backend services. Last week, however, I had the opportunity to participate in the KijaniSpace Hackathon , held at Zone01 Kisumu , and it introduced me to an entirely different side of software development. Our challenge was to build solutions using: Geographic Information Systems (GIS) The Copernicus API IoT devices where applicable It was an opportunity to see how software can interact with our physical world. What is GIS? GIS (Geographic Information Systems) is a technology used to collect, analyze, visualize, and manage data that has a geographic location. Imagine not just storing information like: Temperature Population Vegetation Buildings Roads ...but also knowing exactly where that information exists on Earth. That location data allows developers to build intelligent systems capable of answering questions like: Which farms are experiencing drought? Which roads are likely to flood? Which areas are losing forest cover? Where should new infrastructure be built? GIS transforms ordinary data into meaningful geographic insights. Discovering the Copernicus Program Before this hackathon, I had heard very little about Copernicus. Copernicus is the European Union's Earth Observation Programme. It provides free satellite imagery and environmental data collected by the Sentinel satellite missions. Through its APIs, developers can access information about: Land cover Vegetation health Weather patterns Water bodies Air quality Climate changes Disaster monitoring What amazed me most is that much of this data is openly available for developers to build impactful applications. Where IoT Fits In Some teams also explored Internet of Things (IoT) solutions. IoT devices can collect real-world information through sensors measuring: Soil moisture Temperature Humidi
AI 资讯
The Hidden Cost of a Log Line : Sync/Async Flush and everything in Between
log.info("user logged in") looks free. It isn't. Behind that one line is a chain of decisions — buffer or not, flush or not, block or drop, same thread or another — and each one trades latency , throughput , and durability against the others. This post walks the whole chain, from the method call down to the bytes hitting the disk platter. If you've ever wondered why your p99 latency has a mysterious spike, why logs vanish after a crash, or what "async logging" actually buys you, this is for you. First, the map: facade vs. implementation Java logging is a two-layer cake, and mixing up the layers is the #1 source of confusion. The facade is the API your code calls. The implementation is what actually writes the bytes. your code │ log.info(...) ▼ ┌───────────────────────────────┐ │ Facade: SLF4J (or Log4j2 API)│ ← the interface you compile against └──────────────┬────────────────┘ │ bound at runtime ┌───────────┼────────────┬──────────────┐ ▼ ▼ ▼ ▼ Logback Log4j2 Core java.util.logging ... (the engine that buffers, formats, and flushes) SLF4J — the de-facto standard facade. Your app should log against this. Logback — the reference SLF4J implementation. Solid, widely deployed. Log4j2 — the performance-focused implementation, famous for its lock-free async loggers. java.util.logging (JUL) — built into the JDK, rarely chosen on purpose. Why the split? So you can swap engines without touching a single log. call. Everything interesting in this post — the buffering, the flushing, the async magic — happens in the implementation layer. The anatomy of a single log call Before we talk flushing, let's see what one log.info(...) actually does. There are five stages: 1. Level check → is INFO enabled for this logger? (cheap, often the fastest bail-out) 2. Build LogEvent → capture message, timestamp, thread, MDC context, maybe a stack trace 3. Filter → run any configured filters 4. Layout / encode → turn the event into bytes ("2026-07-28 12:00:01 INFO ...") 5. Append → write those by
AI 资讯
Scraping platform costs: measure successful rows, not browser minutes
A scraping job usually fails in boring ways: the browser hangs, a selector starts returning empty strings, a login expires, or the target site returns a captcha halfway through the run. The awkward part is that many platforms still bill you for the work done before the failure. If you run enough jobs, that difference shows up both in your invoice and in the amount of defensive code you need around the scraper. Billing by compute time changes how you build A lot of scraping platforms charge for runtime. Apify, for example, uses compute units: memory multiplied by time. A browser-heavy actor running for ten minutes with 2 GB of RAM consumes roughly a third of a compute unit before any actor-specific result fees. That model is reasonable from the provider side. Chromium processes are expensive. Proxies cost money. Retries use resources. But as the caller, you care about a different unit: did I get the rows I needed? The hard part is that runtime billing makes cost hard to know before execution. A job that normally takes 30 seconds might take 8 minutes when a site slows down. A job that returns malformed data can still count as successful from the platform's point of view. A job that fails after rendering 200 pages still consumed browser time. If your pipeline runs once a day, that may be fine. If it runs continuously, you probably want a local cost model that tracks outcomes, not just requests. type ScrapeRun = { jobId : string ; target : string ; startedAt : string ; finishedAt ?: string ; status : " queued " | " running " | " succeeded " | " failed " ; rowsExpected ?: number ; rowsReceived ?: number ; billedUnits ?: number ; }; function isUsefulResult ( run : ScrapeRun ) { if ( run . status !== " succeeded " ) return false ; if ( run . rowsExpected && ( run . rowsReceived ?? 0 ) < run . rowsExpected * 0.9 ) { return false ; } return ( run . rowsReceived ?? 0 ) > 0 ; } function costPerUsefulRow ( run : ScrapeRun ) { if ( ! isUsefulResult ( run )) return Infinity ; ret
AI 资讯
Learning Go the Slow Way: Building Projects Instead of Following Tutorials.
Like a lot of beginners, I started learning Go the usual way: tutorials, courses, and coding along with someone who had already solved every problem. It felt productive. I finished lessons, learned the syntax, and everything seemed to make sense. Then I tried building something on my own.I had no idea where to start. That was the point where I changed my approach. Instead of following tutorials, I started building small, messy, imperfect projects. I still use AI, but not to generate the code for me. I use it as a guide that helps me think through the problem. Why tutorials stopped working for me Tutorials are great for introducing concepts and showing that something works. What they don't teach very well is how to make decisions when you're on your own. When you're following along, someone else has already decided how to organize the project, what to name things, how to structure the packages, and how to solve the tricky parts. You learn what to type, but you don't get much practice deciding why to do it that way. I could finish a tutorial and still struggle to build a simple API from scratch. That was a clear sign that I wasn't actually learning how to solve problems. My new approach: start with a real project Now I begin with a small project I actually want to build. Nothing huge—just something manageable, like: A URL shortener A simple job queue A CLI tool that automates something I find repetitive The goal isn't to build an impressive portfolio piece. It's to build something that's mine, where every design decision is one I have to make myself. The problem, of course, is that starting from a blank page can be overwhelming when you're still learning. That's where AI has become genuinely useful. How I use AI I don't ask AI to build the project. Instead, I ask it to break the project into small, testable milestones. For example: "I want to build a basic URL shortener in Go.Break this project into small steps, where each step is one feature I can build and test befo
AI 资讯
JWT + OAuth2 + OIDC + PKCE Complete small Guide
The flow will be: Authentication foundation Session vs JWT JWT deep dive JWT security Access/Refresh tokens OAuth2 relationship with JWT End-to-end production flow PKCE Storage strategies summary 1. Authentication Fundamentals Every secure application needs answers to two questions: Authentication "Who are you?" Example: User enters: username password MFA System verifies identity. Result: User is Bhargav Authorization "What are you allowed to do?" Example: User: Bhargav Permissions: READ_ORDERS CREATE_ORDER DELETE_ORDER Authentication happens first. Authorization happens after. Authentication | v Authorization 2. Traditional Session-Based Authentication (Stateful) Before JWT, applications commonly used sessions. Flow User logs in: Browser | | username/password | v Server Server creates: Session ID = abc123 Stores: Database / Memory abc123 | | User: Bhargav Role: ADMIN Browser receives: Cookie: SESSION_ID=abc123 Every Request Browser sends: GET /orders Cookie: SESSION_ID=abc123 Server: Receive Session ID | v Search session storage | v Find user | v Allow request Problems with Sessions 1. Server maintains state The server must remember: Session ID | v User Information 2. Scaling problem Imagine multiple servers: Load Balancer / \ Server A Server B User logs in: Server A Session stored here Next request: Server B No session found Solutions: Sticky sessions Shared session database 3. JWT Authentication (Stateless) JWT solves this by putting information inside the token. JWT: JSON Web Token It is a compact, signed representation of claims between two parties. Example: eyJhbGciOiJIUzI1Ni... JWT vs Session Session Server stores user state: Server Session ID | v User Data JWT Token contains information: JWT Header + Payload + Signature Server does not need to store session information. 4. JWT Structure A JWT has three parts: HEADER.PAYLOAD.SIGNATURE Example: xxxxx.yyyyy.zzzzz Part 1: Header Contains metadata. Example: { "alg" : "RS256" , "typ" : "JWT" } Meaning: JWT uses RS
AI 资讯
BUILDING GREENWOOD ACADEMY DATABASE USING POSTGRESQL
INTODUCTION Creating Greenwood academy database is essential for managing the students, subject and exam results efficiently. PostgreSQL, a powerful open-source relational database system, offers the perfect foundation for such a project. The main areas areas in SQL covered in this projects are : 1. DDL (Data Definition Language) DDL commands define, modify, and change the physical structure of database objects like tables and schemas. The first step is to create a greenwood academy schema using the create command. create schema greenwood_academy ; set search_path to greenwood_academy ; Next is to crete tables in the schema; The schema has 3 tables students,subject and exam results. create table greenwood_academy . students ( student_id INT PRIMARY key , first_name VARCHAR ( 50 ) NOT null , last_name VARCHAR ( 50 ) NOT null , gender VARCHAR ( 1 ), date_of_birth DATE , class VARCHAR ( 10 ), city VARCHAR ( 50 ) ); create table greenwood_academy . subject ( subject_id INT PRIMARY key , subject_name VARCHAR ( 100 ) NOT null unique , department VARCHAR ( 50 ), teacher_name VARCHAR ( 100 ), credits INT ); create table greenwood_academy . exam_results ( result_id INT PRIMARY key , student_id INT NOT null , subject_id INT NOT null , marks INT NOT null , exam_date DATE , grade VARCHAR ( 2 ) ); ALTER - This command changes the structure of tables in a database. Core Actions You Can Perform Add columns : Insert a new column and its data type into a table. The school realised that the nthey forgot to add phone numbers in the students table. The following command is used to add the data alter table greenwood_academy . students add column phone_number VARCHAR ( 20 ); Rename colums : Change the name of a table or a column. The column credit has to be changed to credit hours alter table greenwood_academy . subject rename column credits to credit_hours ; Drop columns : Delete an unwanted column from a table. Later the school relised that the phone number column is nolonger needed. a
AI 资讯
What Spain's Verifactu law actually does to your backend
Spain is putting a hash chain behind every invoice, and almost everything written about it so far has been written for accountants. This is the version for whoever has to ship it. The deadlines are January 1, 2027 for companies and July 1, 2027 for sole traders. If you read something last year that said 2026, that was true until RD-ley 15/2025 moved the whole calendar back twelve months. Software vendors have been on the hook since July 2025, which is a detail worth holding on to if you sell a product that issues invoices for other people. At BeeL., we sell an API for this, so read the rest with that in mind. The requirement Each invoice your software issues has to produce a registro de facturación de alta: a record containing a defined set of fields, hashed with SHA-256, where the hash of each record folds in the hash of the one before it. One chain per issuing tax ID, growing forever, never edited. Cancelling an invoice is not a delete. It's a second record type, a registro de anulación, which goes into the same chain. Same for corrections, which come in two flavours depending on whether you're amending a difference or replacing the original document. The printed invoice carries a QR code with verification data, plus the string VERI*FACTU if you're in submitting mode. Then you either push each record to the tax agency as it happens, or you keep everything locally under stricter signing and retention rules and hand it over when asked. Written down like that, it reads like an afternoon of work. A hash function, a previous_hash column, an HTTP call. Where the estimate falls apart The chain is strictly sequential, so two workers issuing invoices for the same tax ID at the same time are racing for the same link. You need a lock per issuer, or a queue, or both, and either way concurrent issuance stops being free. Retries are worse than they look. A failed submission that you retry carelessly either duplicates a record or breaks the chain, and a broken chain isn't someth
AI 资讯
Electricity Planning Engine, part 2: A Reader Comment Found a Real Gap in My Test Suite (and How I Fixed It)
I wrote about the Electricity Planning Engine a little while back, including a timezone bug that made a correct price look "not found" after a database round trip. A few days later, Alex Shev left this comment: Timezone bugs are brutal in planning engines because the result can look mathematically correct while being operationally wrong. Energy workflows especially need tests around boundaries, not just averages. That is a genuinely sharp way to put it, and it is not just a comment about the bug I already wrote about. It is a comment about how I test the project in general, and I did not like how well it applied once I went and checked. The part that stung a little "Looks mathematically correct while being operationally wrong" is exactly what the original timezone bug was. PriceSeries::priceAt() threw a clean "price not found" error, which is arguably the good version of that failure mode: loud, easy to catch, hard to ship. A quieter version of the same class of mistake, off by one hour instead of missing entirely, would not throw anything. It would just return a plan that looks completely reasonable and is wrong the entire time it runs. Alex's second point, boundaries over averages, is the one I actually had to go check rather than just agree with in the abstract. So I opened tests/Unit/Domain/Contract/PricingStrategyTest.php and looked at every hour used in every peak/off-peak assertion: new DateTimeImmutable ( '2026-07-18 14:00:00' ) // peak new DateTimeImmutable ( '2026-07-18 23:00:00' ) // off-peak new DateTimeImmutable ( '2026-07-18 05:00:00' ) // off-peak 14:00, 23:00, 05:00. Every single one comfortably inside its window. None of them anywhere near the actual transition. The off-peak slot in the config is 22:00 to 06:00 , and the comparison behind that lives in TimeSlot::contains() : // wraparound slot, e.g. 22:00 -> 06:00 return $minuteOfDay >= $this -> startMinuteOfDay || $minuteOfDay < $this -> endMinuteOfDay ; That >= versus < is exactly the kind of one-
AI 资讯
Solon Flow: Lightweight Process Orchestration Without BPMN XML
When you need process orchestration — approval workflows, business rules, data pipelines — the usual answer is a heavyweight engine: BPMN 2.0 XML, database schemas, a management UI, and a framework that drags in half of enterprise Java. Solon Flow takes a different approach. It's a ~200KB engine that treats process definitions as flat YAML or JSON, runs without a database, and lets you resume interrupted processes from a JSON snapshot. You can embed it in any JVM framework — Solon, Spring Boot, Quarkus, or even a plain main() method. This article walks through the core API, node types, context persistence, and driver customization — all verified against the official documentation at solon.noear.org . Getting Started Add the dependency: <dependency> <groupId> org.noear </groupId> <artifactId> solon-flow </artifactId> </dependency> Define a flow in YAML ( flow/demo1.yml ): id : " c1" layout : - { id : " n1" , type : " start" , link : " n2" } - { id : " n2" , type : " activity" , link : " n3" , task : ' System.out.println("hello world!");' } - { id : " n3" , type : " end" } Load and execute: FlowEngine engine = FlowEngine . newInstance (); engine . load ( "classpath:flow/demo1.yml" ); engine . eval ( "c1" ); That's it. No database, no XML schema, no deployment step. In a Solon application, you can inject the engine directly and let it auto-load flow definitions: solon.flow : - " classpath:flow/*.yml" @Component public class DemoCom implements LifecycleBean { @Inject private FlowEngine flowEngine ; @Override public void start () throws Throwable { flowEngine . eval ( "c1" ); } } The engine scans all matching files on startup, so adding a new flow is just dropping a YAML file. Node Types Solon Flow supports seven node types via the NodeType enum: Type Description Task Condition Parallel In Out start Entry point — — — 0 1 activity Default node Yes — — 1..n 1..n exclusive Exclusive gateway (if/else) Yes Yes — 1..n 1..n inclusive Inclusive gateway (multi-select) Yes Yes — 1
AI 资讯
Why I Put Mirth Connect in Front of FastAPI Instead of Parsing HL7 in Python
When I started building my Maternity HL7-to-FHIR Pipeline , my first instinct was to do everything in Python. Parse the HL7 message, map the fields, validate the FHIR resource, persist it, all in one FastAPI service. It was clean. It was simple. It was wrong. The "Just Parse It in Python" Phase My initial architecture looked like this: Hospital System --MLLP--> Python Script --> HAPI FHIR Server I used python-hl7 to split messages on | and count field positions. For a single ADT^A01 (patient admission) message, it worked fine. I could pull the patient name from PID-5 , the MRN from PID-3 , the gender from PID-8 , and build a FHIR Patient resource from it. Then I tried a real-ish maternity workflow (an admission, an order, and a set of vitals) and things fell apart quickly. Five Problems That Changed My Mind 1. MLLP Is Not HTTP Hospital systems don't send HL7 over HTTP. They send it over MLLP (Minimum Lower Layer Protocol), which is a TCP socket protocol with specific framing bytes ( \x0b at the start, \x1c\x0d at the end). The sender expects an ACK or NACK response in HL7 format, not an HTTP status code. Building an MLLP listener in Python is possible . Libraries like aioml7 exist. But you're now maintaining a custom TCP server alongside your HTTP API server, handling connection pooling, timeouts, and HL7 acknowledgment generation. That's a lot of infrastructure code that has nothing to do with your actual transformation logic. Mirth Connect handles MLLP natively. You point it at a port, it listens, it parses, it ACKs. Done. One config screen, no custom code. 2. HL7 Parsing Is Messier Than It Looks The pipe-delimited format looks simple: PID|1||1234567^^^MRN||TEST^PATIENT^MARY^^MS||19920315|F|||14 SAMPLE ST^^SYDNEY^NSW^2000^AU But consider: Component separators : PID-5 is TEST^PATIENT^MARY^^MS , which is family, given, middle, suffix (empty), prefix. Miss the empty suffix and your prefix ends up as the suffix. Repeating fields : PID-3 can contain multiple identifier
AI 资讯
Como crear Roles de Usuarios RBAC Plano PHP MySQL
Guía crear Roles de Usuario usando RBAC Plano con PHP MySQL Agustin RamosJul 24, 2026PHP Stuffs El control de acceso basado en roles (RBAC) es utilizado en la mayoría de los sistemas para definir qué puede hacer cada usuario. En su versión más simple, conocida como RBAC plano, no es necesaria una tabla de permisos: cada usuario tiene un único rol, representado por un número, y ese número es el que determina qué se le permite hacer dentro del sistema. En esta guía es construido un módulo de RBAC plano completo, con base de datos, conexión, lógica de validación y ejemplos de uso, usando solo PHP y MySQL. Si necesitas repasar los fundamentos antes de continuar, puedes consultar nuestra guía de PHP y MySQL. Qué es el RBAC plano En este modelo, cada rol es representado por un ID numérico. La regla que se sigue en esta guía es simple: entre más bajo el número, mayor es el nivel de acceso. 1 = admin (mayor nivel de acceso) 2 = subadmin 3 = encargado 4 = empleado (menor nivel de acceso) Con esta lógica, validar “solo administradores o superiores” se reduce a una simple comparación: role_id <= 2. Base de datos Son necesarias únicamente dos tablas: rol y user. La columna role_id, dentro de user, es la que define el nivel de acceso de cada persona. Todo este bloque está guardado en el archivo schema.sql. Cómo ejecutarlo: copia todo el bloque de código y pégalo directamente en tu consola de MySQL (o en phpMyAdmin / MySQL Workbench). Esto crea la base de datos rbac_plano, sus tablas y los datos de ejemplo automáticamente. -- schema.sql CREATE DATABASE rbac_plano; USE rbac_plano; -- Tabla rol. -- El ID es usado como nivel: entre más bajo, más privilegios. CREATE TABLE rol ( id TINYINT UNSIGNED PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE ); -- Se insertan los 4 roles base del sistema. INSERT INTO rol (id, name) VALUES (1, 'admin'), (2, 'subadmin'), (3, 'encargado'), (4, 'empleado'); -- Tabla user. -- Cada usuario tiene un único role_id (no hay tabla de permisos). CREATE TABLE us
AI 资讯
Teaching My Backend to Lock the Door — FastAPI Auth, Phase 3
Hash the password, hand out a token, and make absolutely sure no one can read someone else's expenses. So Phase 2 gave my app a mouth. It could finally talk — create, read, update, and delete expenses over real HTTP endpoints, all clicking together through /docs . But there was a giant, deliberately-ignored problem sitting in the middle of it: the door had no lock. Anyone who could reach the server could read, edit, or delete anything. And every expense I created was quietly stamped with the same hardcoded owner — a "dev user" whose id I'd nailed into the code with a # TEMP note and a promise to fix it "in Phase 3." Well. It's Phase 3. Time to pay that debt. This is where the app grows a bouncer. The buzzword is auth , which actually hides two jobs that sound the same and aren't: authentication ["who are you?"] and authorization ["okay, but are you allowed to touch this ?"]. I went in thinking auth was "add a login form" and came out having learned about one-way hashing, signed tokens, a security bug with the excellent name IDOR , and why the same password can produce two different hashes. Let me dump what I learned [and the parts that tripped me up, because — as usual — there were several]. Auth is the one phase where you have to stop thinking like a builder and start thinking like the person trying to rob you. So every step below is really "here's a way an attacker wins, and here's the gap I closed to stop them." The structure. Let's call it PHASE 3 — The Lock: Give the User table somewhere to store a password [a hashed one, never the real thing] Password hashing helpers — turn a password into something safe to store POST /auth/register — sign up with a hashed password Understand what a JWT actually is [it's just a signed string, and it's readable] POST /auth/login — check the password, hand back a token get_current_user — the gatekeeper that turns a token back into a user Lock every expense endpoint and scope it to the logged-in owner Retire the hardcoded DEV_USE
AI 资讯
Defeating the Multi-Tenant SaaS Concurrency Trap in PostgreSQL
Most backend engineers implement multi-tenant quota checks using a standard "read-then-write" pattern. In production, this pattern is highly unsafe: SELECT grading_scans_remaining FROM profiles; If greater than 0, execute the application logic. UPDATE profiles SET grading_scans_remaining = grading_scans_remaining - 1; Under high volume or rapid concurrent requests, two independent processes will read the exact same balance before either one deducts usage. This race condition allows multi-tenant users to bypass your billing gates entirely. To solve this, you have to bypass the frontend and application-level checks, enforcing an atomic database operation that serializes the row update first. I have open-sourced a reference framework that outlines explicit subscription enums, core multi-tenant schemas, and a native VS Code / Cursor snippets configuration to speed up your local database modeling. 📂 Check out the repository on GitHub: { https://github.com/dollykm49/PostgreSQL-SaaS-Multi-Tenant-Subscription-Architecture-reference-framework- } What's inside the repository: Strictly Typed Enums: Centralized business rules handled natively by the database engine. Granular Balance Tracking: Optimized data-layer mapping for profiles and reset states. postgres-saas.code-snippets Engine: A local IDE configuration file that lets you deploy this core schema straight from your code editor by typing pg- shortcuts. For teams building commercial applications looking to skip weeks of writing custom migrations, testing concurrency edge-cases, and debugging row-locking security rules, the repository also includes a link to the extended 28-page production system bundle. Feedback on the multi-tier validation parameters is highly welcome!
AI 资讯
You Might Not Need Kafka: Building a Job Queue with PostgreSQL
It's easy to reach for the popular tool before asking what your system actually needs. For job queueing, the usual advice is to use RabbitMQ or Kafka. The underlying burden of using these tools will be additional processes to deploy, monitor and reason about. But what if using your existing database is possible? I built a job queueing system with a PostgreSQL database that cleared the bar without adding infrastructure. The next question will be, does this solution meet the criteria of a job queue? A job needs a few things to execute properly within a system. It needs to be persistent, surviving unforeseen crashes. Jobs must not be processed more than once by workers; one job should be processed once by one worker. Also, a job's state has to be tracked through every step. A job state must show when it's pending, completed or failed. That's the bar any solution must clear. With the Postgres approach, persistence comes free. Jobs live in a table so when a worker dies mid-job, the job still exists in a row in the db. Whereas with in-memory queues, a crash loses everything still in memory. A broker like RabbitMQ has to be configured for persistence and if configured wrongly, jobs get lost. A database however is fundamentally built for durability. Now, let's say three workers poll the queue at the same instant and run the same query. They'll see the same pending job at the top and nothing stops them all from grabbing it. If that job is a payment, the customer gets charged three times for one service. All the workers successfully process the job with no indication of an error or alerts. This is the requirement that seems to demand a real message broker, and it's exactly where people assume a database can't compete. It can. Postgres has a specific tool for exactly this. The SQL clause FOR UPDATE is used to lock rows. This can be called on a job when a worker picks it up to process. By default other workers will get blocked during this process, they'll wait for the lock to r
AI 资讯
# From JavaScript to Node.js: Understanding What Really Happens Behind the Scenes (Part 4.3A.1)
# Module Resolution Algorithm (Part 1): How Node.js Finds the Right Module In the previous article, we explored one of the most fascinating parts of Node.js—the hidden Module Wrapper Function. We learned that every CommonJS module is wrapped inside a function before execution, and we also discovered that require() is not a JavaScript feature. It is provided by the Node.js runtime. But a very important mystery still remains. When we write: const fs = require ( " fs " ); or const math = require ( " ./math " ); how does Node.js know where these modules are located? How does it decide whether "fs" is a built-in module or a file inside your project? Why does require("./math") work even if you don't write .js ? And what happens internally before your code starts executing? The answer lies inside one of Node.js's most important systems: The Module Resolution Algorithm Understanding this algorithm is essential because every Node.js application uses it hundreds or even thousands of times while starting. What is Module Resolution? The word resolution simply means: Finding the actual file represented by the string passed to require() . Suppose you write: require ( " ./math " ); To you, "./math" looks like a file. But for Node.js, it is initially nothing more than a string. "./math" Node cannot execute a string. It needs the real file. So its first job is to answer one question: "Which exact file should I load?" The complete process of converting the string inside require() into an actual file on disk is called Module Resolution . Why Does Node Need a Resolution Algorithm? Imagine a project like this: project/ ├── app.js ├── math.js ├── database.js ├── auth.js └── utils/ ├── logger.js └── helper.js Now look at these statements. require ( " ./math " ); require ( " ./database " ); require ( " ./utils/logger " ); require ( " fs " ); require ( " express " ); All of them look similar. But internally they are completely different. Some point to your own files. Some point to Node's bu