Skip to content

Repository files navigation

🏛️ Portal eUprava

Digitalni portal za elektronske administrativne usluge — građani podnose i prate zahteve online, službenici ih obrađuju, a administratori upravljaju institucijama, servisima i korisnicima.


Laravel PHP Sanctum React Mantine React Router Recharts Axios SQLite DomPDF Docker Render


🔗 Live demo

🌐 Live aplikacija: https://portal-euprava.onrender.com — ✅ deploy-ovano na Render-u (jedan Docker servis: React + Laravel).

Aplikacija se pušta u rad i jednim klikom (dugme ispod) — Render pročita render.yaml, build-uje Docker image, izvrši migrate --seed i pokrene servis.

Napomena: na besplatnom planu servis „zaspi” posle neaktivnosti, pa prvo učitavanje može potrajati ~30–60 s dok se ne probudi.

Deploy to Render

Deploy-ovana instanca dolazi sa već popunjenim (seed-ovanim) podacima: 3 institucije, 3 servisa sa dinamičkim poljima, 13 korisnika (3 fiksna demo naloga + 10 Faker korisnika) i ~22 demo zahteva raspoređenih po svim statusima. Možete se odmah prijaviti pomoću demo naloga.


📑 Sadržaj


📖 O projektu

Portal eUprava je web aplikacija koja digitalizuje osnovne administrativne usluge i omogućava građanima da podnose zahteve online, prate njihov status, preuzimaju dokumenta u PDF formatu i razmenjuju napomene vezane za obradu. Aplikacija je organizovana po ulogama korisnika (CITIZEN, OFFICER, ADMIN) i koristi jasan tok zahteva:

DRAFT  →  SUBMITTED  →  IN_REVIEW  →  APPROVED / REJECTED

Sistem se oslanja na koncept Servisa (npr. izdavanje izvoda, uverenja, zakazivanje termina) koji pripadaju određenim Institucijama. Svaki servis ima dinamički definisana polja (Service Fields) koja određuju šta korisnik unosi u formu. Uneseni podaci čuvaju se u koloni form_data kao JSON mapa (ključ → vrednost), što omogućava univerzalnu podršku za različite usluge bez tvrdog kodiranja svake forme.


🧰 Tehnologije

Projekat je podeljen na dva nezavisna sloja — REST API (Laravel) i Single Page Application (React) — koja u produkciji isporučuje jedan Docker kontejner.

Backend — portal-euprava/

Tehnologija Verzija Uloga u projektu
PHP ^8.2 Runtime jezik
Laravel ^12.0 Web framework, routing, Eloquent ORM, migracije, seederi
Laravel Sanctum ^4.2 Token autentifikacija (Bearer / personal access tokens)
barryvdh/laravel-dompdf ^3.1 Generisanje PDF dokumenata zahteva
Laravel Tinker ^2.10 REPL za rad sa modelima
SQLite Lagana relaciona baza (datoteka, bez servera)
fakerphp/faker ^1.23 Generisanje realističnih (američkih) demo podataka u seed-u
PHPUnit / Pest ^11.5 Testovi
Laravel Pint ^1.24 Code style (PSR-12)

Korišćeni Laravel koncepti: Eloquent modeli sa relacijama (app/Models), API Resources za serializaciju (app/Http/Resources), Form Request validacija u kontrolerima, slojevite migracije (kreiranje tabela → FK → default vrednosti → nullable ograničenja) i Database Factories + Seeders.

Frontend — portal-euprava-frontend/

Tehnologija Verzija Uloga u projektu
React ^19.2 UI biblioteka (SPA)
Create React App (react-scripts) 5.0.1 Build alat / dev server
Mantine (@mantine/core, dates, dropzone, hooks, notifications) ^8.3 UI komponente, forme, modali, notifikacije, upload
React Router DOM ^7.11 Klijentsko rutiranje i zaštićene rute po ulozi
Axios ^1.13 HTTP klijent sa interceptor-om za Bearer token
Recharts ^3.6 Grafikoni na stranicama statistike
Tabler Icons ^3.36 Ikonice
Day.js ^1.11 Rad sa datumima

