# Infrastruktura — priprema za produkciju

Datum: 7. septembar 2026.

**Status: izmene source konfiguracije su pripremljene i lokalno proverene. Produkcija nije objavljena niti je stvarna Entra prijava potvrđena.** Pre objave administrator mora podesiti produkcijsku bazu, efektivne Entra vrednosti, App Registration, DNS, sertifikat i HTTPS preusmeravanje. Lokalni preflight namerno vraća neuspeh dok nedostaju Entra kredencijali i konfiguracija baze ima staging oznake.

## A. Izmenjeni fajlovi

Sve putanje su relativne u odnosu na `C:\Users\Dimitrije\Desktop\sos-infrastruktura`.

| Fajl | Promena i razlog |
| --- | --- |
| `config.php` | Samo podrazumevani `ENTRA_REDIRECT_URI` prebačen na produkciju. Postojeći environment/secrets prioritet sačuvan. Stvarni pristupni podaci nisu menjani. |
| `config.example.php` | Produkcijski callback umesto pogrešno napisane staging adrese; učitavanje secrets fajla usklađeno sa postojećim `config.php`, uključujući fallback iznad document root-a kada HOME nije dostupan. |
| `app/bootstrap.php` | Session cookie ima prazan Domain atribut, odnosno host-only ponašanje. Više ne nasleđuje stari domen iz `php.ini`. Secure, HttpOnly, SameSite i trajanje ostaju isti. |
| `.htaccess` | Zabranjen javni pristup lokalnim environment/secrets fajlovima, instalacionom vendor arhivu, Git i SSL-manager metapodacima. DCV/ACME validacione putanje nisu blokirane novim pravilom. Postojeće rute i CSP nisu prošireni. |
| `.productionignore` | Dodata izuzeća za lokalni `config.php`, environment/secrets fajlove, instalacioni arhiv i hosting/SSL metapodatke, da ne prepišu produkcijsko okruženje. |
| `.gitignore` | Nova zaštita od budućeg dodavanja lokalne konfiguracije, SQL dumpova, upload podataka, logova i hosting metapodataka u Git. Ne uklanja sadržaj koji je ranije već praćen. |
| `ENTRA_AUTH_IMPLEMENTATION.md` | Tri URL primera ažurirana; razjašnjeni Web platforma, lokalna odjava, odvojene staging vrednosti i činjenica da promena domena ne zahteva SQL migraciju. |
| `README.md` | Link ka ovom postupku, odvojenom od istorijskih nadogradnji. |
| `qa_production_config.php` | Nova read-only CLI provera konfiguracije i PHP preduslova, bez ispisa tajni, mrežnih zahteva ili pristupa bazi. Web pristup odbija sama skripta i postojeće Apache QA pravilo. |
| `PRODUCTION_MIGRATION.md` | Ovaj izveštaj i koraci administratora. |
| `QA_PRODUCTION_STAGING_REFERENCES.txt` | Popis svake preostale staging reference po fajlu i redu, sa klasifikacijom i razlogom zadržavanja. |

Dizajn, CSS/JavaScript aplikacije, API endpointi, autorizacija, role, ticket workflow, struktura i podaci baze nisu menjani. Nije dodata funkcionalnost za reset lozinke. Postojeća promena lozinke i obavezna promena privremene lozinke nisu reset-password tok.

## B. Staging URL reference i obuhvat analize

Pre bilo kakve izmene inventarisano je i pretraženo svih **505 fajlova**, uključujući skrivene fajlove, `vendor`, `uploads`, SQL dump i log. Pregledano je i 407 članova vendor ZIP arhiva, kao i dekodirani SSL-manager JSON.

| Početna grupa | Broj pojavljivanja | Promenjeno | Zadržano |
| --- | ---: | ---: | ---: |
| Tačan staging hostname `infrastage.sos-mig.com` | 427 | 1 | 426 |
| Pogrešno napisan hostname `infrastrage.sos-mig.com` | 4 | 4 | 0 |
| Ostale reference koje sadrže `sos-mig.com` u istorijskom logu | 3 | 0 | 3 |
| Dodatna referenca u base64 SSL-manager JSON-u | 1 | 0 | 1 |
| **Ukupno bez dvostrukog brojanja podstringova** | **435** | **5** | **430** |

Obična tekstualna/binarna pretraga prvobitno daje 434 pojavljivanja šireg domena; dekodiranje metapodataka dodaje jedno. Ove brojke su pojavljivanja, ne broj fajlova ili jedinstvenih URL-ova.

Zadržane originalne reference:

