Brasília Remote
·
Norberto Junior Product Engineer, AI Systems

I build AI systems that reach production.

Three are running right now: a creative platform serving 1,207 students, a CRM with four AI agents handling sales and support, and an autonomous agent system that works offline in the field.

16 years across design, art direction, UX and product. Today I build the infrastructure that makes AI products work when there is real money and real people on the other side.

3Systems in production
19Pipeline nodes measured for cost
A2Fixed ceiling — client, money, deletion

Systems

Three in production one in progress
01

Estúdio Criativo

ReadyToGo Education 1,207 active students
TypeScript · Next.js
PostgreSQL · Supabase
OpenRouter
“How much does one generation cost?”
Nobody could answer.

The problem

An AI creative tool was shipping, but nobody could answer the two questions that decide whether an AI product survives: what does each generation actually cost, and what happens when a provider fails at 2am?

What I built

A single AI gateway. Every outbound call to every provider goes through one place — per-provider timeouts, structured logging, anomaly detection at 40% error rate or 45s latency, and the ability to cut off a provider through a feature flag, without deploying. Twelve egress points migrated, zero direct calls left.

Then per-node telemetry: cost, duration and tokens for each of the 19 node types in the pipeline. Not aggregate — per step. That is what turns “we have an AI feature” into “we know what it costs and what to charge for it.”

Twelve egress points, one path out

Application 12 Egress points Zero direct calls left One place The gateway 01 Per-provider timeout 02 Structured logging 03 Anomaly detection error ≥ 40% · latency ≥ 45s 04 Kill switch feature flag · no deploy Every call, one path Providers Provider 01 live Provider 02 live Provider 03 cut · no deploy needed

The decision that mattered

Slides render in parallel, so summing node durations overstates real elapsed time. The system reports sum_node_ms and wall_ms separately. Measuring the wrong thing confidently is worse than not measuring at all.

slides render in parallel —
summing duration lies

Also shipped

Monthly credit windows with a lifetime ledger as the source of truth. A queue that detects an orphaned job in about two minutes and reprocesses it — without charging the student for the failure. Feature flags with a kill switch. Observable deploys: one endpoint answers which commit is live.

02

Clau Carvalho CRM

Partner Product & engineering Built solo in 4 months
TypeScript · Node
PostgreSQL · Drizzle
WhatsApp Cloud API
“Just tell the agent not to give discounts.”
A prompt is not a rule.

The problem

A post-operative physiotherapy practice running sales, student management and support across WhatsApp, spreadsheets, and an unofficial API that collapsed under load.

What I built

A full CRM with four AI agents that have explicit data boundaries between them: one sees internal operations, one handles inbound leads around the clock, one is isolated and never receives operational data, one writes content.

The sales agent runs on non-negotiable rules encoded in the system, not in a prompt: never offers or negotiates a discount, never closes a sale, never sends a checkout link, never discards a lead. It qualifies and hands off to a human.

Then I migrated the operation to Meta’s official WhatsApp Cloud API — including the diagnosis the documentation doesn’t cover: verifying the webhook and subscribing to events isn’t enough. The app has to be subscribed on the WABA, and the number has to be registered on the Cloud. Before that, Meta simply delivers nothing.

The decision that mattered

Before the migration, bulk sends at machine cadence kept killing the session. The fix wasn’t a retry loop — it was respecting the platform: randomized human-paced intervals with periodic breaks. Some constraints aren’t bugs to route around.

the fix was respecting
the platform, not retrying

Four agents, four data boundaries

System of record PostgreSQL Students · finance · coupons · audit trail Knowledge base RAG Course · method · market No source 01 Internal agent Serves The team Sees Revenue and finance Student records Coupons and offers Never Faces a customer 02 Lead agent · 24/7 Serves Inbound leads Sees Only the lead it is handling Never Negotiates a discount Closes a sale Sends a checkout link Discards a lead Hands off to a human 03 Isolated agent Sees Nothing from the operation Why A boundary enforced by the system cannot be argued away by a message it receives 04 Content agent Serves The specialist Reads Course knowledge Content method Market research Writes Daily copy and stories A human publishes them Never Touches the operation

Also shipped

A financial module — amounts in cents, installments, per-seller commission, partner profit split, refunds, event-level audit trail. Approved sales post automatically, deduplicated by transaction. Round-robin lead distribution. Automated first contact with a silent fallback when a template isn’t approved yet, so nobody is left without a message.

03

Duck Studios

Consulting CRM + autonomous agents
Python · FastAPI
PostgreSQL
Offline-first PWA
“The agent doesn’t have permission to delete files.”
That sentence stopped reassuring me.

The problem

A film production company and equipment rental house tracking a R$519,000 inventory in spreadsheets — and needing it to work on location, where there is no reliable network.

What I built

An offline-first PWA. Equipment check-in and check-out by scan works with no connection: each scan enters a local queue and syncs later without duplicating. It runs on a Mac Mini that travels to shoots, powered by a stationary battery and Starlink.

Autonomous agents with autonomy graded per action, not per agent — A0 through A4. Anything that reaches a client, moves money or deletes data is fixed at A2: the agent prepares the whole action, a human approves, code executes. Everything else moves on evidence — ten clean runs promote an action one level, one correction demotes it and the reason is logged. Every agent action is audited.

