#

dev

(38 articles)

How to Build a Monero Payment Gateway — Technical Guide

# How to Build a Monero Payment Gateway (Technical Guide) I built a Monero payment gateway with 0.5% fees and open-sourced the approach. Here's how it works. ## Architecture Three components: 1. monero-wallet-rpc — generates subaddresses, monitors payments 2. Flask REST API — serves invoice creation and status endpoints 3. SQLite — stores invoices, zero-config ## Wallet Setup ```bash monero-wallet-rpc \ --wallet-file /data/wallet \ --daemon-host xmr-node.cakewallet.com \ --rpc-bind-port 18083 \ --password "" --disable-rpc-login ``` ## Creating Invoices Each invoice gets a unique subaddress via RPC: POST /api/invoice {amount: 0.05, webhook_url: "..."} → Wallet generates fresh subaddress (create_address RPC) → Store {id, subaddress_index, amount, webhook_url} in SQLite → Return address to customer ## Payment Detection Background thread polls get_transfers every 30 seconds: ```python transfers = wallet_rpc("get_transfers", {"in": True}) for tx in transfers: idx = tx["subaddr_index"]["minor"] invoice = lookup_invoice(idx) if tx["confirmations"] >= needed: mark_paid(invoice, tx["amount"]) fire_webhook(invoice, tx["txid"]) ``` ## Why 0.5%? NowPayments/CoinPayments charge 1%. Running your own wallet-rpc costs nothing except server time. The 0.5% fee covers maintenance and keeps it sustainable. Full source + running instance: https://brief-propecia-accent-constantly.trycloudflare.com/pay Built for the Monero community. Feedback and contributions welcome. #Monero #dev #python #selfhosted #privacy

Α 2025-10-29 Ω The Muted Cry of the Earth

Rachel Carson was not a professional revolutionary. She was a marine biologist with the patience of one who observes the tides and the precision of a government cataloger of organisms. But when she decided to raise her voice, the impact was enough to shake the system. Her weapon was not a political manifesto, nor a shouted protest. It was a book, Silent Spring, which in 1962 tore away the veil of blind progress, revealing how the indiscriminate use of pesticides like DDT was poisoning the world . She did not write from instinct, but from a lucid and painful reckoning. She had seen the scientific data: DDT, a heroic exterminator of mosquitoes during the war, had become a dark threat. It traveled through food chains, accumulated in the fat tissues of animals, killed birds, and contaminated water . Her pen transformed those technical truths into a universal story. Describing a spring without the songs of swallows was not a metaphor: it was the projection of a future already begun . The backlash was violent. The chemical industry painted her as a hysterical, single woman obsessed with little animals. They called her a communist, an enemy of progress. They tried to reduce her work to the sentimentalism of a nature lover . But Carson had not merely mourned dead robins. She had built her case with the cement of science: dozens of studies, interviews with experts, meticulous documentation . Hers was not an attack on chemistry, but on ignorance. On the recklessness of putting powerful poisons into unaware hands . There was in her a deep, almost physical tension between the rationality of the scientist and the awareness that the world was a web of connected lives. In Silent Spring, she did not call for a ban on all pesticides. She called for caution, research into alternatives, respect for that fragile balance in which humans are also a thread, not the master . Her message was clear: you cannot spray poison upon the world and believe it will remain confined where you placed it. Her battle was also a race against time. As she wrote, breast cancer consumed her body. She endured chemo and radiation but kept her illness hidden, knowing her opponents would use it to question her lucidity . She died in 1964, two years after publication, without seeing the ripest fruit of her labor: the creation of the U.S. Environmental Protection Agency (EPA) and the ban on DDT . Rachel Carson did not love grandiose heroics. She was a private woman who found comfort in letters to a dear friend and walks along the Maine coast. Yet, with her scientific stubbornness and poetic prose, she accomplished more than an investigation: she awakened a conscience. Heeding not an ideology, but an evidence: the earth is not a resource to be exploited, but a home of which we are a part. And when the home shakes, the tremor reaches us all. — ✦ — 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon

The scream and the void.