- `error_log`: 428 pojavljivanja šireg domena, od kojih 425 sadrži tačan staging hostname. To su istorijske serverske putanje/poruke, a ne runtime konfiguracija. Log nije prepisivan; isključen je iz objave i javnog pristupa.
- `.well-known/ssl-manager/installed.txt:1`: jedan hostname, evidencija prethodne instalacije SSL-a. Nije sertifikat niti konfiguracija aplikacije; hosting njime upravlja.
- `.well-known/ssl-manager/installed.b64.json:1`: jedna dodatna referenca nakon base64 dekodiranja, u polju `domain`. Nije menjana da se ne falsifikuje evidencija hostinga. Oba metapodatka su isključena iz produkcionog paketa.
- Novi izveštaj namerno navodi stare adrese radi evidencije i ručnih koraka. Njegove reference su dodatno i odvojeno popisane u `QA_PRODUCTION_STAGING_REFERENCES.txt`; nisu uključene u početnih 435.

Završna pretraga cele radne kopije daje **434 direktna pojavljivanja + 1 dekodirano = 435**: 430 sačuvanih originalnih referenci i pet novih istorijskih navoda u ovom izveštaju. Pet prvobitnih source/dokumentacionih vrednosti jeste promenjeno; nove reference u izveštaju nisu runtime zavisnosti.

**U izvršnom aplikacionom kodu i primerima produkcione konfiguracije nema preostalih staging domena.** Ponovljena pretraga obuhvata i redirect/callback/logout/authority/tenant/client/MSAL/Entra/Azure/OIDC/OAuth termine. Vendor ZIP nema staging reference; bibliotečki primeri drugih domena nisu aplikaciona konfiguracija.

### Nalazi po komponentama

- Arhitektura: serverski PHP/MySQL sistem, Apache `.htaccess`, Composer OIDC biblioteka i običan JavaScript/CSS; nema odvojenog SPA frontenda ili backend API hosta.
- Svi aplikacioni frontend pozivi koriste relativne putanje. Pretraga učesnika poziva `participant_search.php`; sesija poziva `session_activity.php`, `session_extend.php` i `logout.php`, sa same-origin credentials.
- Ticket, profil, administrativni, upload/download i asset linkovi koriste postojeći `url()` mehanizam. Ne uvodi se `/api` prefiks niti menja API contract.
- Notifikacije su u bazi, sa relativnim `ticket_view.php?id=...`, `dashboard.php` i `account.php#...` linkovima. Helper odbija spoljne apsolutne linkove. U dumpu nema staging domena ni URL konfiguracije koju treba menjati.
- Nema implementiranog email/SMTP/Graph slanja, email template sistema ili activation/invitation URL-ova u ovoj kopiji; takvi tokovi nisu dodavani.
- Nema axios, WebSocket, service worker, web manifest, sitemap, Docker, nginx konfiguracije, `.env`, package.json ili CI/CD konfiguracije. `app/header.php` sadrži `noindex,nofollow` robots meta oznaku.
- HTTP reference u SVG/OpenXML su namespace identifikatori; Composer/vendor dokumentacija sadrži bibliotečke URL-ove. To nisu HTTP asset zahtevi niti mixed content aplikacije.
- Jedini SQL fajl je `trenutnabaza.sql`, sa 17 tabela, postojećim Entra kolonama i indeksima. Pregled dumpa ne potvrđuje stanje buduće produkcione baze.

## C. Production konfiguracija