The autonomy scale, level by level

Autonomy is rated per action, not per agent Fixed ceiling A0 Forbidden The action does not exist in the agent's code — not even with your approval on screen. Today Real file deletion Writes to the source card Charging A1 Suggests The agent analyses and writes the suggestion. You execute it with your own hands. Today Deadline alerts, D-2 and overdue A2 Approve first The agent prepares the whole action. It waits for your tap. Approve and code runs at once. Today Lead reply Reactivation message Card formatting Drive cleanup A3 Acts and reports Acts without asking, tells you after. Every run lands in the audit trail. Reversible only. Today Rental round, 15 min Folder inventory Tag capture Machine heartbeat A4 Autonomous You see the aggregate, not each run. Mature, low risk, high volume. Today Nothing yet How an action moves 10 clean runs → up one level · 1 correction → down one level, reason logged in the SOP Client · money · deletion never pass A2 — fixed by principle, and the two rules above do not apply

The decision that mattered

Anti-overbooking is a PostgreSQL exclusion constraint, not application logic. Guarantees that matter live in the database, where a code bug can’t route around them.

A0 is not denied permission.
It is absence.

Inbound messages are data, not instructions. Agent rules do not change based on the content of a message received — prompt injection handled as architecture, not as a filter.

Found along the way

Cross-referencing the catalogue against real inventory surfaced 14 items being sold that didn’t exist in the fleet.

04

UGC creator platform

ReadyToGo Education in progress
TypeScript · Next.js
PostgreSQL · outbox
Event-driven
In progress
“Put the queue in Redis. It’s the standard, and it’s faster.”
Both true. Neither was the problem.

The problem

A platform where content creators publish, get measured and get ranked. Every submission has to be analysed, scored and folded into a cycle — in the background, never inside the request. The obvious answer was a queue in Redis.

What I built

The state change and the event are written in the same transaction — the outbox pattern. A worker claims rows with for update skip locked, and consumers are idempotent by key, so the same event arriving twice costs nothing.

Webhooks and server actions record the event and return. Heavy work belongs to whoever consumes it, never to whoever receives the request. Events are named in the past tense — content collected, metric updated, cycle closed — because an event is a fact that already happened, not an order to obey.

One transaction, or two systems that can disagree

The path taken server action webhook ONE TRANSACTION 1 · estado muda 2 · outbox recebe o evento Queue · PostgreSQL for update skip locked score recalculado ranking atualizado ciclo fechado idempotentes por chave The path refused server action webhook escrita 1 · PostgreSQL escrita 2 · Redis a segunda falha o trabalho existe e nunca é processado a criadora fica sem pontos · o ranking mente Measured peak 0,42 job/s Headroom 4 orders of magnitude throughput was never the argument

The decision that mattered

Queueing outside the database splits the content write from the job enqueue: two writes that can diverge. If the second one fails, the work exists and is never processed — the creator loses points and the ranking lies, silently, in one row. The canonical fix is the outbox, and an outbox table is a queue in the database. Redis would add a piece without removing one.

the argument was never
throughput. it was atomicity.

Where Redis would earn its place

As a rate limiter shared across serverless invocations. So the limiter was born behind an interface, with a PostgreSQL implementation. Swapping it later is one file — when measurement asks, not when intuition does.

How I build

Four things learned carrying real money
01

The database comes before the agent

An agent without a system of record hallucinates the state of the world. The CRM isn’t a project running alongside the agents — the CRM is the agents’ memory.

02

User input is data, not instructions

Agent rules don’t change based on what arrives in a message. Prompt injection is an architecture problem, not a filter you bolt on afterwards.

03

Guarantees belong in the database

Not in application logic, where a bug can route around them. If overbooking must be impossible, it’s a constraint — not a validation.

04

Measure cost per step

Aggregate spend tells you that AI is expensive. Per-step cost tells you which step, and what to charge for it.

Selected work

16 years curated
PeriodOrganisationRoleWhat it was
2026 —IDPFreelance Figma MCP integration: page and asset changes, saves and management handled by an AI agent, removing the manual design step from the workflow.In progress
2022 —ReadyToGo EducationUX → Product → AI UX Designer (2022) → Product Manager (2024) → AI Product Lead (2026). Four and a half years, two promotions, same company.
2018 – 2019Top MarketingCreative Director All art and design across every campaign, reporting directly to the owners. Clients: Brasal, MRV.
2020 – 2022IDPSenior UX Designer UI/UX, pages, campaigns and identity for undergraduate, postgraduate and master’s programmes. Remote.
2019 – 2020LinkBizDesigner High-conversion landing pages, copywriting, and API integrations — the first time the output was an automated process rather than a piece of artwork.
2015 – 2018Mix7Art Director Three years leading a team across on and off campaigns, project management and UI/UX.
OngoingCBF · STJDFreelance Websites, landing pages, public notices and campaigns. Recurring retainer relationships.

Background

The path was deliberate
MBAProduct Management & GrowthFIAP
PostgraduateUX / User ExperienceUniNabuco
BAGraphic DesignUniPlan

Design → UX → Product, in that order, credentials following the work. The engineering I learned by building. What runs in production is the proof.

Open to conversations about product engineering and AI systems.