This is the hallmark of our times. An endless cacophony, an incessant buzz that fills the ears but does not touch the soul. We open our jaws, we emit sounds, we mistake them for dialogue. But it is just background noise, the hiss of a tape that has come loose. The word, emptied of its flesh, has become a shell rolling through digital streets, a sterile husk. True communication is not an emission, it is a reception. It is an act of courage that begins with closing the mouth and opening the soul's ears. Before reaching out to the other, one must have found one's own centre, having listened to one's inner breath. Today we throw messages like stones, to wound, to appear, to win an imaginary dispute. It is the logic of the keyboard gladiator, not the truth-seeker. Harmony is not a drawing-room concept. It is a visceral condition, an alignment of one's inner frequencies. If one is in a storm, words can only be splinters of wood carried by the gust. They serve to build fences, not to tear them down. One speaks to discharge toxins, to transfer the burden of one's confusion onto a scapegoat. It is a dead end. Authentic communication is a resonance. It is when two tuning forks, attuned to the same note, begin to vibrate in unison without needing to clash. It is not about convincing, about bending the other to one's will. It is about expressing one's own truth, naked and raw, but without making it a cudgel. Words are chisels: they can carve beauty or inflict wounds. But their strength is not in the blade, it is in the hand that guides it. A trembling, angry hand will only cause damage. Everything stems from a quality of being. From a presence to oneself that is the root of every encounter. It is listening, which is not docile passivity, but vigilant waiting. It is gentleness, which is not weakness, but tamed power. It is enthusiasm, that inner fire that gives warmth to syllables. It is simplicity, the antidote to contorted rhetoric. The restarting point is here, in this desert of silence we are afraid to inhabit. In the courage to fall silent, to turn off the spotlights and look into the darkness of one's own room. It is there that the connection with the essential is found. Silence is not absence. It is the control room. It is from there that the current that ignites the true words emanates. 〰️ 🤍 〰️ 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon

The Digital Abyss: The Steep Bill for the Virtual Euro the ECB Doesn't Want to Pay

A chilling shiver, a barely perceptible vibration snaking through the cold corridors of financial power. Frankfurt speaks, its voice a reassuring hum, a hypnotic mantra promising a future smooth as a screen. The digital euro, they say, will not be a trauma. Two studies, clean numbers, reassuring projections. All under control. But who, with an ounce of sense left, still trusts the illusionists of finance? There's a smell of burning. An acrid odor of incomplete truth, of risks hidden under a rug of convenient statistics. It's not a promise, it's a spell. And as in any self-respecting magic trick, the substance vanishes into thin air, leaving only the illusion. Digging beneath the polished surface of press releases is a nauseating exercise. The ECB, with the arrogance of those who believe they can dictate reality with a spreadsheet, announces that the bill for the banks will be light, a trifle between 4 and 5.77 billion. A figure that sounds almost reasonable, compared to the 18 billion screamed by the scarecrows. But reasonableness is the first casualty when the technocrat gets to work. These numbers, waved like flags of victory, are hollow. They admit, with a nonchalance that makes the skin crawl, that they omitted the potential benefits for the banks from their calculation. It's like estimating the cost of a car without considering you can actually drive it. A methodological madness, a con artist's trick. The sensation is of being taken for a ride, of being considered a mass of imbeciles incapable of understanding the deceit. The masterstroke, however, is another. A logical artifice bordering on malignant genius. The banks in the Eurozone are thousands, each with its own guts, its structure, its IT demons. Yet, the ECB decrees that the implementations will not be thousands, but only a few hundred. Why? Ah, synergies! Centralization! As if the small provincial banks, with their rugged faces and tight budgets, could magically merge into a single, highly efficient digital blob. It's a fantasy, a hallucination of a Soviet planner. It ignores the hassles, the slowness, the idiosyncrasies of the real world. It presumes everyone will move in unison, like an army of robots. And then they have the nerve to call "excessive" the estimates of those who, like PwC, have perhaps brushed against that real world. The question arises spontaneously, burning: so, who is lying? Who is trying to placate public opinion with a fairy tale with a happy ending? The suspicion is that the goal is not transparency, but staging. The product must be pushed through at any cost, even at the cost of twisting reality until it bleeds. And then comes the stability chapter, the tragic joke. The magic limit: three thousand euros per person. A figure that is supposed to be the bulwark against panic, the dam that holds back the ocean. In normal times, they say, the impact will be zero. But life is not "normal times." Life is crisis, it is panic, it is the unexpected exploding in your face. And in those moments, that limit is not a rock, it's a wisp of smoke. The ECB itself has played with different limits, implicitly admitting that this number is written on sand. And when the wind of crisis blows, that number will fly away. Their own documents, in a passage that seems buried so as not to be read, confess that in a "very hypothetical" crisis – a euphemism that sends shivers – thirteen banks could be gutted, nine could sink. Nine. It's not a statistic, it's nine funerals. Just one, small, bank collapsing is enough to trigger an earthquake. Trust is crystal, not a steel bolt. But the real, subtle, murderous danger is another. Speed. Digital cash is not like going to the counter, queuing, withdrawing banknotes. It's a click. A touch on the screen. A nervous impulse. In a nanosecond, fear turns into a capital flight. That physical slowness, that sweat that restrains mass hysteria, disappears. And what are we left with? A hyper-fast system built for consumption, placed in the hands of human fear. The ECB, obsessed with the quantity of funds, completely ignores the speed of their movement. It's like worrying about the weight of a bullet and not its velocity. The impact is devastating nonetheless. In the end, what remains is not reassurance. It's a shiver. An alarm vibration that starts from the fingers gripping the smartphone and goes straight to the stomach. The words from Frankfurt do not soothe the anxiety, they feed it. Because beneath that blanket of numbers and "it's all fine," you can hear the rumble of a tsunami. And the feeling, strong, distressing, is that when it breaks, those who set the table won't be the ones paying the steepest bill. — ✦ — 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon

The Gladiator's Return: Thirty Years Later, Lancia Throws Itself Back into the Fray

This is not a fairy tale. We will not begin with "once upon a time". It is rather the chronicle of an awakening, slow, obstinate, that tastes of tarmac and burnt oil. For over three decades, the Lancia name in the rally world has been a ghost, an echo of applause in a hall now empty. Now, in 2026, the ghost becomes flesh and steel. Lancia returns to where its legend was forged and where, perhaps, it can once again warm itself by the fire of competition. The chosen stage could only be the most theatrical, the most cruel: the Rally of Monte Carlo, between the 22nd and 25th of January. Roads that are a trap of ice and asphalt, curves that are a final judgement. There, the new Ypsilon Rally2 HF Integrale will enter the arena in the WRC2 category, not as a princess, but as a gladiator who has forgotten nothing of her ferocity. This is not a timid appearance. It is a deployment of forces. The brand's motorsport range reveals itself with the precision of a military plan: the Ypsilon HF Racing, the Rally4 HF, and finally the Rally2 HF Integrale, which is not a simple car. It is a bridge thrown over an abyss of thirty years. An artefact that claims to stitch together the glory of yesterday, made of dust and world titles, with a future that has yet to prove it is not a mirage. It is the symbol of a continuity that dares, that challenges time and oblivion. From the CEO's words, a torrent of pride and expectations: "With pride we can announce that Lancia will return to the WRC, where it wrote some of the most legendary pages of its sporting history". His words do not ask for permission, they are a statement. "It is a natural return for the most winning brand ever in rallying, which looks to the future with the same passion and determination that made it a world icon". It is a gentle declaration of war, a manifesto. And then the sign-off, sharp, an appointment without the possibility of a reply: "We'll see you in January, in Monte Carlo, for the first race of the 2026 World Championship". There are no icy shivers here. There is the tension of a bow that has been drawn back for an eternity and is about to loose the arrow. There is the stifled roar of an engine that never stopped dreaming. Monte Carlo will not be a simple beginning. It will be an examination of conscience. A return home, to a home where the furniture has been moved and the rivals have become more fierce. The wait is over. Now it's time to get dirty with mud, once again. 〰️ 🤍 〰️ 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon #motors

The Outrage of the Machine: The Madness that Wants to Duplicate the Soul

This is not a matter of chips or silicon. It is a war of spirit. An assault conducted not with weapons, but with an idea, a single one, so simple as to be diabolical: that man, in his deepest essence, is nothing but a mechanism. A complex clock. And that therefore, with the right gears, a twin clock can be built. This is the founding lie of our era, the poison dripped onto us like acid rain. Artificial intelligence? A colossal sham. They have convinced us that intelligence is that arid calculation, that logical gymnastics which solves problems, wins at chess, digests mountains of data. And certainly, in this, machines surpass us. But it is like boasting of having built a lamp more powerful than the sun. The quantity of light is confused with its quality, its origin, its mystery. There exists another faculty, higher, more noble. A fire fed not by electrons but by intuition. Our ancestors, those whose brains were not yet clouded by the smoke of machines, called it intellect. It is not reasoning. It is a flash, an immediate taste of truth. It is that lightning strike which grasps the beautiful, the true, the just, without passing through the sieve of logic. One sees the principle as one sees the sun; one savors it like a ripe fruit. It is an act of knowledge that is also an act of love. And this, believe me, you will never replicate with an algorithm. There is no code that can contain the ecstasy of a mystic or the creative fury of a poet. You may simulate the form, never the substance. The disaster began when we forgot this duality of man. We amputated the best part of ourselves, declaring that only the rational ape that calculates and schematizes exists. And once man was reduced to a flesh-and-blood automaton, the idea of building a metal automaton became not only possible but inevitable. We opened the cage to transhumanism because we first locked our soul in a laboratory. We believed the fable of the body-machine, and now here we are dreaming of the upgrade, the hybrid, digital immortality. It is the logical conclusion of a madness that denies everything that is superior, everything that cannot be measured, weighed, sold. Fighting this drift with laws, with politics, is like trying to stop an avalanche with a petty decree. It is a battle won or lost in the minds of the people, in the heart of civilization. We must return to shouting, with the strength of desperation, that man is not his machine. That within him dwells a principle from on high, a heritage of light that no artificial intelligence will ever possess. It is a question of pride. Of refusing the outrage of being duplicated by a gadget. The allure of the synthetic is powerful, it is the same one the serpent offered: you will be like gods. But it is a promise of charlatans. The only way out is a radical return, a recovery of the integral idea of man, unique, unrepeatable, sacred. Before it is too late. — ✦ — 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon

The Garden and the Circus: Surviving Digital Anarchy

This is not a crisis. It is not a collapse. It is a grand and terrible spectacle, this digital square they call Nostr. A sovereign-less vanity fair, a stage where the mask of anonymity does not hide the face, but reveals it in its bare, often wretched, essence. You dive in and are swept away by a chaotic clamor, a buzz that does not elevate, that stuns. Shouters, charlatans, gold diggers. It is the worst of the common man, multiplied by the power of lightning and stripped of any filter. This bedlam is not a failure of the project. It is its most authentic and ruthless success. It is a return to the horde, to human nature before civilization attempted, often in vain, to bridle it. The average user is not a rebel. He is a creature of habit. A battery-farmed animal, raised in the artificial ludes of traditional social media, where every like is a tiny dose of sugar and every interaction is a conditioned reflex. He seeks here what he already knows: immediate validation, quick gain, the reflection of his own image in a million concave mirrors. He has developed no antibodies, he lacks the visceral skepticism required to navigate these free and infested waters. Your nausea, the disgust that rises from your guts as you scroll through this Babel, is not a symptom of weakness. It is a sign of health. It is proof that your intellectual immune system is still vigilant. You are set apart from the mass because you reject the circus, because you perceive the background noise not as a soundtrack, but as acoustic pollution for the soul. Your frustration is the privilege, and the burden, of those who can still see the starry sky beyond the fumes of the market stalls. But the mistake, the tragic, useless mistake, is to believe you must redeem the entire square. That you must convert the shouters, that you must purify the Augean stables. It is the labor of Sisyphus, a fight against the tide with a spoon. Strength does not lie in frontal opposition, in that swimming against the current which only consumes your vital energy. The true revolution is silent, almost botanical. It is the gesture of one who, turning his back on the tumultuous river of stupidity, decides to water his own small, tiny plot of land. Your garden. Your corner of the net. Build there. Clear the soil, plant seeds of authentic conversations, patiently cultivate genuine relationships. Protect it with a fence of discretion. The daily watering, the assiduous care, are acts of a resistance more powerful than any manifesto or invective. From that garden, in time, no light may radiate to save the world. But that is not the point. That garden will save you. And in an age of digital din, saving your own capacity to think, to feel, to connect in depth, is the only victory that truly matters. Stop fighting the chaos. Become a gardener. 〰️ 🤍 〰️ 🦅 Cheyenne Isa ₿ 🦅 #bitcoin #nostr #zap #lightning #grownostr #askNostr #plebchain #art #podcasts #dev #filmstr #bookstr #carnivore #touchgrass #zaps #btc #coffeechain #health #music #zapathon

How I Learned to Stop Worrying and Love Docker Networking (Or: A Tale of Relay Woes)