| Stavka | Efektivna namera / vrednost |
| --- | --- |
| Frontend | `https://infrastruktura.sos-decijasela.rs` |
| Backend/API | Isti origin: `https://infrastruktura.sos-decijasela.rs`; npr. `/participant_search.php`, `/session_activity.php`, `/session_extend.php`, `/attachment_download.php?id=...`. Nema zasebnog `/api` servisa. |
| BASE_URL | Postojeći `config.php`: prazna vrednost; primer: `auto`. `USE_ABSOLUTE_BASE_URL` ostaje false ili nije definisan. |
| CORS | Same-origin. Nema `Access-Control-Allow-Origin` middleware-a ili posebne allowliste; produkcijski browser pozivi idu na sopstveni origin. Ne dodavati `*` ili credentials CORS zaglavlja bez potrebe. |
| Cookie/session | Postojeći session name `ticketa_session`; lifetime 0, path prema postojećem PHP podešavanju (u testu `/`), host-only, Secure=true, HttpOnly=true, SameSite=Lax; strict mode, cookies-only, trans_sid isključen. |
| Istek/CSRF | 600 sekundi neaktivnosti + 60 sekundi upozorenja; CSRF token je u serverskoj sesiji. Nema remember-me cookie-ja ili odvojenog CSRF cookie-ja. |
| Trusted proxy | `TRUSTED_PROXY_IPS=[]` dok administrator ne navede stvarne neposredne proxy IP adrese. Samo pouzdani peer sme uticati preko `X-Forwarded-Proto`/`X-Forwarded-SSL`. `X-Forwarded-Host` se ne koristi za generisanje URL-ova. |
| CSP/security headers | `connect-src`, `script-src`, `img-src`, `form-action` koriste `'self'` uz postojeće dodatke; `frame-ancestors 'none'`; Referrer-Policy `strict-origin-when-cross-origin`. Produkcijski origin prirodno odgovara `'self'`. PHP šalje HSTS `max-age=31536000` kada prepozna HTTPS. |
| Entra client/tenant | `ENTRA_CLIENT_ID` = Application (client) ID; `ENTRA_TENANT_ID` = Directory (tenant) ID. Stvarne vrednosti nisu dostupne u lokalnoj konfiguraciji. |
| Authority i issuer | `https://login.microsoftonline.com/{ENTRA_TENANT_ID}/v2.0` |
| Redirect URI | `https://infrastruktura.sos-decijasela.rs/auth/entra/callback`, bez završne kose crte |
| Uspešan login | `https://infrastruktura.sos-decijasela.rs/dashboard.php`; postojeći uslov obavezne promene privremene lozinke vodi na `/password_change_required.php`. |
| Logout | Lokalni `/logout.php` sa postojećim CSRF tokenom; povratak na `/login.php`, odnosno `/login.php?session=expired` posle isteka. |
| Microsoft logout | Nema Entra end-session poziva, front-channel handlera ili `post_logout_redirect_uri` vrednosti. Microsoft sesija ostaje aktivna, kao i ranije. |

Entra je **server-side confidential Web client, OpenID Connect authorization code flow sa PKCE S256 i client secret-om**, `response_mode=query`. Nije MSAL Browser/SPA, implicit/hybrid ili client-credentials flow. Biblioteka `jumbojett/openid-connect-php` je 1.0.2; implicit flow je isključen.

Traže se samo `openid`, `profile`, `email`. Aplikacija ne poziva Microsoft Graph i ne koristi `User.Read`, offline access ili application permissions. Validira potpis, RS256, issuer, audience prema client ID-u, nonce, exp/iat, tenant `tid` i korisnikov `oid`. Email i `preferred_username` služe prvom povezivanju; sledeće prijave koriste `oid` i tenant. `name`, `groups` i Entra `roles` ne upravljaju autorizacijom. Role, organizaciona jedinica i administratorska prava dolaze iz lokalne baze.

Postojeći projekat nema APP_ENV prekidač ni dotenv loader; nisu dodavani neaktivni `APP_ENV`/`APP_URL` parametri. Okruženja se razdvajaju postojećim `config.php`, server environment-om i secrets fajlom:

- **Production:** gore navedeni callback, produkcijska baza, Secure=true i HTTPS.
- **Staging:** eksplicitni sopstveni `ENTRA_REDIRECT_URI` i staging baza; HTTPS/Secure ostaju uključeni.
- **Development:** odvojena lokalna baza; Secure=false samo za lokalni HTTP. Entra ostaje neaktivan bez kredencijala; za Entra razvoj potreban je odgovarajući registrovani HTTPS callback, bez popuštanja validatora.

`entra_setting()` čita environment pre konstante. Zbog toga ispravljen source default **ne može nadjačati staru server environment vrednost**. HOME secrets fajl takođe može već definisati konstantu. Ako oba domena dele cPanel HOME i isti secrets fajl, podesiti callback environment po domenu ili koristiti odvojene hosting naloge. Ne prebacivati zajednički callback na produkciju dok ga staging i dalje koristi.

## D. MICROSOFT ENTRA ID — MOJI RUČNI KORACI

### Šta mora ručno da se promeni u Microsoft Entra admin centru

Otvoriti **Microsoft Entra admin center → Identity → Applications → App registrations** i izabrati aplikaciju čiji Application (client) ID odgovara serverskom `ENTRA_CLIENT_ID`. Naziv registracije i stvarni GUID-ovi ne mogu se utvrditi iz dostavljenog source-a. **Potrebno ručno proveriti u Entra ID.** Sledeće navedene „postojeće vrednosti” potiču iz source-a; trenutno stanje portala nije pročitano.

