I Built a Venezuela Aid Directory in One Day. Here's What I Learned.

The feed woke up full of videos. Earthquake in Venezuela. While searching for information to share with friends and family, I noticed a problem that repeats in every emergency: critical information was scattered across hundreds of WhatsApp groups, Twitter threads, and outdated PDFs that nobody could edit.

I decided to build something that same day.

It's live at: rubenrangel.org/en/ayudavenezuela


The first version: centralizing what matters

The MVP was simple. A no-login form to report three types of information:

  • Missing persons — name, ID number, last known location
  • Alerts and needs — what's needed, where, contact info
  • Collection centers — address, hours, what they accept

Anyone can add an entry. It appears in the directory within seconds. No registration, no pre-moderation, no bureaucracy.

While building that, I noticed another gap that emergency directories almost never solve.


The two-sided problem

In the first days of an emergency, information flows in one direction: "we need X." But there are volunteers with medical knowledge, companies with excavators, available translators, people with space to house families — and they have no way to find those who need them.

The matching happens by coincidence, not by design.

I built the Support Network: a two-column panel inside the same directory. Left: those who have something to offer. Right: those who need help. No intermediaries — contact is direct between the parties.


The most interesting design problem: editing without an account

If someone posts "3 generators available today" and lends them out the next day, they need to be able to update or remove their entry. But I didn't want to require any kind of registration — every friction step is one less person who publishes.

The solution: anonymous edit tokens.

When an entry is created, the backend generates a UUID. It stores the sha256 of that UUID in the database. And returns the UUID in plain text exactly once, in the POST response.

POST /api/v1/apoyo
↓
generate UUID → hash('sha256', $uuid) → save to DB
↓
return UUID in plain text (only in this response)
↓
frontend stores in localStorage as apoyo_token_{id}

If you open the directory from the same device, the "Edit" button appears automatically — the token is in localStorage. Switch devices, enter it manually. Lose it, create a new entry.

In a humanitarian context, that's acceptable. The alternative — asking you to register during an emergency — is not.


AI moderation: the most important principle is fail-open

A public directory without login is an easy target for spam. I integrated Claude Haiku as an automatic moderator: before saving each entry, the text goes through an evaluation.

The prompt explains the context to the model: a humanitarian directory for Venezuela, where you'd expect to find volunteers, translators, rescue groups, medical centers. It should only reject obvious spam, hate speech, or irrelevant commercial advertising.

But the most important design principle was this: fail-open.

try {
    $response = $this->anthropic->chat($systemPrompt, $messages);
    $decoded  = json_decode($response, true);
    return ($decoded['approved'] ?? true) === true;
} catch (Throwable) {
    return true; // if API fails, we approve
}

If the Anthropic API fails — timeout, quota, network — the entry gets saved anyway. In an emergency I can't block legitimate help because an external service isn't responding. Occasional spam is a smaller problem than losing a real entry.

For cases that do get rejected, I implemented a strike system per IP: warning on the first and second attempt, 24-hour block on the third. All via Laravel cache, no database writes.


What I left out (on purpose)

  • Automatic matching between supply and demand
  • Push or email notifications
  • Identity verification
  • Ranking algorithm

Full YAGNI. If someone needs a translator, they contact the translator who posted their availability directly. The algorithm can wait. People can't.


The stack, for the curious

Laravel 11 · Vue 3 · SQLite · Vite · Claude Haiku (moderation) · Lightsail

No complex relational database, no microservices, no premature abstraction. Expected volume is low — under 200 entries total. SQLite is enough and avoids an extra database server.


If you know someone in Venezuela or with connections there, share the link:

rubenrangel.org/en/ayudavenezuela

Every entry helps.