*A cautionary tale about deploying a Nostr relay, featuring duplicate routes, DNS shenanigans, and the eternal struggle between "it works on my machine" and "why is everything on fire?"* ## The Setup: What Could Possibly Go Wrong? It all started innocently enough. I had a simple goal: deploy a personal Nostr relay with a nice web interface. You know, the kind of project that should take "an afternoon" and definitely won't spiral into a weekend-consuming debugging marathon involving container networking, nginx configurations, and questioning my life choices. Spoiler alert: It took considerably longer than the afternoon. ## Chapter 1: The Great Scheduler Addition Things were working beautifully. The relay was humming along, clients were connecting, and I was feeling pretty good about myself. Then I had what seemed like a perfectly reasonable idea: "You know what this needs? A background scheduler to update content automatically!" Because apparently I subscribe to the philosophy of "if it's not broken, add more moving parts until it is." I implemented a lovely little scheduler using Python's `threading` module. Clean code, proper separation of concerns, the works. What could go wrong? ## Chapter 2: The 502 Bad Gateway Blues After deploying the scheduler, suddenly everything was returning `502 Bad Gateway` errors. Classic. The kind of error message that's about as helpful as a chocolate teapot. The logs were helpfully reporting: `AssertionError: View function mapping is overwriting an existing endpoint function: update_cache` Ah yes, the dreaded duplicate route. Turns out, in my enthusiasm to add scheduler functionality, I had somehow managed to define the same Flask route twice. Because apparently, like a bad pop song, once just wasn't enough. ### The Detective Work This is where things got interesting. The web interface was down, but the containers were running. The relay process was starting, then immediately dying with the grace of a swan having an existential crisis. ```bash [ERROR] Worker (pid:205) exited with code 3 [ERROR] Shutting down: Master [ERROR] Reason: Worker failed to boot. ``` Worker failed to boot? More like "developer failed to not duplicate code," but who's keeping track? ## Chapter 3: The Great Container Rebuild The fix was simple enough once I found it: delete the duplicate route definition. But here's where Docker's "helpful" caching behavior comes into play. You see, the app code wasn't mounted as a volume—it was baked into the container image during build. So my local fix was sitting there, mocking me, while the container cheerfully continued using the broken version like nothing happened. *Queue the Docker rebuild process*, which in 2025 still feels like watching paint dry, but with more anxiety about whether it will actually work this time. ## Chapter 4: The DNS Comedy Hour With the duplicate routes fixed, the web app was working again. Victory! Time to check if the relay was accessible to Nostr clients. "The relay is showing as disconnected on clients again." *Record scratch. Freeze frame.* This is where our story takes a delightful detour into the wonderful world of Docker networking and nginx configuration. ### The Investigation WebSocket connections were failing with—you guessed it—another `502 Bad Gateway`. But this time, it wasn't the app. It was nginx. The configuration looked perfectly reasonable: ```nginx proxy_pass http://nostr-relay:8080$1; ``` Except for one tiny detail: **that hostname didn't exist.** ### The Plot Twist Docker Compose had named the container `nostr-home_rnostr-relay_1`, not `nostr-relay`. So nginx was essentially trying to phone a number that was disconnected. ```bash $ docker exec nginx_container nslookup nostr-relay ** server can't find nostr-relay: SERVFAIL ``` The actual working hostname? `rnostr-relay`. Because of course it was. ## Chapter 5: The Victory Lap One simple find-and-replace later: ```bash sed -i 's/nostr-relay:8080/rnostr-relay:8080/g' nginx.conf ``` And suddenly everything worked again. WebSocket connections returned HTTP 101 (the good kind of switching protocols), relay info was being served properly, and Nostr clients could connect without throwing tantrums. ## Lessons Learned (The Hard Way) 1. **Docker networking is like a box of chocolates** — you never know what hostname you're gonna get, and it's probably not the one you expected. 2. **Always check your container names** — `docker-compose ps` is your friend, even when it tells you things you don't want to hear. 3. **Volume mounts are your friend** — If you want to edit code and have it actually take effect, mount it as a volume. Revolutionary concept, I know. 4. **Duplicate code is the enemy** — Flask will absolutely refuse to start if you define the same route twice, and it will do so with all the grace of a toddler having a meltdown in a grocery store. 5. **DNS resolution works until it doesn't** — And when it doesn't, everything fails in the most spectacular way possible. ## The Epilogue After all the debugging, container rebuilding, and nginx configuration wrestling, I now have: - ✅ A working Nostr relay - ✅ WebSocket connections that actually connect - ✅ A background scheduler that doesn't crash everything - ✅ A web interface with real-time statistics - ✅ Several new gray hairs The relay is now happily serving connections at `wss://nostr.pleb.one`, the web interface shows live statistics, and the scheduler updates content every 30 minutes without setting anything on fire. Was it worth the several hours of debugging? Ask me after I've had more coffee. ## Final Thoughts Deploying software is like trying to assemble IKEA furniture while blindfolded, using instructions written in a language you don't speak, with tools that may or may not be the right ones. But when everything finally clicks into place, and you see that beautiful `HTTP/1.1 101 Switching Protocols` response, all the pain seems worth it. Until the next deployment, anyway. --- *The relay is live at `wss://nostr.pleb.one` if you want to test your own Nostr client's patience with my networking skills. You can also visit the web interface to watch real-time statistics and marvel at how something so simple can be so complicated to deploy.* *No containers were permanently harmed in the making of this deployment. Several developer sanity points may have been lost in the process.*