Infrastruktura

Tehnologija Uloga
Docker (multi-stage build) Build React-a + pakovanje Laravel aplikacije u jedan image
Render Hosting (Docker web service, render.yaml Blueprint)
Git / GitHub Verzionisanje

🏗️ Arhitektura

U produkciji Laravel servira i React build i /api rute sa istog porekla (origin), pa nema CORS-a niti odvojenog frontend hostinga. CRA build se kopira u public/, a sve rute koje nisu /api/* vraćaju index.html (routes/web.php) kako bi React Router preuzeo rutiranje.

flowchart LR
    subgraph Browser["🌐 Browser (SPA)"]
        UI["React 19 + Mantine 8<br/>React Router 7"]
        AX["Axios klijent<br/>baseURL = /api<br/>Bearer token interceptor"]
        UI --> AX
    end

    subgraph Server["🐳 Docker kontejner (Render)"]
        direction TB
        WEB["routes/web.php<br/>servira index.html (SPA)"]
        API["routes/api.php<br/>REST kontroleri"]
        SANCTUM["Laravel Sanctum<br/>auth:sanctum"]
        ELO["Eloquent modeli<br/>+ API Resources"]
        PDF["DomPDF<br/>PDF izveštaji"]
        API --> SANCTUM --> ELO
        API --> PDF
    end

    DB[("🗄️ SQLite<br/>database.sqlite")]

    AX -->|"HTTPS /api/*"| API
    UI -.->|"navigacija /home-*, /admin/*"| WEB
    ELO --> DB

    classDef store fill:#003B57,stroke:#012,color:#fff;
    class DB store;
Loading

Tok autentifikacije: POST /api/auth/login vraća Sanctum token → frontend ga čuva u sessionStorage → Axios interceptor dodaje Authorization: Bearer <token> na svaki naredni zahtev (src/api/api.js).


🗂️ Model podataka (ER dijagram)

Model ima 5 entiteta. Relacije su jednostavne i hijerarhijske (bez ukrštanja linija): institucija sadrži servise, servis ima polja i zahteve, a korisnik figurira u zahtevu u dve uloge — kao podnosilac (user_id) i kao službenik koji obrađuje (processed_by).

erDiagram
    INSTITUTIONS ||--o{ SERVICES : "ima"
    SERVICES ||--o{ SERVICE_FIELDS : "definiše"
    SERVICES ||--o{ SERVICE_REQUESTS : "generiše"
    USERS ||--o{ SERVICE_REQUESTS : "podnosi (citizen)"
    USERS ||--o{ SERVICE_REQUESTS : "obrađuje (officer)"

    USERS {
        bigint   id PK
        string   name
        string   email UK
        string   password
        date     date_of_birth
        string   jmbg UK "13 cifara"
        string   role "CITIZEN | OFFICER | ADMIN"
        datetime created_at
    }

    INSTITUTIONS {
        bigint   id PK
        string   name
        string   city
        string   address
        string   email
        datetime created_at
    }

    SERVICES {
        bigint   id PK
        bigint   institution_id FK
        string   name UK
        text     description
        decimal  fee "iznos takse"
        boolean  requires_attachment
        string   status "ACTIVE | INACTIVE"
        datetime created_at
    }

    SERVICE_FIELDS {
        bigint   id PK
        bigint   service_id FK
        string   key "deo jedinstvenog para (service_id, key)"
        string   label
        string   data_type "STRING|NUMBER|DATE|BOOLEAN|SELECT|FILE"
        boolean  is_required
        json     options
        json     validation_rules
        int      sort_order
    }

    SERVICE_REQUESTS {
        bigint   id PK
        bigint   user_id FK "podnosilac (citizen)"
        bigint   service_id FK
        bigint   processed_by FK "službenik, nullable"
        string   status "DRAFT|SUBMITTED|IN_REVIEW|APPROVED|REJECTED"
        text     citizen_note
        text     officer_note
        string   attachment
        json     form_data "popunjena polja (key -> value)"
        string   payment_status "NOT_REQUIRED|NOT_PAID|PAID"
        datetime payment_date
    }
Loading

Entiteti ukratko

  • users — nalozi sa ulogom (role). Jedan korisnik može da podnese više zahteva i, ako je službenik, da obradi više zahteva. Polja jmbg i email su jedinstvena.
  • institutions — institucije koje nude servise (npr. Matična služba Grada Beograda).
  • services — usluge koje pripadaju instituciji; nose taksu (fee), zastavicu da li traže prilog i status. Brisanje institucije kaskadno briše servise.
  • service_fieldsdefinicija dinamičke forme za servis (koja polja, kog tipa, validacija, redosled). Jedinstven par (service_id, key).
  • service_requests — zahtev građana za servis; čuva popunjenu formu u form_data, status u toku obrade, napomene, prilog i status plaćanja.

📌 Sve relacije su definisane sa odgovarajućim FK ograničenjima u ...add_foreign_keys.php: cascadeOnDelete za vlasničke veze, a nullOnDelete za processed_by (brisanje službenika ne briše zahtev).


🔄 Tok obrade zahteva (state machine)

stateDiagram-v2
    direction LR
    [*] --> DRAFT: građanin kreira zahtev
    DRAFT --> SUBMITTED: pošalji na obradu
    SUBMITTED --> IN_REVIEW: službenik preuzme (assign)
    IN_REVIEW --> APPROVED: odobreno
    IN_REVIEW --> REJECTED: odbijeno
    APPROVED --> [*]
    REJECTED --> [*]
Loading
Status Značenje
DRAFT Zahtev je kreiran, ali još nije poslat.
SUBMITTED Poslat; čeka da ga neki službenik preuzme (inbox).
IN_REVIEW Dodeljen službeniku i u obradi.
APPROVED Odobren (može zahtevati plaćanje takse → payment_status = PAID).
REJECTED Odbijen (npr. nedostaje dokumentacija).

💡 Ključni koncept: dinamička forma (form_data)

Za razliku od fiksnih formi, Portal eUprava koristi Service Fields kao izvor istine o tome koja se polja prikazuju i unose. Kada građanin popuni formu, vrednosti se čuvaju u form_data kao mapirani JSON objekat. Time:

  • novi servis i nova polja se dodaju bez izmene frontenda,
  • prikaz detalja zahteva uvek može univerzalno da prikaže sva polja (vidi FormDataPretty.jsx),
  • aplikacija ostaje skalabilna i lako proširiva na veliki broj usluga.

Primer (form_data za servis eIzvod iz matične knjige rođenih):

{
  "delivery_method": "EMAIL",
  "purpose": "za potrebe zaposlenja",
  "contact_phone": "0641234567"
}

👥 Korisničke uloge i slučajevi korišćenja

👤 CITIZEN (Građanin)

  • Registracija i prijava (token autentifikacija); registracija je rezervisana za građane.
  • Pregled servisa i detalja (opis, iznos takse).
  • Pokretanje zahteva — bira servis i popunjava dinamička polja (Service Fields).
  • DRAFT → SUBMITTED — kreira nacrt pa ga šalje na obradu.
  • Upload priloga (opciono, ako servis to traži).
  • Praćenje zahteva — lista, filtriranje, promene statusa.
  • Preuzimanje PDF dokumenta zahteva.

🧑‍💼 OFFICER (Službenik)

  • Inbox — zahtevi u statusu SUBMITTED koji nisu dodeljeni.
  • Preuzimanje (assign) zahteva → postaje zadužen.
  • Dodeljeni meni — lista zahteva koje obrađuje.
  • Promena statusa (IN_REVIEW → APPROVED/REJECTED) uz napomenu.
  • PDF i Statistika (broj zahteva po statusu, metrike).

🛠️ ADMIN (Administrator)

  • CRUD institucija i pregled njihovih servisa.
  • CRUD servisa (taksa, status, povezivanje sa institucijom).
  • CRUD polja servisa (Service Fields — key, label, tip, obavezno, opcije, redosled).
  • Upravljanje korisnicima — promena uloge, brisanje (uz zaštitu sopstvenog naloga).
  • Globalna statistika — agregati, distribucija po statusima, trendovi.

🔌 API reference

Bazni prefiks: /api. Sve rute osim registracije i prijave zahtevaju Authorization: Bearer <token> (Laravel Sanctum). Definicije: routes/api.php.

Auth

Metoda Putanja Opis
POST /api/auth/register Registracija građanina (vraća token)
POST /api/auth/login Prijava (vraća token + korisnika)
GET /api/auth/me Trenutno prijavljeni korisnik
POST /api/auth/logout Odjava (poništava token)

Servisi i polja

Metoda Putanja Opis
GET /api/services Lista servisa
GET /api/services/{id} Detalji servisa
POST / PUT / DELETE /api/services{/id} CRUD (ADMIN)
GET /api/services/{id}/fields Polja servisa
POST /api/services/{id}/fields Dodaj polje (ADMIN)
PUT / DELETE /api/service-fields/{id} Izmena/brisanje polja (ADMIN)

Institucije

Metoda Putanja Opis
GET/POST/PUT/DELETE /api/institutions{/id} apiResource CRUD (ADMIN)

Zahtevi (Service Requests)

Metoda Putanja Opis
GET /api/service-requests Lista (filtrirana po ulozi)
GET /api/service-requests/{id} Detalji zahteva
POST /api/service-requests Kreiraj (DRAFT)
PUT /api/service-requests/{id} Izmena
PATCH /api/service-requests/{id}/submit DRAFT → SUBMITTED
PATCH /api/service-requests/{id}/assign Preuzmi (officer)
PATCH /api/service-requests/{id}/status Promena statusa
PATCH /api/service-requests/{id}/payment Ažuriranje plaćanja
DELETE /api/service-requests/{id} Brisanje
GET /api/service-requests/{id}/pdf PDF izveštaj (DomPDF)

Korisnici, statistika, upload

Metoda Putanja Opis
GET /api/users{/id} Lista / detalji (ADMIN)
PATCH /api/users/{id}/role Promena uloge (ADMIN)
DELETE /api/users/{id} Brisanje korisnika (ADMIN)
GET /api/stats Metrike (zavise od uloge)
POST /api/uploads/filebin Upload priloga

🔑 Demo nalozi

Seed kreira fiksni demo nalog za svaku ulogu (lozinke su iste i na lokalu i na deploy-u), da bi se aplikacija mogla isprobati iz svakog ugla:

Uloga Ime Email Lozinka
👤 CITIZEN Ksenija Cvjetan ksenija@euprava.test ksenija123
🧑‍💼 OFFICER Michael Johnson officer@euprava.test officer123
🛠️ ADMIN Admin Portal admin123@euprava.test admin123

Seeder je osmišljen kao demo cele aplikacije:

  • Ksenija (građanin) ima po jedan zahtev u svakom statusu (DRAFT, SUBMITTED, IN_REVIEW, APPROVED, REJECTED) — vide se svi prikazi i ceo tok obrade.
  • Michael Johnson (službenik) ima popunjen inbox (nedodeljeni SUBMITTED zahtevi) i listu „Assigned to me” (već obrađeni zahtevi).
  • Admin vidi sve institucije, servise, korisnike i agregiranu statistiku.

Jedino ručno definisano lično ime u seed-u je Ksenija Cvjetan. Ostali korisnici (uključujući službenika Michael Johnson i dodatne građane) dobijaju američka imena preko Faker-a (APP_FAKER_LOCALE=en_US), vidi UserSeeder.php, ServiceRequestSeeder.php i UserFactory.php. Lozinka dodatnih (Faker) naloga je password.


💻 Lokalno pokretanje

Preduslovi: PHP 8.2+, Composer, Node 18+ (preporučeno 22), npm.

1) Backend (Laravel API → http://127.0.0.1:8000)

cd portal-euprava
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate:fresh --seed     # kreira SQLite bazu i puni demo podatke
php artisan serve

2) Frontend (React → http://localhost:3000)

cd portal-euprava-frontend
npm install
npm start

CRA proxy (http://127.0.0.1:8000) prosleđuje /api pozive backendu tokom razvoja, pa ne morate da podešavate CORS.

(Opciono) Cela aplikacija u jednom Docker kontejneru

docker build -t portal-euprava .
docker run -p 8080:10000 portal-euprava   # otvori http://localhost:8080

🚀 Deployment

Aplikacija se deploy-uje na Render kao jedan Docker web service. Repozitorijum sadrži sve potrebno:

  • Dockerfile — multi-stage build: (1) node:22 build React-a → (2) php:8.2 instalira zavisnosti i kopira React build u public/.
  • docker-entrypoint.sh — pri pokretanju generiše APP_KEY, kreira SQLite bazu i izvršava migrate:fresh --seed (zato deploy uvek dolazi sa popunjenim demo podacima), pa pokreće server na $PORT.
  • render.yaml — Render Blueprint (plan free, env varijable, health check /).

Koraci

Najbrže (jedan klik): kliknite na dugme Deploy to Render iznad — Render automatski pročita render.yaml i ponudi deploy ovog repozitorijuma.

Ručno:

  1. Push koda na GitHub.
  2. Na dashboard.render.comNew + → Blueprint → poveži ovaj repozitorijum.
  3. Render pročita render.yaml, build-uje Docker image i pokrene servis.
  4. Po završetku, javni URL dodajte u sekciju Live demo.

ℹ️ Na besplatnom planu fajl sistem je efemeran, pa se demo podaci ponovo seed-uju pri svakom pokretanju — što je idealno za prezentacionu instancu.


📁 Struktura projekta

EUPRAVA/
├── Dockerfile                  # multi-stage: React build + Laravel runtime
├── docker-entrypoint.sh        # migrate --seed + start servera
├── render.yaml                 # Render Blueprint
├── README.md
│
├── portal-euprava/             # 🐘 Backend (Laravel 12 REST API)
│   ├── app/
│   │   ├── Http/Controllers/   # Auth, Service, ServiceRequest, Institution, Stats, PDF...
│   │   ├── Http/Resources/     # API Resources (serializacija)
│   │   └── Models/             # User, Institution, Service, ServiceField, ServiceRequest
│   ├── database/
│   │   ├── migrations/         # slojevite migracije (tabele → FK → defaults → nullable)
│   │   ├── factories/          # Faker fabrike
│   │   └── seeders/            # demo podaci (Ksenija Cvjetan + američka imena)
│   └── routes/{api.php,web.php} # REST rute + SPA fallback
│
└── portal-euprava-frontend/    # ⚛️ Frontend (React 19 + Mantine 8)
    └── src/
        ├── api/api.js          # Axios inst, Bearer interceptor
        ├── pages/              # ekrani po ulozi (Citizen / Officer / Admin)
        ├── components/         # ProtectedRoute, FormDataPretty, Slider
        ├── hooks/              # useLatestSerbianNews
        └── utils/auth.js       # session/role helperi

Napravljeno sa ❤️ koristeći Laravel i React.

About

Portal eUprava — digitalni portal za elektronske administrativne usluge. Laravel 12 REST API + React 19 (Mantine) SPA, Sanctum auth, dinamicke forme (form_data), PDF izvestaji, Docker deploy na Render.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages