Skip to content

FufuTool: a detailed description of the product

Product 02

FufuTool

live · checked 15:50

One listing, one screen, many portals. Today it publishes to zaflache, Allegro and OLX; Otomoto is still in progress.

Screenshots

01044 screens · test data

Left and right arrow keys switch the item shown on the stage.

Item 1 of 4: Homepage

fufutool.plFufuTool homepage: one listing published to many portals, with a publication status preview, September 2026
fufutool.plThe list of background jobs in FufuTool, test data, September 2026
fufutool.pl"When... then..." rules in FufuTool, test data, September 2026
fufutool.plFufuTool status page, public data, September 2026

01Screen 01

Homepage

FufuTool homepage: one listing published to many portals, with a publication status preview, September 2026

Four screens from our own test copy, filled with made-up data; no phone frames around them, no retouching.

Technologies: Next.js · React · TypeScript · Supabase (PostgreSQL) · Stripe · Tailwind

01

Under the hood

Ten parts that keep the system running. Each one has a name, so you can ask about it by name when you describe your own project.

0106

Ten parts under the hood

011010 parts · each with a name you can quote

Left and right arrow keys switch the item shown on the stage.

Item 1 of 10: Wizard with a list of gaps

Card · part 01

Wizard with a list of gaps

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 02

Team and the list of background jobs

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 03

Three layers of duplicate protection

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 04

Plug-ins for Allegro and zaflache

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 05

Stripe payments

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 06

"When... then..." rules

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 07

Price autopilot

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 08

Photo drop with a QR code

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 09

Connection to ChatGPT and Claude

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

Card · part 10

Backups and status page

Status
live
System
FufuTool
Address
fufutool.pl

ask about this part when you describe your project · Describe your project →

01Part 01

Wizard with a list of gaps

The listing form knows each portal's requirements and, before publication, names what is missing and for which portal. That section is usually empty, because we ask for everything once.

02

How it works

One diagram and two short pieces of code. They show the pattern, not the code that runs the live version: no addresses, no identifiers, no service names.

0206

Diagram

  1. Listing form
  2. Jobs waiting
  3. zaflache ●Allegro ●OLX ●Otomoto ◐

portal plug-ins

A listing on its way from the form to the portalsThe form saves the listing, the list of background jobs hands publishing to the portal plug-ins; zaflache, Allegro and OLX are live, Otomoto is in progress.Listing formJobs waitingzaflache ●Allegro ●OLX ●Otomoto ◐portal plug-ins

● working today · ◐ in preparation

A listing on its way from the form to the portals

Pieces of code

Request fingerprint on a jobTypeScript

Ordering the same publication twice returns the job that already exists instead of making a new one; the fingerprint comes from the content, not from the clock.

// The fingerprint comes from the order itself, not from the clock.
// A second order with the same fingerprint returns the job that exists.
export async function zlecPublikacje(
  baza: Baza, ogloszenieId: string, portal: Portal,
): Promise<Zadanie> {
  const klucz = skrotIdempotencji({ ogloszenieId, portal, operacja: 'publikacja' })
  const istniejace = await baza.zadania.znajdzPoKluczu(klucz)
  if (istniejace && istniejace.stan !== 'blad') {
    return istniejace
  }
  return baza.zadania.dodaj({ klucz, typ: 'publikacja', ogloszenieId, portal })
}
Taking the next job off the waiting listSQL

A background worker takes one job and locks its row; the other background workers skip that row instead of waiting for it.

-- One background worker takes one job; the others skip the locked row
-- instead of waiting for it to be released.
update zadania
   set stan = 'w_toku', pobrano_o = now(), proby = proby + 1
 where id = (
   select id from zadania
    where stan = 'oczekuje' and uruchom_po <= now()
    order by uruchom_po
    limit 1
    for update skip locked
 )
returning id, typ, ladunek;
03

Three decisions

Decisions we made in this system and would make the same way in yours.

0306

Three decisions from this system

01033 decisions · the same way in your project

Left and right arrow keys switch the item shown on the stage.

Item 1 of 3: A change reaches the portals after a delay you can call back

Card · decision 01

A change reaches the portals after a delay you can call back

Risk
a typo on several portals at once costs money
Decision
saved at once, sent after the "Undo" window
Not done
no "send now" by default

FufuTool · technical details below the scene

Card · decision 02

A rule shows first and acts second

Risk
a pricing rule reprices the whole account in a minute
Decision
rehearsal by default, going live is a separate click
Not done
no rules running unseen, with no log

FufuTool · technical details below the scene

Card · decision 03

One fixed set of functions for every portal

Risk
every portal's own quirks end up in the form code
Decision
one shape for every plug-in, with tests
Not done
no Otomoto plug-in without access

FufuTool · technical details below the scene

01Decision 01

A change reaches the portals after a delay you can call back

Once an edit is saved the user gets an "Undo" window; only after it closes does the job go into the waiting list.

Technical details
Context
Editing a listing on several portals at once means several paid or capped operations; a typo costs money.
Decision
Saved on our side at once, sent to the portals after a window in which it can be called back; the waiting job carries the time it may run from.
What we did not do
We did not make "send now" the default; we do not hide the delay either, it is there on screen.
04

Numbers

Every number about the product in one place, under one date stamp.

0406

status as of 2026-09-03
Summary · numbers taken from the code
Counted in the recorded database layout changes and in the test files of the product code; we count them again every quarter and sign the result with the date in the stamp.
What we countCount
Recorded changes to the database layout97
Database tables68
Permission rules kept in the database itself101
Test cases2,010
Test files222
Kinds of job the system runs in the background15
Tools for connecting to ChatGPT and Claude9
05

What is still missing

0506

What is still missing

Otomoto does not publish; it waits on a partner agreement and on access we do not have yet. InPost labels wait on the real access keys. Until that changes both carry the "in progress" stamp, exactly as in the table on the home page.

  • Otomoto (dependent on a partner agreement).
  • InPost labels (the real access keys are not set yet).
in progress
06

What we would carry over to your project

0606

FufuTool

To a program for running orders, or to a connection between systems, we carry over three things from FufuTool:

  1. A list of background jobs kept in the database, with a second attempt after a failure and a fingerprint on every request, so that a dropped connection does not cost you a doubled operation.
  2. One fixed shape for every outside system we plug in (a warehouse and accounting system, a courier, a portal), with tests that prove the shape holds and a rehearsal mode.
  3. A release with a way back: a copy before it, the new version running next to the live one, and a check that the main screens open after it.