Skip to main content
Glama
mob-dev-org

olx-pik-toolkit

by mob-dev-org
README.md
# olx-pik-toolkit

Interni CLI i MCP server za upravljanje OLX.ba / PIK.ba shopovima. Jedno jezgro (`src/core`), dva lica: CLI (`src/cli`) i MCP server (`src/mcp`).

## Zahtjevi

- Node.js 20.12 ili noviji (ispod toga se `.env` tiho preskace jer `loadEnvFile` ne postoji;
  preflight to obara). Preporuka: 22 LTS.
- Odobren API pristup za shop (Gold ili Platinum + odobrenje OLX/PIK podrske). Provjeri sa `olx whoami`.
- Za klon koji vrti Telegram bota jos i `bun` u PATH-u (Telegram plugin njime dize svoj MCP
  server; sam plugin instaliraju pripremi skripte).

## Brzi start

```bash
bun install
bun run build
cp .env.example .env     # popuni OLX_TOKEN ili OLX_USERNAME/OLX_PASSWORD
bun dist/cli/index.js whoami
```

Provjere: `bun run test` (testovi match logike, bez mreze) i `bun run typecheck`.

## CLI primjeri

```bash
# Sigurno (citanje)
bun dist/cli/index.js listings ls --state active --all
bun dist/cli/index.js users profile <username>           # javni profil shopa (paket, ocjene)
bun dist/cli/index.js refresh limits
bun dist/cli/index.js category suggest "golf 7"
bun dist/cli/index.js sponsor price 12345 --type 2 --days 7 --refresh-every 8

# Obnova
bun dist/cli/index.js refresh one 12345
bun dist/cli/index.js refresh all --limit 200            # dry-run
bun dist/cli/index.js refresh all --limit 200 --yes      # izvrsi

# Trosak kredita (uvijek trazi --yes)
bun dist/cli/index.js sponsor apply 12345 --type 2 --days 7 --refresh-every 8 --yes

# Planer izdvajanja: predlog u fajl (ne trosi), pa izvrsenje termina dospjelih danas
bun dist/cli/index.js sponsor plan napravi --budzet 500 --dana 7 --trajanje 7
bun dist/cli/index.js sponsor plan prikazi
bun dist/cli/index.js sponsor plan izvrsi              # probni prikaz
bun dist/cli/index.js sponsor plan izvrsi --yes        # naplacuje

# Slike (URL-ovi i/ili lokalni fajlovi)
bun dist/cli/index.js listings images add 12345 --url https://primjer.com/1.jpg https://primjer.com/2.jpg
bun dist/cli/index.js listings images add 12345 --file ./slika1.jpg ./slika2.jpg
bun dist/cli/index.js listings images main 12345 67890     # postavi glavnu sliku po imageId
bun dist/cli/index.js listings images rm 12345 67890        # obrisi sliku
```

Napomena o slikama (potvrdjeno uzivo): API prima slike samo kao stvarne fajlove preko `multipart/form-data`, pod poljem `images[]`. Ne prihvata `image_url`. Zato `--url` prvo preuzme sliku pa je posalje kao fajl, a `--file` salje lokalni fajl direktno. Oba zavrse isto na `POST /listings/:id/image-upload`.

## Spajanje sa vanjskim katalogom (komanda match)

CLI ima komandu `match` koja spaja PIK oglase sa artiklima iz vanjskog kataloga (po sifri, pa po
slicnosti naslova: IDF Jaccard i trigram Dice, sa normalizacijom dijakritika). Katalog se predaje
kao fajl, pa repo ne nosi kredencijale nijednog vanjskog sistema:

```bash
bun dist/cli/index.js match --katalog izvoz.csv --out izvjestaj.json
bun dist/cli/index.js match --katalog shopify-izvoz.json --with-sku
```

Prihvata se CSV sa kolonama `sifra, naziv, zaliha, cijena` (izvoz iz WooCommerce, ERP-a, Excela)
ili JSON (Shopify izvoz sa `handle/title/skus/totalInventory/price`, ili neutralna imena polja).
Prazna zaliha ostaje nepoznata, ne nula, da se ne skrije oglas koji je pun. Logika je u
`src/core/match.ts` i `src/core/katalog.ts`, pokrivena testovima (`bun run test`).

## Snapshot kategorija i lokacija (statički, bez stalnog dohvatanja)

Kategorije i lokacije se rijetko mijenjaju, pa se jednom povuku u JSON i koriste kao statički MCP resource (`olx://categories`, `olx://locations`). Pokreni jednom kad token proradi:

