A legtöbb kis cég nem azért nem posztol Facebook-ra, mert nincs mondanivalója — azért nem posztol, mert senki nem ül le délután ötkor elgondolkodni azon, hogy hol van a jó képe a héten, milyen felirat illene hozzá, hashtag-et hogyan válasszon, és hogy egyáltalán rátegye-e Instagramra is vagy csak FB-re legyen. Ez több munka, mint amennyit egy 4-fős ügyvédi iroda vagy egy pékség vezetője szívesen csinálna.
Erre született meg a GhostlyPost. A koncepció: odaadod neki a képeidet és a videóidat, ő meg — mint egy szellem a gépben — megírja a caption-öket, kiválasztja a legjobb képet, ütemezi a posztokat, és feltölti őket Facebook-ra meg Instagram-ra. Te annyit csinálsz, hogy rakod bele a képeket. A többit elintézi a gép.
Miért szellem?
A brand-tematikája nem véletlen. A „ghost" szó kettős jelentésű: egyrészt valami, ami
a háttérben dolgozik, nem látszik (ghost-writer), másrészt játékos, nem-corporate
hangulatot ad. A logó egy kedves kis szellem (ghostly.svg), a Messenger
bot válaszai is szellem-tematikájúak: amikor felteszel egy képet, azt mondja
„👻 Megvan, a következő posztban kiküldöm." — nem valami steril „Kérelmét fogadtuk,
ügyintézője hamarosan jelentkezik."-es vállalati automatizmus.
Az a tapasztalat, hogy a KKV tulajdonosok nem a hatalmas funkciólisták miatt választanak eszközt — azért, mert valami emberközeli módon szól hozzájuk. A Ghostly pont ezt csinálja.
Architektúra — szétosztva két konténerbe
A rendszer Proxmox alatt fut, két Linux Container-ben:
-
CT 104 — Dashboard (
dashboard.ghostlypost.com): a fő Flask alkalmazás. Itt van a multi-tenant admin felület, az ügyfélkezelés, a queue rendszer, az AI hívások és a Messenger bot. PostgreSQL ugyanezen a CT-n, gunicorn 5 workerrel, Cloudflare Tunnel HTTPS-hez (nincs nginx, a tunnel közvetlenül a gunicorn-ra csatlakozik). -
CT 106 — Landing (
ghostlypost.com): ez a marketing oldal. Statikus Nginx-en ülő HTML/CSS/JS, dinamikus pricing API-ból tölti a csomagokat — így amikor árat változtatok, a landing magától frissül. -
NAS (
192.168.1.10): SMB shareként mount-olva a CT 104-re. Ezen tárolom az ügyfelek képeit és videóit — nem a DB-ben, nem a CT merevlemezén. A méretbeli skálázhatóság és a backup így könnyebb.
Ez a setup gyakorlatilag olcsó is — havi fix költség nincs, az egész egy otthoni Proxmox szerveren van. A Cloudflare Tunnel ingyenes, és az ügyfelek webhook-jai ezen keresztül érkeznek be.
Queue rendszer — a szív
A posztolás aszinkron, three-phase pipeline-ban történik:
-
Pre-render (15 percenként):
prepare_calendar.pymegnézi, hogy a következő 7 nap ütemezésében milyen slotok vannak, és mindegyikre előre elkészít egy posztot — AI kiválaszt képet, Gemini ír caption-t, berakja a content-naptárba. Az ügyfél a dashboardon előnézetben látja, és kattintással elvetheti vagy szerkesztheti. -
Scheduler (5 percenként):
queue_scheduler.pymegnézi mely posztok esedékesek most, és felvesz egy rekordot apost_queuetáblábapendingállapotban. -
Worker (1 percenként):
queue_worker.pyatomi módon kiszolgál egypendingposztot (UPDATE RETURNING a dupla-futás ellen), átváltjaprocessing-ra, elposztolja Meta Graph API-n keresztül, ésdone-ra állítja.
Három réteg: (1) Partial unique index a
(client_id, post_type, scheduled_date, scheduled_time)-ra,
WHERE status IN ('pending', 'processing'). (2) Atomi claim
— a worker UPDATE ... WHERE id = (SELECT ... LIMIT 1) RETURNING *-gal
ragad ki egy feladatot, tehát két worker sohasem kapja el ugyanazt. (3)
Stale recovery — ha egy feladat 15 perce processing
állapotban van, visszarakja pending-re max 3 próbálkozásig.
Az AI réteg — Gemini + OpenAI fallback
Három dologra használ AI-t a rendszer:
- Caption generálás — Google Gemini 2.5 Flash, iparág-specifikus promptokkal. A fodrász mást kap, mint egy ügyvédi iroda. A brand hangvétele (hashtag pool, tagline, célközönség) mind beleszól.
- Képválasztás — a pipeline felkínál 5 jelölt képet, a Gemini kiválasztja az aznapi „fókusz" alapján a legjobbat. A fókuszok: minimal (tiszta termékfotó), documentary (valós élethelyzet), question (közösségi bevonás), dynamic (mozgalmas), CTA (vásárlásra ösztönző) — plus egyedi fókuszok ügyfél-igény szerint.
- Video scene selection — a Reels feltöltésnél 3 képkockát kihúz a videóból (25%/50%/75%-nál), ezeket pre-tag-eli a Gemini, és a fókusz alapján eldönti melyik videó illik a slot-hoz.
Ha a Gemini API nem válaszol (rate limit, outage), automatikusan átkapcsol OpenAI GPT-4o-mini-re. Ez nem ugyanaz a minőség, de jobb, mint egy „próbáljuk újra 15 perc múlva" üzenet.
A Messenger bot — a kapu
A leginkább eladható funkció nem is a dashboard, hanem a Messenger bot. Az ügyfél saját Facebook-jelenléten keresztül üzenget a GhostlyPost oldalra, és:
- Képet küld → automatikusan bekerül a posztoló várólistájába
- Videót küld → Reels várólistába kerül
- Szöveget küld → a legutóbbi képhez/videóhoz kerül caption hint-ként
- Parancsot ír (pl.
/status,/pause,/post) → a bot azonnal végrehajtja
A parancs-rendszer tizenkét parancsot támogat: /help, /status,
/schedule, /post, /reels, /next,
/pause, /resume, /invoice, /bind,
/unbind. A /bind KÓDNÉV-el az ügyfél egy egyszer használatos
kóddal köti össze a Messenger fiókját a GhostlyPost ügyfél-fiókjával.
A webhook biztonsága HMAC-SHA256 signature-el van védve: a Meta minden callback-et aláír az app secret-jel, a mi oldalunk ellenőrzi. Ha nem egyezik, a kérés eldobódik.
Jogosultság — négy szint
Nem egyszerű admin/user felosztás, hanem négy role:
- SuperAdmin — minden: felhasználók, csomagok, rendszer-konfiguráció, deploy gombok
- Admin — ügyfelek, leads, queue, security log, deploy (de nem felhasználó-kezelés)
- Agent — csak a hozzárendelt ügyfelek kezelése (N:M kapcsolat az
agent_clientstáblán) - User — csak a saját ügyfél dashboard: média feltöltés, ütemezés, branding, számlázás
Ez a séma egy fontos üzleti célt szolgál: agent partnerek tudnak kezelni több ügyfelet (pl. egy marketing ügynökség a saját kliensei nevében), anélkül hogy egymás adatait látnák.
Biztonság — a tokenek
A Meta API token az ügyfél Facebook-oldalához, ez a drágakő. Ha kiszivárog, a GhostlyPost egy spammelő botnet-é válhatna. Ezért:
- Fernet szimmetrikus titkosítás — a tokenek a DB-ben nem
plaintext-ek. A Fernet kulcs az
.env-ben van, soha nem kerül a gitbe. - Brute-force védelem — 5 próba / 5 perc / IP
- CSRF — Flask-WTF minden POST-on
- Honeypot — a regisztráció és a lead űrlapon rejtett mező; ha kitöltve érkezik (bot), csendben eldobjuk
- Magic byte + ffprobe + ClamAV a feltöltött médiához — a kiterjesztés nem elég, ellenőrizzük, hogy a fájl tényleg az amire hivatkozik
Amit megtanultam
A queue az első változat soha nem volt jó. Az első verzióban egy egyszerű scheduler volt, ami közvetlenül posztolt — nem atomi, nem retry-olható, nem recovery-zhető. Amikor egy poszt közben crash-elt a worker, a feladat örökre processing állapotban maradt. Amikor két worker egyszerre indult, duplán posztolt. A partial unique index + atomic claim + stale recovery hármas együtt oldotta meg a dolgot — és ezen tanultam meg, hogy a queue-pattern nem csak technikai nyugalom, hanem ügyfél-bizalom is: a duplán posztolt „új szuper ajánlat" szörnyű benyomás.
Az AI fallback megéri. Mikor a Gemini egyszer két napig elérhetetlen
volt, az OpenAI GPT-4o-mini simán átvette, az ügyfelek észre se vették. A
FALLBACK_AI_PROVIDER env-változó kapcsol közöttük. Ez olyan, mint egy
UPS: reméled nem kell, de amikor kell, ott van.
A Messenger bot a belépő. Az ügyfeleim 80%-a sose nyitja meg a dashboardot — Messenger-ben dobálják be a képeket, és ennyi. A dashboard az admin dolga, nem a felhasználóé. Ezt mindig úgy tervezd meg, hogy egyetlen dologra legyen szükség a felhasználó oldalán — a többit intézd te.
Ki próbálja ki?
Ott van élesben: ghostlypost.com. 14 napos ingyenes próba van most, regisztráció után önboarding wizard vezet végig. Ha kérdésed van, írj egy emailt — én veszem fel a telefont.
A gép ne helyettesítsen — szabadítson fel. Egy KKV vezető nem akar feed-stratégiát írni. Azt akarja, hogy legyen feed, és ő közben foglalkozzon azzal, amiben jó.