Od ideje do deployovanog AI proizvoda: realan put

Prošle godine sam za jedan interni alat potrošio tri dana na CI/CD i dva sata na "AI deo". To nije bio izuzetak, to je pravilo. Kad gradiš AI proizvod kao solo inženjer ili u malom timu, gubiš vreme na sve osim na model. Ovaj post je moj realan put od prazne repozitorije do proizvoda koji radi u produkciji, sa stackom koji koristim najčešće: Next.js, Supabase, PostgreSQL, Docker.
Šta zaista znači "AI proizvod" u produkciji
Kad kažem AI proizvod, ne mislim na demo koji zove OpenAI API iz React komponente. Mislim na sistem koji ima autentifikaciju, bazu sa istorijom razgovora ili artefakata, red za obradu (queue), retry logiku, monitoring troška po korisniku, i UI koji ne puca kad model kasni 40 sekundi. Razlika između PoC-a i proizvoda nije model, nego sve oko modela.
Kad prvi put pustiš pravog korisnika, otkriješ da 80% koda nije AI. To je auth, rate limiting, streaming, error boundary, snimanje inputa za debug, mehanizam za refund tokena kad model vrati smeće. Zato biram stack koji mi to daje besplatno, umesto da svaki put pišem od nule.
Zašto Next.js + Supabase + Postgres + Docker
Ovo je moj podrazumevani izbor za B2B SaaS sa AI komponentom, i evo zašto ga biram iznad Django/Rails ili "microservices from day one" pristupa.
Next.js (App Router) mi daje server components, streaming, i API rute u istom projektu. Za AI proizvod je kritično da mogu da streamujem tokene iz Claude ili OpenAI API-ja direktno u UI. Sa ReadableStream i Server Actions to je pedeset linija koda, ne poseban WebSocket servis.
Supabase rešava tri stvari odjednom: auth, Postgres, i row-level security. Za early stage proizvod nemam vremena da pišem JWT flow, verifikaciju emaila, i middleware za multi-tenancy. RLS mi daje sigurnost na nivou baze, što znači da čak i ako imam bug u API ruti, korisnik ne može da pročita tuđe podatke.
PostgreSQL direktno, jer sa pgvector ekstenzijom imam vektorsku bazu, a sa tsvector full-text search. Za većinu RAG scenarija koje sam gradio, ne treba mi Pinecone ni Weaviate. Jedna baza, jedan backup, jedan hosting račun.
Docker samo za produkciju i za lokalni Postgres+pgvector u razvoju. Ne dockerizujem Next.js dev server, to je gubljenje vremena. Docker mi treba da imam identičan runtime na Fly.io, Railway ili nekom self-hosted VPS-u.
Trade-off koji priznajem: ovaj stack nije optimalan ako imaš tim od 20 ljudi i tri različita servisa. Ali za solo ili tim do 5 ljudi koji šalju proizvod u ruke korisnika za 4-8 nedelja, teško da nešto pobeđuje.
Realan put: od prazne repo do produkcije
Evo šta radim redom, sa vremenom koje realno traje.
1. Šema baze pre koda (dan 1, 3-4 sata)
Ovo je sekcija gde sam najviše grešio ranije. Krenuo bih od UI-ja, pa bih tri puta menjao šemu, i svaki put migracija bi bila bolna. Sad prvo crtam šemu, čak i ako je gruba.
-- Minimalna šema za AI proizvod sa razgovorima
create table profiles (
id uuid primary key references auth.users(id) on delete cascade,
org_id uuid not null,
created_at timestamptz default now()
);
create table conversations (
id uuid primary key default gen_random_uuid(),
org_id uuid not null,
user_id uuid not null references profiles(id),
title text,
created_at timestamptz default now()
);
create table messages (
id uuid primary key default gen_random_uuid(),
conversation_id uuid references conversations(id) on delete cascade,
role text check (role in ('user','assistant','system','tool')),
content jsonb not null,
tokens_in int,
tokens_out int,
model text,
cost_usd numeric(10,6),
created_at timestamptz default now()
);
create index on messages (conversation_id, created_at);
Obrati pažnju na tokens_in, tokens_out, cost_usd. Ovo su kolone bez kojih ne mogu da živim. Kad korisnik posle mesec dana kaže "zašto je moj račun 400 evra", moraš da imaš odgovor po korisniku, po modelu, po danu. Ako to ne postoji od prvog dana, kasnije nikad nećeš da retroaktivno rekonstruišeš.
RLS politike pišem odmah:
alter table conversations enable row level security;
create policy "own org conversations" on conversations
for all using (
org_id = (select org_id from profiles where id = auth.uid())
);
2. Auth i multi-tenancy (dan 1-2, 2-3 sata)
Supabase Auth pokriva login. Ono što ne pokriva besplatno je koncept organizacije. Skoro svaki B2B proizvod treba org_id na svakom redu, i join tabelu org_members(user_id, org_id, role). Ako to ne postaviš na početku, kasnije je pakao.
3. AI sloj kao servis, ne kao poziv (dan 2-3, 4-6 sati)
Ovde većina ljudi zabrlja. Ne zovem OpenAI ili Anthropic API direktno iz UI komponente. Pravim server-side servis sa jasnim interfejsom:
// lib/ai/complete.ts
export async function complete({
orgId, userId, conversationId, messages, model
}: CompleteArgs): Promise<CompleteResult> {
await checkRateLimit(orgId);
await checkBudget(orgId);
const start = Date.now();
const stream = await provider(model).stream({ messages });
return {
stream,
onComplete: async (usage) => {
await logMessage({
conversationId, role: 'assistant',
tokensIn: usage.input, tokensOut: usage.output,
model, costUsd: computeCost(model, usage)
});
}
};
}
Ovaj sloj je taj koji mi omogućava da za jedan dan zamenim Claude sa lokalnim modelom preko Ollame, ili da uvedem Bedrock ako klijent traži AWS. UI ne zna ni ne mari.
4. Streaming u UI (dan 3, 2-3 sata)
Ovo je detalj koji korisnici primete odmah. Ako model odgovara 20 sekundi i UI čeka pa iznenada ispljune tekst, deluje pokvareno. Sa Next.js App Routerom, Server Actions plus useOptimistic plus SSE stream čini korisnika srećnim.
Praktičan trik: uvek renderuj "assistant is typing" indikator odmah kad korisnik pošalje poruku, pre nego što token stigne. Perceptivna latencija se prepolovi.
5. Docker i deploy (dan 4, 3-5 sati prvi put, kasnije 30 minuta)
Za Next.js koristim standalone output i multi-stage Dockerfile:
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
Deploy ide na Fly.io ili Railway za rane faze, na AWS ECS ili self-hosted VPS kad proizvod počne da nosi. Vercel je odličan, ali za AI proizvode sa dugačkim streamovima i heavy background poslovima često dolazi do function timeout-a i skupih poziva. Kontejner mi daje kontrolu.
6. Observability od prvog dana (dan 4-5, 2 sata)
Bez ovoga letiš slepo. Minimum koji uvek postavim:
- Sentry za error tracking u frontendu i backendu
- Struktuirani JSON log za svaki poziv modela (input hash, model, latencija, cena)
- Jedan Postgres view koji agregira trošak po korisniku po danu
Kad klijent posle dve nedelje pita "koliko me košta korisnik X", odgovor je jedan SQL upit, ne dan istraživanja.
Gde se gubi najviše vremena (i kako da ne izgubim)
Ovo je delo koje bih pisao na desetak proizvoda koje sam isporučio. Vremenske procene su moje iskustvo, ne benchmark.
| Aktivnost | Očekivano vreme | Realno vreme | Kako da smanjim |
|---|---|---|---|
| Auth + multi-tenancy | 4h | 12-20h | Supabase Auth + RLS od dana 1 |
| Šema baze i migracije | 2h | 15h (jer je menjaš 4 puta) | Skica na papiru pre koda |
| Streaming UI | 2h | 8-12h | Kopiraj pattern iz prethodnog projekta |
| Deploy pipeline | 3h | 15-25h | Šablon Dockerfile + jedan deploy target |
| Rate limit i budget kontrola | 1h | 6h | Sredi kad prvi korisnik potroši 50 evra |
| Prompt tuning | "beskonačno" | zaista beskonačno | Kraj proizvoda, ne početak |
Najveći kradljivac vremena za mene je bio deploy pipeline. Rana verzija BizFlowAI ContentStudio je imala tri različita deploy skripta jer sam menjao providere. Kasnije sam napravio jedan Docker template koji radi svuda i taj problem je nestao.
Drugi veliki kradljivac je prompt tuning bez evaluacije. Ako nemaš jednostavan set od 20-50 primera koje puštaš kroz svaki novi prompt, tuning je nagađanje. Napravi golden set pre nego što tuniraš.
Šta bih uradio drugačije
Nakon 10+ godina i desetak isporučenih proizvoda, evo mojih najoštrijih zaključaka.
Ne bih više krenuo od UI-ja. UI se menja za dva sata. Šema baze i AI servisni sloj su kičma. Prvo njih.
Ne bih koristio serverless funkcije za sve. Za AI proizvod sa streaming odgovorima i dugotrajnim background poslovima (embedding batch, scraping, evaluacija), kontejner je jednostavniji i jeftiniji. Serverless čuvam za event-driven integracije (moj AWS + Zendesk integracioni projekat je klasičan primer gde serverless briljira).
Ne bih dodavao vektorsku bazu odmah. Za prvih 1000 dokumenata, pgvector je više nego dovoljan. Prelaz na Pinecone ili Qdrant je pitanje jednog dana kad zaista zatreba. Odloži tu odluku.
Ne bih pravio "AI orkestrator" servis dok nemam bar dva modela u produkciji. Prerani apstrakti koštaju više nego kasniji rewrite.
Uveo bih trošak-po-korisniku dashboard prvog dana. Znam da zvuči preterano za MVP, ali je to razlika između proizvoda koji preživi prvu fakturu i proizvoda koji ne preživi.
Skratio bih iteracije sa klijentom. Deploy na staging jednom dnevno, čak i kad ništa nije završeno. Klijent koji vidi napredak je klijent koji ne pravi paničan poziv u petak uveče.
Prakticno: kako izgleda tipičan raspored
Za solo isporuku B2B AI SaaS proizvoda (mislim na pravi MVP koji korisnik plaća, ne demo), moj realan raspored je oko 6-8 nedelja:
- Nedelja 1: šema baze, auth, org model, prvi AI servis endpoint
- Nedelja 2: osnovni UI, streaming, konverzacije
- Nedelja 3: RAG ili domenska logika, embedding pipeline
- Nedelja 4: billing, rate limit, budget kontrola, admin dashboard
- Nedelja 5: staging deploy, prvi beta korisnici, feedback loop
- Nedelja 6: fiks bugova iz produkcije, observability, dokumentacija
- Nedelja 7-8: iteracije po real-world upotrebi, prompt evaluacija
Ako neko obeća isto u dve nedelje, pravi PoC, ne proizvod. To je legitimno, samo neka bude jasno šta je šta.
Gde ovo ima smisla
Ovaj stack i ovaj proces koristim kad radim za domaće i regionalne firme koje traže AI proizvod bez cirkusa oko infrastrukture. Ako gradiš interni alat, B2B SaaS, ili automatizaciju za operativu, Next.js + Supabase + Postgres + Docker te vodi od nule do produkcije brže nego bilo šta drugo što sam probao. Kad proizvod naraste, delovi se zamenjuju bez rewrite-a: Supabase Auth ostaje, Postgres ide na svoj RDS, Next.js kontejner ide na ECS, AI sloj ostaje isti.
Ako gradiš AI proizvod i ne znaš gde da počneš ili si zaglavio u fazi "PoC radi, produkcija ne", javi se preko lazar-milicevic.com/#contact. Najkorisnije razgovore vodim kad neko dođe sa konkretnim problemom, ne sa apstraktnom idejom. Rado ti pokažem gde bih ja skratio put.
Često postavljana pitanja
Koji tech stack je najbolji za solo inženjera koji pravi AI proizvod?
Za solo inženjere i male timove koristim Next.js, Supabase, PostgreSQL i Docker kao podrazumevani stack za B2B SaaS sa AI komponentom. Next.js daje server components, streaming i API rute u istom projektu, Supabase rešava auth, Postgres i row-level security odjednom, a Postgres sa pgvector zamenjuje posebne vektorske baze poput Pinecone-a. Ovaj stack omogućava da proizvod bude u rukama korisnika za 4-8 nedelja, umesto meseci koje bi zahtevao pristup sa mikroservisima ili Django/Rails.
Koja je razlika između AI PoC-a i pravog AI proizvoda u produkciji?
Razlika nije u modelu, nego u svemu što ga okružuje. Pravi AI proizvod ima autentifikaciju, bazu sa istorijom razgovora, red za obradu, retry logiku, monitoring troška po korisniku i UI koji ne puca kad model kasni 40 sekundi. Kada pustiš prvog realnog korisnika, otkriješ da 80% koda uopšte nije AI, već auth, rate limiting, streaming, error boundary, logovanje inputa za debug i mehanizam za refund tokena kad model vrati loš odgovor.
Da li mi treba Pinecone ili posebna vektorska baza za RAG?
Za većinu RAG scenarija ne treba ti posebna vektorska baza kao Pinecone ili Weaviate. PostgreSQL sa pgvector ekstenzijom daje vektorsku pretragu, a sa tsvector imaš full-text search u istoj bazi. To znači jedna baza, jedan backup i jedan hosting račun, što drastično smanjuje operativnu složenost za mali tim. Posebna vektorska baza ima smisla tek kad imaš zaista velike količine podataka ili specifične performanse.
Kako pratiti trošak AI modela po korisniku od prvog dana?
Trošak se prati tako što u tabelu messages odmah dodaš kolone tokens_in, tokens_out, model i cost_usd, i logujuš ih svaki put kad model odgovori. Bez ovih kolona od prvog dana, ne možeš retroaktivno da rekonstruišeš ko je koliko potrošio kada korisnik pita zašto mu je račun visok. Preporučujem AI sloj kao server-side servis sa onComplete callback-om koji upisuje usage u bazu odmah po završetku streama.
Kako implementirati multi-tenancy u Supabase za B2B AI proizvod?
Multi-tenancy postavljam tako što svaki red u bazi ima org_id kolonu, plus join tabelu org_members(user_id, org_id, role). Row-level security politike u Postgresu obezbeđuju da korisnik može da vidi samo redove svoje organizacije, čak i ako postoji bug u API ruti. Supabase Auth pokriva login, ali koncept organizacije moraš sam da dodaš, i kritično je da to uradiš na samom početku jer je kasnija migracija izuzetno bolna.
Gradiš nešto teško sa AI-jem ili automatizacijom? Otvoren sam za razgovor.
Javi se