```bash
node --env-file=.env dist/cli/index.js category dump      # -> olx-dokumentacija/categories.json
node --env-file=.env dist/cli/index.js location dump      # -> locations.json + locations.csv (lagani index)
```

`category dump` uz puni `categories.json` pravi i lagani `categories.csv` (index: id, parent_id, level, path, name + zastavice brand/model/has_models/show_condition/fee). CSV se regenerise iz JSON-a i bez API poziva: `bun dist/cli/index.js category index`.

Zatim commitaj te fajlove. Poslije toga AI/MCP cita kategorije i lokacije iz resursa bez ijednog API poziva:

- `olx://categories-index` (CSV) za PRONALAZAK kategorije po imenu/path. Lagano, koristi prvo.
- `olx://categories` (puni JSON) samo kad trebas polja kojih nema u CSV-u.
- `olx://locations-index` (CSV) za `country_id` (BiH = 49) i `city_id` po imenu. Lagano, koristi prvo.
- `olx://locations` (puni JSON) samo za detalje (lat/lon, zip, state).

Za forme i opcije izabrane kategorije koristi live alat `olx_category_attributes <id>` (opcije nisu u snapshotu, dolaze iz API-ja). Pojedinacni live upiti su i dalje dostupni (`category list/children/get/brands/models`, `location countries/cities/city`).

## Jedan klon, jedan klijent, jedan nalog

Ovaj repozitorij se klonira po klijentu. U `.env` tog klona ide token samo tog naloga:

```bash
OLX_TOKEN=token_tog_naloga
```

Zato u toolkitu nema profila, nema prebacivanja naloga i nema alata koji mijenja nalog u letu.
Radnja ne moze zavrsiti na pogresnom klijentu, jer u procesu postoji samo jedan nalog. Za drugog
klijenta kloniraj repo ponovo i postavi njegov token.

Ko je klijent ovog klona pise u `KLIJENT.md` (kopija `KLIJENT.primjer.md`, u `.gitignore`):
naziv firme, username, glavne kategorije, ton komunikacije, sta bot smije bez pitanja i sta nikad
bez potvrde. Brojevi (paket, krediti, kvota obnova) se ne prepisuju tamo, nego citaju sa API-ja.

Kad token istekne: ako su u `.env` postavljeni `OLX_USERNAME` i `OLX_PASSWORD`, toolkit sam
obnovi token na prvi 401 i ponovi citanje. Radnje koje trose kredite se posle obnove NE ponavljaju
same, nego se javlja da ih treba pokrenuti ponovo, da se nista ne naplati dva puta.

## MCP server

```bash
bun run build
bun dist/mcp/server.js   # radi preko stdio
```

Server izlaze `admin` (puna lista) ili `klijent` (suzena, bez kataloga, lokacija i analitike
konkurenata). Tacan broj alata po profilu mjeri `bun run kontekst`.

Profil se ne bira samo kroz `.env`. Klijentsku bot sesiju server prepoznaje sam, po `OLX_SESIJA_TIP`
odnosno po runtime mapi `.claude-runtime` (postavlja ih `scripts/lib/sesija.mjs`), i tada tvrdo
uzima klijentski profil bez obzira na `.env`. Posljedica u praksi: goli `claude` u terminalu klona
daje vlasniku pun alat, a musterijin bot ostaje suzen i kad `.env` kaze `admin`.

`OLX_MCP_PROFILE` u `.env` je drugi sloj i smije samo SUZITI: postavljen na `klijent` uzima alate i
terminalu i admin botu. Da klijentski put stvarno daje suzen profil provjerava
`bun scripts/provjeri-klon.mjs`, i to mjerenjem ishoda, ne citanjem varijable.

## Pogon klijenta: dvije sesije, cron, AI runda

Puna mapa sa dijagramima je u `olx-dokumentacija/arhitektura.md` — nju procitaj prvu. Sazetak:

- **Klijentska sesija**: Telegram bot klijenta, profil `klijent`, pravila u
  `runtime/SISTEM-klijent.md`. AI pogon bira `OLX_KLIJENT_AI` u `.env` (`pretplata` ili
  `deepseek` preko `OLX_DEEPSEEK_*` varijabli; bez njih se sesija ne pokrece). DeepSeek nema
  vid, pa za objavu iz fotografije postoji vision proxy: uz `OLX_VID_API_KEY` u `.env` server
  registruje alat `olx_opisi_sliku` koji sliku opise jeftinim Claude Haiku modelom (desetinka
  centa po slici) i vrati tekst sesiji. Na pretplati nije potreban i ne registruje se.