1. **LOKACIJA:** App registrations → [aplikacija] → Authentication → Web → Redirect URIs.
   **POSTOJEĆA VREDNOST:** source fallback je bio `https://infrastage.sos-mig.com/auth/entra/callback`; dokumentacija/primer su pogrešno navodili `https://infrastrage.sos-mig.com/auth/entra/callback`. Stvarno registrovane URI-je proveriti u portalu.
   **NOVA VREDNOST:** `https://infrastruktura.sos-decijasela.rs/auth/entra/callback`.
   **AKCIJA:** **Add**, zatim Save; postojeći ispravan staging URI **Keep dok staging radi**.
   **NAPOMENA:** Pun URI, HTTPS, mala/velika slova putanje i odsustvo završne kose crte moraju odgovarati efektivnom `ENTRA_REDIRECT_URI`. Ovo je Web platforma iako koristi PKCE. Ne registrovati domen bez callback putanje niti `/auth_entra_callback.php`. Uklanjanje staging URI-ja prekida staging prijavu. Pogrešno napisani URI ukloniti samo posle provere da ga nijedno drugo okruženje ne koristi. [Microsoft: redirect URI pravila](https://learn.microsoft.com/en-us/entra/identity-platform/reply-url).

2. **LOKACIJA:** App registrations → [aplikacija] → Authentication → Single-page application.
   **POSTOJEĆA VREDNOST:** SPA tok ne postoji u source-u; portal nepoznat.
   **NOVA VREDNOST:** Nema nove SPA registracije.
   **AKCIJA:** **Keep**; ne dodavati produkcijski callback pod SPA.
   **NAPOMENA:** Postojeće SPA stavke eventualno pripadaju drugim klijentima. Ne brisati ih zbog ove migracije. PKCE je podržan i u serverskom authorization-code toku. [Microsoft: authorization code](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow).

3. **LOKACIJA:** App registrations → [aplikacija] → Authentication → Front-channel logout URL.
   **POSTOJEĆA VREDNOST:** Nije definisana niti podržana aplikacionim handlerom; stanje portala nepoznato.
   **NOVA VREDNOST:** Za ovaj sistem nije potrebna.
   **AKCIJA:** **Keep** ako je prazno; ako je popunjeno, proveriti namenu pre promene.
   **NAPOMENA:** Ne unositi `/logout.php`: on za aktivnu sesiju zahteva CSRF, a frame politika je DENY. Automatsko Microsoft front-channel odjavljivanje nije postojeća funkcionalnost. [Microsoft: OIDC odjava](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#single-sign-out).

4. **LOKACIJA:** Aplikaciona konfiguracija odjave, odnosno Authentication → Web registrovane povratne adrese ako bi klijent slao post-logout parametar.
   **POSTOJEĆA VREDNOST:** `post_logout_redirect_uri` / `POST_LOGOUT_REDIRECT_URI` nisu definisani niti se šalju.
   **NOVA VREDNOST:** Nema novog Entra parametra; lokalni povratak je `https://infrastruktura.sos-decijasela.rs/login.php`.
   **AKCIJA:** **Keep** postojeći lokalni logout tok.
   **NAPOMENA:** Nema posebnog obaveznog portal polja „Post logout redirect URI” za ovaj postojeći tok. Ne dodavati novu odjavu ili URI samo zbog promene domena.

5. **LOKACIJA:** App registrations → [aplikacija] → Authentication → Supported account types / Implicit grant and hybrid flows.
   **POSTOJEĆA VREDNOST:** Kod zahteva jedan konkretan tenant; dokumentacija navodi single tenant. Biblioteka ima implicit flow=false.
   **NOVA VREDNOST:** Zadržati **Accounts in this organizational directory only** za namensku registraciju i postojeći tenant; ovom toku implicit access/ID token opcije nisu potrebne.
   **AKCIJA:** **Keep**; proveriti da odgovara source-u.
   **NAPOMENA:** Ako portal koristi širi tenant model ili registraciju dele drugi klijenti, ne menjati ga naslepo; aplikacija i dalje prihvata samo konfigurisani tenant. **Potrebno ručno proveriti u Entra ID.**

6. **LOKACIJA:** App registrations → [aplikacija] → API permissions.
   **POSTOJEĆA VREDNOST:** Zahtevani scope-ovi u kodu su `openid`, `profile`, `email`; portal dozvole nepoznate.
   **NOVA VREDNOST:** Isti scope-ovi, bez novih Graph/API privilegija.
   **AKCIJA:** **Keep**; proveriti consent prema politici organizacije.
   **NAPOMENA:** Ne dodavati `User.Read`, directory/group ili mail dozvole zbog domena; ne brisati postojeće dozvole drugih klijenata. [Microsoft: OIDC scope-ovi](https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc).

7. **LOKACIJA:** App registrations → [aplikacija] → Certificates & secrets → Client secrets.
   **POSTOJEĆA VREDNOST:** Aplikacija očekuje `ENTRA_CLIENT_SECRET`; vrednost i datum isteka nisu dostupni u projektu.
   **NOVA VREDNOST:** Važeći secret **Value** iste App Registration u production environment-u; nije Secret ID.
   **AKCIJA:** **Keep** važeći secret iste registracije ili **Add** zaseban produkcijski secret po organizacionoj politici. Promena domena sama ne zahteva novi secret.
   **NAPOMENA:** **Potrebno proveriti u Entra ID → Certificates & secrets.** Datum isteka nije moguće pouzdano navesti. Ne uklanjati staging secret dok ga staging koristi. Certificate autentifikacija nije implementirana u aplikacionom kodu.

8. **LOKACIJA:** App registrations → [aplikacija] → Expose an API → Application ID URI / Scopes / Authorized client applications.
   **POSTOJEĆA VREDNOST:** Nema aplikacionog exposed API-ja, custom scope-a ili audience vezanog za domen u source-u. Portal nepoznat.
   **NOVA VREDNOST:** Nema promene.
   **AKCIJA:** **Keep**.
   **NAPOMENA:** Ako portal ipak sadrži Application ID URI sa staging domenom, evidentirati ga i prvo utvrditi klijente, access-token audience i consent zavisnosti. Ne prepisivati automatski; ovaj sistem validira ID-token audience prema client ID-u. **Potrebno ručno proveriti u Entra ID.**

9. **LOKACIJA:** App registrations → [aplikacija] → Token configuration.
   **POSTOJEĆA VREDNOST:** Kod koristi `oid`, `tid`, `email`, `preferred_username`, uz protokolarne `iss`, `aud`, `nonce`, `exp`, `iat` i uslovno `azp`.
   **NOVA VREDNOST:** Ista claim konfiguracija.
   **AKCIJA:** **Keep**.
   **NAPOMENA:** Promena domena ne menja te claim-ove ako registracija i tenant ostaju isti. `groups`, Entra `roles` i `name` nisu osnova autorizacije. Email/UPN mora omogućiti postojeće prvo povezivanje sa lokalnim nalogom.

10. **LOKACIJA:** App registrations → [aplikacija] → App roles.
    **POSTOJEĆA VREDNOST:** Aplikacija ne mapira Entra role value/group ID/App Registration object ID na poslovne role.
    **NOVA VREDNOST:** Bez promene.
    **AKCIJA:** **Keep**.
    **NAPOMENA:** Sačuvati lokalne `users`, `user_roles`, Entra `oid`/tenant veze i Enterprise Application. Kreiranje druge registracije/tenant-a nije deo promene domena.

11. **LOKACIJA:** Enterprise applications → [service principal iste aplikacije] → Properties / Users and groups / Single sign-on; zatim odgovarajuće Conditional Access politike i Sign-in logs.
    **POSTOJEĆA VREDNOST:** Dodeljeni korisnici/grupe, assignment requirement, SSO launch linkovi i Conditional Access nisu dostupni u source-u.
    **NOVA VREDNOST:** Zadržati postojeće pristupe i politike. Ako postoji korisnički Home page/launch URL koji vodi na stari sistem, nakon provere vlasništva promeniti ga na `https://infrastruktura.sos-decijasela.rs/` ili postojeću login putanju `/login.php`.
    **AKCIJA:** **Keep** pristupe; **Change** samo potvrđeni launch URL vezan za ovaj sistem.
    **NAPOMENA:** Ne konvertovati OIDC u SAML. Proveriti da aplikacija dozvoljava sign-in, da su test korisnici dodeljeni ako je assignment obavezan, da Conditional Access/MFA funkcionišu i da Sign-in logs nemaju AADSTS50011 ili tenant/consent greške. **Potrebno ručno proveriti u Entra ID.**

12. **LOKACIJA:** Entra Authentication → Web i aplikacioni hosting, CORS/Allowed origins.
    **POSTOJEĆA VREDNOST:** Server razmenjuje authorization code; browser ne poziva token endpoint preko SPA CORS-a.
    **NOVA VREDNOST:** Produkcijski Web callback iz koraka 1; aplikacioni origin `https://infrastruktura.sos-decijasela.rs`.
    **AKCIJA:** **Add** Web callback; ostalo **Keep**.
    **NAPOMENA:** Ne postoji dodatna generička „Allowed origins” lista koju ovde treba popuniti u App Registration. Ne uvoditi SPA platformu radi CORS-a.

### Entra validacija na produkciji — još nije izvršena

- [ ] Produkcijski Redirect URI dodat pod Web u očekivanoj App Registration.
- [ ] Efektivni `ENTRA_REDIRECT_URI` odgovara portalu 1:1, uključujući HTTPS, callback path i odsustvo završne kose crte.
- [ ] Client ID i Tenant ID potvrđeni prema očekivanoj registraciji i direktorijumu.
- [ ] Authority je `https://login.microsoftonline.com/{ENTRA_TENANT_ID}/v2.0`.
- [ ] Važeći client secret postoji u production environment-u; provereno isticanje. Certificate: nije primenljivo za implementirani tok.
- [ ] ID-token audience odgovara Client ID-u; required scopes su `openid profile email`.
- [ ] Posle prijave sačuvani su lokalne role, administracija i organizaciona jedinica. Entra App Roles: ne koriste se.
- [ ] Lokalni logout radi; povratak je na produkcijski login. Microsoft post-logout tok: ne koristi se.
- [ ] Nema povratka na staging domen, AADSTS50011, login CORS ili state/nonce/session grešaka.

## E. Ostali ručni koraci pre produkcije

1. Napraviti i proveriti backup fajlova, baze i persistent upload podataka. Odrediti trenutak finalne sinhronizacije podataka; ne pustiti dva okruženja da nenamerno rade nad istom bazom.
2. DNS A/AAAA/CNAME produkcijskog domena usmeriti na stvarni hosting. U cPanel Domains/virtual host podesiti tačan hostname i document root za ovu aplikaciju. Server IP nije poznat iz projekta.
3. U hosting SSL/TLS/AutoSSL postaviti sertifikat koji važi za produkcijski hostname i proveriti ceo chain. **Staging SSL-manager/DCV fajlove ne prenositi kao produkcijske.** Sertifikati nisu generisani niti menjani ovim radom.
4. Uključiti cPanel **Force HTTPS Redirect** za produkcijski domen nakon instalacije sertifikata. Ako TLS završava na reverse proxy-ju, HTTP→HTTPS sprovesti na spoljašnjem proxy-ju; ne dodavati backend pravilo koje bi napravilo redirect loop. Proveriti preusmeravanje i PHP i statičkih URL-ova sa očuvanjem putanje/upita. U projektu nema postojećeg globalnog HTTPS redirect pravila; Secure cookie i HSTS nisu njegova zamena.
5. Ako postoji proxy, proslediti originalni `Host`, kontrolisani `X-Forwarded-Proto` i `X-Forwarded-For`; u `TRUSTED_PROXY_IPS` upisati samo stvarne neposredne proxy IP adrese. Ne verovati proizvoljnom forwarded zaglavlju. Proveriti backend HTTPS detekciju i HSTS bez petlje.
6. Sačuvati postojeće poslovne/UI/session opcije `config.php`; na produkcijskom serveru promeniti samo `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` na potvrđenu produkcijsku bazu. Ove DB vrednosti su postojeće PHP konstante — postavljanje DB environment promenljivih samo po sebi ih ne menja. Ne kopirati lokalni staging `config.php` kao gotovu produkcijsku konfiguraciju i ne zameniti ga primerom bez prenosa postojećih opcija.
7. Postaviti četiri Entra promenljive iz odeljka C. Proveriti efektivne vrednosti i u web PHP procesu, ne samo u CLI. Za secrets fajl izvan web root-a koristiti dozvole `0600` i odgovarajućeg vlasnika. Proveriti HOME fallback i odvojene staging/production callback vrednosti kada oba domena dele nalog.
8. Pre objave potvrditi da produkcijska baza ima postojeću očekivanu šemu, uključujući Entra kolone/indekse, `login_attempts`, notifikacije, priloge i role. Za promenu domena ne pokretati CREATE/ALTER ni istorijske rollback/migration skripte. Ne importovati dostavljeni istorijski dump preko aktivnih produkcijskih podataka bez dogovorene migracije podataka.
9. Objaviti aplikaciju i postojeći `vendor` prema `composer.lock`. **`.productionignore` je lista izuzeća, a ne automatski deployment program.** U alatu za pakovanje/upload eksplicitno primeniti listu i pregledati paket. Izostaviti SQL dumpove, logove, lokalni config, QA, dokumentaciju, `create_admin.php`, vendor ZIP, Git, `.env` i SSL-manager/stare `.well-known` fajlove. Preneti root/app `.htaccess`; persistent `uploads` preneti/sinhronizovati zasebno uz postojeća zaštitna `.htaccess` pravila i PHP write dozvole.
10. Proveriti Apache `mod_rewrite`, `mod_headers`, dozvolu za `.htaccess` direktive i `/auth/entra/callback` routing. Globalna nginx/Apache/firewall/CI konfiguracija nije u projektu i nije menjana. Omogućiti izlazni HTTPS ka Microsoft discovery/JWKS/token endpointima, DNS i sinhronizovan sat; bazu izložiti samo potrebnim serverima.
11. Proveriti PHP preduslove u odgovarajućem cPanel PHP profilu: cURL, JSON, mbstring, PDO MySQL, fileinfo, OpenSSL, DOM i ZIP/Phar podršku; GD za postojeću obradu fotografija. `upload_max_filesize=50M`, `post_max_size=64M`, `max_file_uploads=10`, `session.gc_maxlifetime=900` prema postojećem `.user.ini.example`; proxy limit ne sme biti manji od očekivanog zahteva. Isključiti javni `display_errors`; log čuvati privatno.
12. Privremeno na server preneti `qa_production_config.php` i iz privatnog terminala u document root-u pokrenuti `php qa_production_config.php`; ne ostavljati QA fajlove u konačnom paketu. Provera je read-only i vraća exit 1 za neusaglašenu konfiguraciju. Ne dokazuje Entra portal, validnost secreta, vezu sa bazom ili web environment. Zatim izvršiti checklist ispod sa namenskim test nalogom.
13. Posle uspešne validacije uraditi prelazak i nadgledati login, callback i server logove. Za rollback vratiti prethodne aplikativne fajlove/konfiguraciju i saobraćaj prema planu, uz očuvanje novih poslovnih podataka. Staging callback zadržati dok postoji potreba za povratkom. Ne menjati korisničke Entra veze ili šemu radi rollback-a domena.

## F. Test checklist i stvarni rezultati

### Izvršene lokalne provere

- **PASS:** PHP 8.3.33 syntax/lint svih 415 PHP fajlova, uključujući vendor i novi preflight. Privremeni PHP preuzet sa zvaničnog PHP izvora i SHA-256 proveren; nije dodat aplikaciji.
- **PASS:** JavaScript syntax svih 19 fajlova (17 QA i dva aplikaciona).
- **PASS:** devet postojećih PHP runtime testova, ukupno 158 pojedinačnih PASS provera, bez grešaka.
- **PASS:** 17 dodatnih runtime tvrdnji za produkcijski callback/povratak, odvojeni environment override, relativne linkove, odbijanje spoljnog notification linka, HTTPS/trusted proxy detekciju, OIDC klijent i state validaciju. Test identiteti su sintetički; nije pozivan Microsoft.
- **PASS:** stvarni PHP bootstrap sa namerno postavljenim nasleđenim cookie domenom daje host-only, Secure, HttpOnly, SameSite=Lax cookie.
- **PASS:** devet lokalnih HTTP provera: login, tri statička asset-a, nevažeći callback, anonimni logout i zaštita ticket/participant/download endpointa. Nema staging referenci u tim odgovorima/preusmerenjima; cookie i CSP potvrđeni. Ovo nije autentifikovan poslovni test i lokalni PHP server ne izvršava Apache `.htaccess`.
- **PASS:** `composer validate --no-check-publish` i `composer check-platform-reqs --no-dev`; bez izmene zavisnosti. Validator upozorava na nedostajuću license oznaku i namerno fiksiranu OIDC verziju; te stavke nisu menjane.
- **OČEKIVANI FAIL lokalnog produkcijskog preflight-a:** 19 provera prolazi, dve ne prolaze — Entra kredencijali nisu dostupni i naziv DB/korisnika pokazuje staging. Skripta ne proverava validnost lozinki preko mreže.
- **POSTOJEĆI JS QA PROBLEMI:** istih 17 skripti pokrenuto pre i posle izmena, sa potpuno istim rezultatima. Dvanaest se zaustavlja zbog nedostajućih istorijskih SQL fajlova; pet ima po jednu zastarelu proveru CSS/cache verzije (uz 115 uspešnih provera). Među blokiranima je `qa_entra_auth.js`, jer nema `upgrade_entra_auth.sql` / `rollback_entra_auth.sql`. SQL fajlovi nisu izmišljeni, a CSS nije menjan radi testova.
- **Nije primenljivo:** odvojeni frontend build, TypeScript typecheck ili npm build pipeline; takva konfiguracija ne postoji.

### Obavezni testovi na produkciji

Sledeće stavke ostaju **nije moguće testirati u dostupnom okruženju**: nema pristupa produkcijskom hostingu/Entra portalu, podešene baze i test korisničkog naloga. Lokalni PASS iznad nije zamena.

- [ ] Login preko Microsoft Entra ID.
- [ ] Logout aktivnog korisnika.
- [ ] Povratak na produkcijski domen posle logina.
- [ ] Povratak na produkcijski domen posle logout-a.
- [ ] Kreiranje tiketa.
- [ ] Otvaranje tiketa.
- [ ] Promena statusa.
- [ ] Dodavanje komentara.
- [ ] Dodavanje učesnika.
- [ ] Upload fajlova/fotografija.
- [ ] Download fajlova sa ispravnom autorizacijom.
- [ ] Notifikacioni linkovi; email slanje nije implementirano i nije primenljivo.
- [ ] Korisnički profil.
- [ ] Administracija i postojeće lokalne role.
- [ ] Autentifikovani API pozivi.
- [ ] CORS u produkcijskom browser-u.
- [ ] Session/cookies, istek i više tabova na produkciji.
- [ ] Mobile prikaz.
- [ ] Direktno otvaranje URL-a nakon refresh-a i Apache auth rewrite.
- [ ] HTTP → HTTPS za PHP i statičke fajlove.
- [ ] Nema mixed-content grešaka.
- [ ] Nema zahteva ka staging domenu u Network panelu.
- [ ] Nema AADSTS50011 Redirect URI mismatch greške.
- [ ] Nedozvoljen javni pristup konfiguraciji, SQL/log/QA fajlovima, vendor arhivu i upload direktorijumima.

## G. Rizici / napomene

- **CRITICAL — preduslovi objave:** bez registrovanog produkcijskog Web callback-a, odgovarajućih efektivnih Entra vrednosti i potvrđene produkcijske baze ne odobravati puštanje u rad. Source default nije dokaz da je portal ili server podešen.
- **HIGH — lokalni pristupni i poslovni podaci:** dostavljeni `config.php` sadrži stvarnu DB lozinku; SQL dump sadrži poslovne/korisničke podatke i password hash-eve, a log interne podatke. Vrednosti nisu navedene u izveštaju. Ne objavljivati/commitovati ove fajlove. Proveriti prethodnu izloženost i rotirati kredencijale ako su deljeni neovlašćeno; dodati `.gitignore` ne čisti postojeću istoriju. U ovoj radnoj kopiji nema `.git` direktorijuma pa istorija nije mogla biti proverena.
- **HIGH — deljeni cPanel secrets:** zajednički HOME/environment može zadržati staging callback ili prekinuti staging nakon zamene. Vrednosti moraju biti odvojene po okruženju; staging Redirect URI ne uklanjati dok staging radi.
- **HIGH — HTTPS/server:** sertifikat, DNS, redirect, Apache pravila, reverse proxy i server ekstenzije nisu potvrđeni na produkciji. `.htaccess` zahteva odgovarajuće Apache module/AllowOverride. PHP test server nije Apache test.
- **HIGH — stari runtime log:** postoje istorijske greške za nedostajući `finfo` i DB tabelu, kao i upozorenja za nedefinisane `email`, `status`, `priority`, `q` ključeve. Nije utvrđeno da se još javljaju u trenutnom produkcijskom okruženju. Proveriti fileinfo i šemu pre objave; poslovni kod nije menjan u ovoj migraciji.
- **MEDIUM — nepotpuna istorijska QA dokumentacija:** više referenced migration/rollback fajlova ne postoji u dostavljenoj kopiji. Ne koristiti stara uputstva za naslepo menjanje šeme. Postojeći dump već sadrži Entra veze i indekse.
- **MEDIUM — odjava:** lokalna odjava ne završava Microsoft sesiju, pa sledeća Microsoft prijava može iskoristiti postojeći SSO. To je zadržano ponašanje; full Entra logout bi bio zasebna funkcionalna izmena.
- **LOW — QA cache očekivanja / Composer metadata:** postojeće zastarele CSS provere i Composer upozorenja nisu posledica promene domena i nisu automatski popravljani.

Zaključak za administratora: source je pripremljen za produkcijski domen, ali konačna spremnost za puštanje u rad zavisi od izvršenja koraka D/E i produkcijskih testova u F.