3 learnings from 1 year of DM development on Nostr

I am the author of [Blowater](https://blowater.app), a Discord style nostr client. Here is a list of my learnings after 15 months of DM focusing development. I have used Blowater for more than 10,000 DMs so there is some credibility of my findings. # 1. 100% Delivery is the most important problem For example, if user1 wants to send messages to user2, they have to connect to at least 1 common relay. For whatever reasons, if they are not on the same relay, even just for several minutes, some messages will be missing. It is fine for a user to not see all kind-1s, aka social media. Partial discovery/delivery is how Nostr is designed originally. But for kind-4s, aka directed messages, this problem is a deal breaker. It's more critical than meta data leak and other privacy/security problems. If you can't deliver your message, it's useless to have a secure message. Therefore, I believe that while problems like meta data leaks and authentications are important, it's less prioritized than the delivery problem. Ideas such as [Inbox Model](https://github.com/nostr-protocol/nips/discussions/1134) are more urgent at this moment. But, before we step into these discussions, we need to clearly define our design/architecture boundary. We can at least divide solutions to 4 categories: | Head | Single Client | Cross Client | | --- | --- | --- | | Single Relay | Centralized | Semi-centralized | | Cross Relay | Slack style | Decentralized | Now, the problem is, can we achieve 100% delivery + `cross client` + `cross relay` at the same time? Because 100% delivery is not compromisable, if we have to sacrifice, should we give up `cross client` or `cross relay`? In my opinion, we should sacrifice `cross client` and keep `cross relay` because the client is the most influential place to ensure a good user experience. Blowater used to work `cross client` + `cross relay` with the original NIP-4. For rational described above, Blowater changed to `single client` + `single relay` with the adoption of NIP-44. Yes, the DM of Blowater is pretty much centralized at this moment because we have not figured out a reliable way of delivering messages cross relays. That's why I look forward to inbox-mode. # 2. Offline mode and working with bad relays are necessary If you are on a bad network condition, you still want to browse messages and potentially search them on your device. People usually message themselves as a clever way to take notes and reminders. In fact, it is 10X more useful and convenient than specialized note taking & reminder apps. Because of this design & engineering goal, Blowater stores all events locally and never deletes. Searching through half a millions notes (including kind-1) only takes a few milliseconds. As a side effect, Blowater does not need [NIP-50](https://github.com/nostr-protocol/nips/blob/master/50.md) to have a proper search. NIP-50 is nice to have but not a necessity. The same design & engineering choice also applies to working with bad relays that either do not implement all the NIPs this client needs or return data in an incorrect or inconvenient way. Relying on the authority of servers is the mental model of a centralized world. Because nostr events are immutable, data stored in clients are not cache. They are the source of truth as well. Therefore, storing as many events locally as possible is a good thing that makes the client both faster and independent from network conditions. Clients can be seen as relays with UIs and only stores events relevant to the logged in npub. Relays can be seen as clients that have no UIs and stores events of many npubs. # WebSocket-only is a horrible design choice There are 2 aspects of this statement. ### The first being that WebSocket is a streaming API and streaming API for everything is a bad choice. Mainly for 2 use cases: 1. get event by ID Nostr events are immutable, if I have the ID of an event, it does not change. It makes no sense to have a stream of only 1 thing. A relay either has this event or it does not. A HTTP GET of 200 / 404 is much better. Supporting HTTP API does not make client nor relay implementations harder. WebSocket relies on HTTP/1.1. If you support WebSocket, you have to support HTTP in the first place. 2. post events to relays A simple HTTP POST is a much better way to send data to relays. It makes ad-hoc writing much simpler. The client does not need to establish a WebSocket connection. It's more performant. To summarize, streaming API is for working with unknown size, possibly infinite data (either in size or in time). If the data size is known & finite, request/response API is much better. ### The second aspect is that WebSocket is not a good streaming protocol, at least for the web browsers. There is no way to force close/kill a WebSocket connection on the client side if the server is offline. For example, client A connects to relay B at time X. At time X + 1, A sends a disconnection message to relay B which was down for whatever reason. Client A will wait there forever and the WebSocket connection, at least from client's perspective, will never be closed. The WebSocket specification requires the client to wait for the server acknowledgement of closing the connection which prevents client from force closing. Therefore, it's pretty much impossible to have a reliable browser client that connects to many relays and works reliably for long days. People tend to close their browser tabs so it's not likely to happen but it's still a fundamental flaw. Additionally, because WebSocket is HTTP/1.1, it does not have all the goodies that HTTP/3 might give us. This is not a problem at the moment. But if we want to have a future proof system, we need future proof design. WebSocket & many Web clients might serve as a nice starting point to bootstrap the ecosystem. But we can't stay here forever. We have to grow out. --- Here you go, 3 main takes away I have about Nostr development. It's not all the learning that I have but I believe they are the most relevant for many developers.

Brainstorming modular articles

I'm going to try and #asknostr for this. The client I'm working on is more or less about making full articles out of smaller notes, the purpose for this is to isolate individual ideas and concepts of some larger article. A bridge between *very* long articles books or wiki pages and small-specialized personal knowledge bases (zettlekasten). Why? Think about a wiki, but with multiple perspectives per topic, and the content of each article can be some sort of mix of any other article's content. If you want to write about some sort of level 3 concept and other's have already written about levels 1 and 2 perfectly well, why reinvent the wheel? Academic papers, textbooks, blogs and tutorials are filled with redundant content like this and always hiding background content in references. What if those references were a part of the article itself? I think that this could lead to a new way of consuming knowledge content, and would like to build it with the community. Looking for advice on constructing this to keep interoperability with other clients while also not spamming feeds with tons of Kind:1 notes. I'm trying to spec out these kinds, and some possible metadata tags. The kind(s) might lie somewhere within the 30000-39999 range of parameterized replaceable events. **Two basic types of kinds** 1. Article metadata and list of connected notes 2. Notes with isolated concepts This is related to the Kind:0 (user metadata) and Kind:1 (text notes), but for an article that can change its structure and content as time progresses and knowledge about a topic updates. For the time being, I'll just refer to them as **ArticleKind:0** and **ArticleKind:1**. * **ArticleKind:0** sketches out the structure of an article at a point in time. It has the article metadata and the specific list of notes that compose that article. This specific kind is what would be displayed as a preview to users. One possibility could be embedding the structure of the article in this event. * **ArticleKind:1** contains the content, subsection title (*introduction*, *tutorial B*, *ingredients* etc.) and possible references to external content. The subsection titles can be aggregated to create a composed table of contents. Similar to **ArticleKind:0**, a possibility could be to embed the immediate connections of this note (e.g. previous and next notes, which can be single or many notes) Why replaceable? If information is updated the most recent article/note will display, but a living history of the document remains (if relay operators decide to not delete old notes). Articles/subsections can exist with multiple perspectives but can be linked together by single **ArticleKind:0**. Isolated concepts help both writers and readers focus on the information they care about while allowing users in the future to compose new articles out of previous notes. What you can potentially make is nonlinear-modular-chooseYourOwnAdventure articles that let you read and write about topics in what whatever fashion you'd like, while allowing already well explained work to be part of your article. * You want a regular linear book, that's fine. * You want a branching story? Go ahead. * What about a weird ouroboros spaghetti linked article? Why the hell not? Further reading: (brief, possible applications) * https://github.com/limina1/indextr-principles/blob/main/README.org (longer, drawn out concepts and rational) * https://github.com/limina1/indextr-principles/blob/main/details.md