- **Admin bot sesija** (opcion po klonu): vlasnikov privatni Telegram kanal za taj shop,
  profil `admin`, uvijek na pretplati, bez Bash-a. Priprema:
  `bun scripts/pripremi-admin-runtime.mjs <bot_token> <tvoj_telegram_id> [id_admin_grupe]`.
  BotFather privacy za admin bota OSTAJE ukljucen (u grupi prima samo mention i reply);
  za klijentskog bota se privacy GASI.
- **Telegram most** `scripts/telegram-most.mjs [klijent|admin-bot]`: jedan dugoziv proces koji
  sam radi `getUpdates` i sam salje `sendMessage` (bez Telegram plugina), drzi sesiju zivom dok
  se radi. Gasi zivu sesiju (kontekst OSTAJE, `--resume` je nastavlja) poslije mirovanja
  (`OLX_MOST_IDLE_MIN`, default 30 min; admin override `OLX_MOST_ADMIN_IDLE_MIN`), i gasi je uz
  BRISANJE konteksta u nocnom rezu (`OLX_MOST_RESTART_SAT`, default 3h). Nijedna poruka se ne
  gubi: Telegram offset se pomjera tek kad je poruka upisana u red na disku, a stavka izlazi iz
  reda tek kad je odgovor poslan.
- **Rucna proba sesije** `bun scripts/pokreni-klijenta.mjs`: ista klijentska sesija u ISTOM
  terminalu, na obje platforme (Windows PowerShell ukljucen); greska se vidi odmah, umjesto po
  logu mosta. Prije probe ugasi posao `sesija` (telegram-most.mjs) ako radi, jer dva konzumera
  na istom bot tokenu daju 409. Telegram plugin zivi u `.claude-runtime/plugins/` (po klonu, ne
  globalno) i instaliraju ga pripremi skripte same.
- **Cron poslovi bez modela** (nula tokena): snapshot pregleda 02:40, dnevne obnove i jutarnja
  poruka 07:20, backup stanja 08:10, sedmicni pregled ponedjeljkom 07:40. Vrti ih CLI
  (`posao dnevni`, `posao sedmicni`, `posao backup`, `stats snapshot`).
- **Backup klijentskog stanja** (`posao backup`): pamcenje, izuzeca, audit trag i snapshoti
  pregleda idu na privatnu granu po klijentu u odvojenom repou stanja. Tokeni namjerno ne idu.
  Snapshoti su nezamjenjivi retroaktivno, jer OLX ne daje istorijske preglede. Nadzor sa admin
  strane: `scripts/backup-nadzor.sh` (ponedjeljak 09h) javi svaki klon koji kasni.
- **AI runda** (nedjelja 21h, jednom za cijelu masinu): headless analiza svih klonova iz
  `~/.olx-klijenti.txt` kroz vlasnikovu pretplatu, strogo read-only; izvjestaj ide klijentu u
  grupu, prijedlozi u `.olx-pik/prijedlozi/`, odakle ih klijentski bot cita alatom `olx_prijedlozi` i
  primjenjuje uz potvrdu (Read nad `.olx-pik` mu je zabranjen, pa ide kroz alat).

Instalacija svih poslova: macOS `scripts/instaliraj-cron.sh` (launchd, po klonu; AI runda se
instalira rucno jednom, uputa u sablonu), Windows
`deploy/windows/instaliraj-zadatke.ps1` (Task Scheduler, isti termini). Na Windowsu kredencijali
pretplate zive u config diru, pa svaki runtime trazi svoj `claude login` PRIJE instalacije
poslova: u PowerShellu `$env:CLAUDE_CONFIG_DIR=".claude-runtime"` pa `claude login` (kad
klijentska sesija ide na pretplatu; na DeepSeeku ne treba), i isto sa `.claude-runtime-admin`
za admin bota. Na macOS-u su u Keychainu pa login ne treba.

## Potrosnja tokena po klijentu

Svaki klon biljezi vlastitu potrosnju sam od sebe: transkripti sesija nose tacan broj tokena
po poruci (ulaz, kes, izlaz, model), odvojeno za klijentsku i admin sesiju. Izvjestaj:

```bash
bun run tokeni                    # zadnjih 30 dana, po danu i modelu, sa USD i projekcijom
bun run tokeni -- --od 7          # zadnjih 7 dana
bun run tokeni -- --dan 2026-07-28
bun run tokeni -- --upisi         # spoji zbirove u trajni dnevnik (pokreni sedmicno)
bun run tokeni -- --json          # masinski izlaz za dalju obradu
```

Transkripti se ciste poslije ~30 dana, pa `--upisi` cuva dnevne zbirove trajno u
`.olx-pik/tokeni-dnevnik.jsonl`. Cijene modela su na jednom mjestu, `scripts/ai-cijene.mjs`;
model kojeg tamo nema dobija tokene bez dolara, broj se ne izmislja. Izlaz ukljucuje prosjek po
aktivnom danu i projekciju na 30 dana, sto je osnova za predikciju troska po klijentu.

## Za kolege: kloniranje i dodavanje MCP-a u Claude Code

Repozitorij ima `.mcp.json` u korijenu, pa Claude Code automatski ponudi `olx-pik` MCP server kad otvoriš projekat. Token se NE čuva u repou; svako postavlja svoj kroz env varijablu `OLX_TOKEN`.

Koraci poslije kloniranja:

```bash
# 1. Build (dist/ je u .gitignore, pa se mora lokalno izgraditi)
bun install
bun run build

# 2. Postavi svoj token u okruzenje (zamijeni vrijednost svojim tokenom)
export OLX_TOKEN=tvoj_token        # zsh/bash; trajno dodaj u ~/.zshrc ili ~/.bashrc

# 3. Otvori Claude Code u korijenu repozitorija
claude
```

Windows PowerShell ekvivalenti: `copy .env.example .env`, `$env:OLX_TOKEN="tvoj_token"` za
tekucu sesiju (trajno: `setx OLX_TOKEN "tvoj_token"` pa NOV terminal).

Pri prvom otvaranju Claude Code pita da odobriš projektni MCP server `olx-pik`. Potvrdi, pa provjeri sa `/mcp`. Server preuzima `OLX_BASE_URL` iz `.mcp.json`, a `OLX_TOKEN` iz `.env` fajla klona ili iz okruženja procesa.

Alternativa bez `.mcp.json` (registracija samo za tebe, token ostaje lokalno):

```bash
claude mcp add olx-pik -s user \
  -e OLX_TOKEN=tvoj_token \
  -e OLX_BASE_URL=https://api.olx.ba \
  -- node "$(pwd)/dist/mcp/server.js"
```

PowerShell (jedan red, bez `\` nastavaka):

```powershell
claude mcp add olx-pik -s user -e OLX_TOKEN=tvoj_token -e OLX_BASE_URL=https://api.olx.ba -- node "$PWD/dist/mcp/server.js"
```

Napomene:
- Bez postavljenog `OLX_TOKEN` server se podigne, ali API pozivi vraćaju 401/403. Provjeri pristup sa `node --env-file=.env dist/cli/index.js whoami` ili kroz MCP alat `olx_whoami`.
- Token nikad ne commitati. `.env` i pravi tokeni su u `.gitignore`.

## Claude Code skillovi

Repozitorij nosi jedanaest skillova u `.claude/skills/` (folder je skriven u file browserima jer pocinje tackom, ali je u gitu):

- `olx-novi-klijent`: ULAZNA TACKA za postavku novog klijentskog klona na novom racunaru, od
  kloniranja do zivog bota (.env, Telegram runtime za oba bota, plugin, cron, preflight).
- `olx-mcp-setup`: postavljanje i koristenje toolkita (token, MCP, CLI, troubleshooting).
- `olx-analiza-profila`: analiza vlastitog profila i oglasa; analiza konkurenta po username-u.
- `pik-olx-kreditni-savjetnik`: potrosnja kredita, izdvajanje, cjenovnik, strategija promocije.
- `olx-shopovi-snimci`: obrada Excel snimaka shopova, sva cetiri PIK paketa (razdvajanje po kantonima, po potrebi i u odvojen fajl po nivou paketa, poredjenje dva snimka, telefon kandidata).
- `olx-seo-oglasa`: naslov, podnaslov i format opisa; izvjestaj pa primjena tek uz potvrdu.
- `olx-klijent-flow`: kandidat iz javnih podataka, onboarding sa tokenom, prvi potezi po ROI.
- `olx-cron-obnove`: raspored obnova i ravnomjerno trosenje kvote (izvrsenje nosi CLI cron).
- `olx-objava-artikla`: vodjena objava novog oglasa od slike do objave, sa provjerom nacrta.
- `olx-serijski-posao`: posao kroz mnogo oglasa odjednom, preko podagenata iz `.claude/agents/`.
- `olx-izdanje`: zatvaranje posla i pustanje koda u flotu klijenata (verzija, tag, `stabilno`).

Dolaze automatski sa kloniranjem; nista se ne instalira posebno. Sistemski prompt nosi
`CLAUDE.md` u korijenu (tvrde granice kroz `olx-dokumentacija/granice.md`), a po sloju se sama
ucitavaju i pravila iz `.claude/rules/` (`paths` frontmatter).

### Dnevna obnova

Dnevnu obnovu NE radi model: CLI `posao dnevni` (launchd/Task Scheduler u 07:20) obnovi oglase
unutar besplatne kvote po tempu do reseta kvote i posalje jutarnju poruku klijentu, sve za
nula tokena. Skill `olx-cron-obnove` sluzi za razgovor o rasporedu i kvoti, ne za izvrsenje.
Izdvajanje i akcijska cijena nikad automatski.

### Audit log

Svaka radnja koja mijenja stanje ili trosi kredite upisuje se u `.olx-pik/audit.jsonl` (jedan JSON
po liniji, van gita). Zapis nosi vrijeme, **verziju toolkita** (`version`), ime komande ili MCP
alata, metodu, putanju, status, trajanje i broj pokusaja, a kod odbijenog troska i to da potvrda
nije data. Verzija je tu jer "sta je radjeno i kada" ne pomaze kad se ponasanje promijenilo izmedju
dva izdanja: zapis mora reci i kojim kodom je radnja izvrsena. Tijelo zahtjeva se
nikad ne zapisuje, jer login nosi lozinku. Citanja se ne biljeze osim ako se postavi
`OLX_AUDIT_READS=1`. Putanja se mijenja kroz `OLX_AUDIT_FILE`; prazna vrijednost gasi log.

### Verzija i izdanja

Verzija sistema stoji u `src/core/verzija.ts` i vidi se na cetiri mjesta: `olx --version`, MCP
handshake, polje `version` u audit logu i prva stavka `bun scripts/provjeri-klon.mjs`. Na kojem je
izdanju klon: `git describe --tags`.

Izdanje se pravi sa `bun scripts/izdanje.mjs <broj>` (provjeri preduslove, pa `bun pm version` vrti
testove, prepise konstantu i izgradi), nosi anotiran tag `vX.Y.Z`. Pustanje u flotu je
`bun scripts/pusti-u-flotu.mjs [--pomjeri-stabilno]`: bez zastavice sve je povratno, sa njom se
pomjera prekidac `stabilno` (koji kaze koje izdanje flota vozi) i azurira flota. Cijeli tok vodi
skill `olx-izdanje`. Sta je uslo po izdanju: `CHANGELOG.md`. Zasto dva taga:
`olx-dokumentacija/arhitektura.md`, sekcija 7.

Zaostaje li ovaj klon: `bun scripts/provjeri-izdanje.mjs` (isto javi i hook pri pokretanju
sesije). Povlacenje jednog klona: `bun scripts/azuriraj-ovaj-klon.mjs [--restart]`, koji pri padu
builda ili testova sam vraca klon na prethodno izdanje. Sesija kod ne povlaci sama od sebe.

### Podaci klijenata

Onboarding klijenta pise baseline i zapise poteza u `klijenti/<ime>/`. Taj folder je u
`.gitignore` jer sadrzi podatke klijenata. Token klijenta ide u `.env` tog klona kao `OLX_TOKEN`,
a kontekst klijenta u `KLIJENT.md`. Nista od toga ne ide u git.

Izvori znanja (jedan izvor istine, ne duplirati brojeve po skillovima):
- `olx-dokumentacija/OLX_PIK_AI_Knowledgebase.md` — pravila platforme, paketi, kvote, pretraga.
- `olx-dokumentacija/API-INVENTAR.md` — svi MCP alati, parametri, rupe u API-ju.
- `olx-dokumentacija/PIK-pomoc-korpus/` — 52 zvanicna clanka podrske (pomoc.olx.ba).
- `olx-dokumentacija/sta-sistem-radi.md` — sta sistem radi, obicnim jezikom i bez imena alata. Pise se rukom i cita minut prije razgovora sa klijentom.
- `olx-dokumentacija/mogucnosti.md` — potpun tehnicki popis: alati, resursi, CLI komande, zakazani poslovi, postavke, skillovi i podagenti. GENERISAN iz koda, ne uredjuje se rukom.
- `olx-dokumentacija/mogucnosti.html` — isti sadrzaj kao stranica, sa pretragom i prekidacem profila. GENERISAN iz koda, ne uredjuje se rukom.

Oba generisana fajla pravi `bun scripts/popis-mogucnosti.mjs`, a `bun run test` pada kad zaostanu za kodom.

`PLAN.md` je arhiviran handoff iz faze prije builda; stvarno stanje opisuju README i API-INVENTAR.