Changes between Initial Version and Version 1 of BuildInstructions


Ignore:
Timestamp:
08/21/26 08:34:30 (5 days ago)
Author:
231175
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • BuildInstructions

    v1 v1  
     1= BuildInstructions =
     2
     3[[PageOutline(2-3, Содржина, inline)]]
     4
     5Оваа страница ја опишува развојната околина, начинот на градење и начинот на тестирање на проектот '''Shifter Web App''' (гранка `main`).
     6
     7----
     8
     9== Опис на развојната околина ==
     10
     11=== Архитектура на проектот ===
     12
     13Shifter е веб-апликација составена од два независни дела кои се пуштаат одделно:
     14
     15|| '''Компонента''' || '''Технологија''' || '''Директориум''' || '''Порта (локално)''' ||
     16|| Backend (REST API) || Java 17, Spring Boot 3.5.3, Spring Security (JWT + OAuth2), Spring Data JPA / Hibernate, Maven || `backend/` || `8080` ||
     17|| Frontend (SPA) || React 19, TypeScript 5.8, Vite 6, Tailwind CSS 4, react-i18next || `frontend/` || `5173` ||
     18|| База на податоци || PostgreSQL || – || `5432` ||
     19
     20=== Задолжителен софтвер ===
     21
     22|| '''Софтвер''' || '''Верзија''' || '''Зошто е потребен''' || '''Проверка''' ||
     23|| Git || било која || Преземање на изворниот код || {{{git --version}}} ||
     24|| JDK (Java Development Kit) || '''17''' (Temurin / OpenJDK / Oracle) || Компајлирање и извршување на backend-от; `pom.xml` е фиксиран на `java.version=17` || {{{java -version}}} ||
     25|| Maven || '''не се инсталира одделно''' || Проектот има Maven Wrapper (`mvnw` / `mvnw.cmd`) кој сам ја презема Maven 3.9.9 || {{{./mvnw -v}}} ||
     26|| PostgreSQL || 14 или понова (драјвер 42.7.7) || База на податоци на апликацијата || {{{psql --version}}} ||
     27|| Node.js || 20.19+ или 22.12+ (LTS) || Градење и пуштање на frontend-от (Vite 6 / React 19) || {{{node -v}}} ||
     28|| npm || 10 или понова (доаѓа со Node.js) || Инсталација на frontend зависности || {{{npm -v}}} ||
     29|| Веб-прелистувач || Chrome, Firefox, Edge или Safari (актуелна верзија) || Тестирање на апликацијата || – ||
     30
     31=== Надворешни сервиси и клучеви ===
     32
     33Backend-от се поврзува на неколку надворешни сервиси. Клучевите се внесуваат преку променливи на околината, види `Конфигурација на backend`.
     34
     35|| '''Сервис''' || '''За што служи''' || '''Потребен за подигање на апликацијата?''' ||
     36|| PostgreSQL || Главна база на податоци || '''Да''' – без неа апликацијата не се подига ||
     37|| ZeptoMail (Zoho) || Емаил за верификација, потврди за состаноци, контакт-форма || '''Да''' – клучот мора да постои; мора да е и '''валиден''' за регистрација преку емаил ||
     38|| Google Cloud – OAuth 2.0 Client ID || Најава со Google („Sign in with Google“) || '''Да''' – вредностите мора да постојат ||
     39|| Google Cloud – Service Account + Calendar ID || Читање слободни термини од календарот на експертот || '''Да''' – види `Google Service Account`, инаку подигањето паѓа со грешка ||
     40|| Amazon S3 || Прикачување и чување фајлови (слики, материјали) || '''Да''' – вредностите мора да постојат ||
     41|| Zoom (Server-to-Server OAuth App) || Автоматско креирање Zoom состанок при закажување консултација || '''Да''' – вредностите мора да постојат ||
     42
     43'''ВАЖНО:''' повеќето променливи во `application.properties` немаат стандардна вредност (пр. `${AWS_S3_REGION}`, `${JWT_CONFIG_SECRET}`, `${ZOOM_CLIENT_ID}`). Ако некоја од нив недостасува, Spring нема да успее да ги создаде бавовите и апликацијата '''воопшто нема да се стартува'''. За локален развој е сосема во ред да се стават '''лажни (dummy) вредности''' за сервисите што нема да ги тестирате – важно е клучевите да '''постојат'''.
     44
     45----
     46
     47== Инструкции за градење ==
     48
     49=== Преземање на изворниот код ===
     50
     51{{{#!sh
     52git clone <URL-на-репозиториумот> Shifter-Web-App
     53cd Shifter-Web-App
     54git checkout main
     55}}}
     56
     57Структура на проектот:
     58
     59{{{
     60Shifter-Web-App/
     61├── backend/        # Spring Boot апликација (Maven)
     62├── frontend/       # React + Vite апликација (npm)
     63└── modeling/       # модели и дијаграми
     64}}}
     65
     66=== Подготовка на базата на податоци ===
     67
     68Инсталирајте и стартувајте PostgreSQL, па креирајте корисник и празна база:
     69
     70{{{#!sql
     71CREATE USER shifter WITH PASSWORD 'shifter';
     72CREATE DATABASE shifter OWNER shifter;
     73GRANT ALL PRIVILEGES ON DATABASE shifter TO shifter;
     74}}}
     75
     76'''Не е потребно рачно да се извршуваат SQL скрипти.''' На гранката `main` вредноста е `spring.jpa.hibernate.ddl-auto=update`, што значи дека Hibernate автоматски ги креира и ажурира сите табели при првото стартување на backend-от. Во продукцискиот профил `prod` вредноста е `validate`, т.е. шемата мора веќе да постои.
     77
     78=== Конфигурација на backend ===
     79
     80Backend-от при стартување чита `.env` датотека (библиотека `dotenv-java`). Датотеката '''не е''' во Git (наведена е во `.gitignore`), па мора рачно да се создаде на патека `backend/.env`:
     81
     82{{{
     83# ===== Основно =====
     84SPRING_PROFILES_ACTIVE=default
     85PORT=8080
     86BACKEND_URL=http://localhost:8080
     87FRONTEND_URL=http://localhost:5173
     88ALLOWED_ORIGINS=http://localhost:5173
     89
     90# ===== База на податоци =====
     91SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/shifter
     92SPRING_DATASOURCE_USERNAME=shifter
     93SPRING_DATASOURCE_PASSWORD=shifter
     94DDL_AUTO=update
     95SHOW_SQL=true
     96
     97# ===== JWT (мин. 32 знаци, HS256) =====
     98JWT_CONFIG_SECRET=promeni-go-ovoj-taen-kluc-min-32-znaci!!
     99JWT_EXPIRATION=86400000
     100JWT_REFRESH_EXPIRATION=604800000
     101COOKIE_SECURE=false
     102COOKIE_SAME_SITE=Lax
     103
     104# ===== Amazon S3 =====
     105AWS_S3_REGION=eu-central-1
     106AWS_S3_BUCKET_NAME=shifter-bucket
     107AWS_S3_ACCESS_KEY=xxxxxxxxxxxx
     108AWS_S3_SECRET_KEY=xxxxxxxxxxxx
     109
     110# ===== Емаил (ZeptoMail) =====
     111ZEPTOMAIL_API_KEY=xxxxxxxxxxxx
     112
     113# ===== Google OAuth2 =====
     114GOOGLE_CLIENT_ID=xxxxxxxxxxxx.apps.googleusercontent.com
     115GOOGLE_CLIENT_SECRET=xxxxxxxxxxxx
     116
     117# ===== Google Calendar =====
     118GOOGLE_EXPERT_CALENDAR_ID=expert@shift-er.com
     119# алтернатива на service-account.json (Base64 од JSON фајлот):
     120# GOOGLE_CALENDAR_SERVICE_ACCOUNT_JSON_BASE64=xxxxxxxxxxxx
     121
     122# ===== Zoom (Server-to-Server OAuth) =====
     123ZOOM_ACCOUNT_ID=xxxxxxxxxxxx
     124ZOOM_CLIENT_ID=xxxxxxxxxxxx
     125ZOOM_CLIENT_SECRET=xxxxxxxxxxxx
     126
     127# ===== Логирање =====
     128LOG_LEVEL=INFO
     129APP_LOG_LEVEL=DEBUG
     130}}}
     131
     132=== Google Service Account ===
     133
     134Класата `GoogleCalendarService` се иницијализира '''при подигање на апликацијата'''. Ако не најде credentials, целата апликација паѓа со `GoogleCalendarException: Service account JSON not found in classpath or environment`.
     135
     136Затоа мора да обезбедите '''еден''' од следниве два начина:
     137
     138* Поставете ја JSON-датотеката на Service Account-от на патека `backend/src/main/resources/service-account.json` (датотеката е во `.gitignore` и не се комитира).
     139* '''или''' поставете ја променливата `GOOGLE_CALENDAR_SERVICE_ACCOUNT_JSON_BASE64` со Base64-кодирана содржина на истата датотека:
     140
     141{{{#!sh
     142base64 -i service-account.json | tr -d '\n'
     143}}}
     144
     145Service Account-от треба да има пристап (Google Calendar API scope `https://www.googleapis.com/auth/calendar`) до календарот наведен во `GOOGLE_EXPERT_CALENDAR_ID`.
     146
     147=== Google OAuth2 redirect URI ===
     148
     149Во Google Cloud Console, во OAuth 2.0 Client ID, додајте го овој '''Authorized redirect URI''':
     150
     151{{{
     152http://localhost:8080/login/oauth2/code/google
     153}}}
     154
     155=== Компајлирање и стартување на backend ===
     156
     157Сите команди се извршуваат од директориумот `backend/`.
     158
     159{{{#!sh
     160cd backend
     161
     162# Компајлирање и градење (Linux / macOS)
     163./mvnw clean package -DskipTests
     164
     165# Компајлирање и градење (Windows)
     166mvnw.cmd clean package -DskipTests
     167}}}
     168
     169Резултат: извршна JAR-датотека `backend/target/shifter.jar`.
     170
     171{{{#!sh
     172# Стартување во развоен режим
     173./mvnw spring-boot:run
     174
     175# или стартување на изградената JAR-датотека
     176java -jar target/shifter.jar
     177}}}
     178
     179Проверка дека backend-от работи:
     180
     181{{{#!sh
     182curl http://localhost:8080/actuator/health
     183# очекуван одговор: {"status":"UP"}
     184}}}
     185
     186=== Конфигурација и градење на frontend ===
     187
     188Сите команди се извршуваат од директориумот `frontend/`.
     189
     190Прво креирајте `frontend/.env` – frontend-от бара '''една''' променлива:
     191
     192{{{
     193VITE_BACKEND_URL=http://localhost:8080
     194}}}
     195
     196Потоа:
     197
     198{{{#!sh
     199cd frontend
     200npm install        # инсталација на зависностите
     201npm run dev        # развоен режим → http://localhost:5173
     202
     203npm run build      # TypeScript проверка + Vite build → frontend/dist/
     204npm run preview    # локален преглед на изградената верзија
     205npm run lint       # ESLint проверка
     206}}}
     207
     208Содржината од `frontend/dist/` се качува на статички хостинг; проектот содржи `vercel.json` со SPA rewrite правило за Vercel.
     209
     210=== Цел редослед на пуштање ===
     211
     212{{{#!sh
     213# 1. Стартувај PostgreSQL и создај база `shifter`
     214
     215# 2. Backend
     216cd backend
     217# создај .env и service-account.json
     218./mvnw spring-boot:run
     219# → http://localhost:8080
     220
     221# 3. Frontend (во нов терминал)
     222cd frontend
     223# создај .env со VITE_BACKEND_URL
     224npm install
     225npm run dev
     226# → http://localhost:5173
     227}}}
     228
     229=== Продукциско градење и пуштање ===
     230
     231* Backend: поставете `SPRING_PROFILES_ACTIVE=prod`. Профилот `prod` автоматски вклучува `spring.jpa.hibernate.ddl-auto=validate` (шемата мора да постои однапред), `cookie.secure=true` и `cookie.same-site=Strict` (задолжителен HTTPS), намалено логирање и сокриени stack trace-ови.
     232* Поставете ги `BACKEND_URL`, `FRONTEND_URL` и `ALLOWED_ORIGINS` на вистинските домени; `ALLOWED_ORIGINS` прифаќа повеќе вредности одделени со запирка.
     233* Додајте го продукцискиот redirect URI во Google Cloud Console: `https://<backend-domen>/login/oauth2/code/google`.
     234* Frontend: `npm run build` и качете го `frontend/dist/`; поставете `VITE_BACKEND_URL` на продукцискиот backend домен.
     235
     236=== Чести проблеми при градење ===
     237
     238|| '''Проблем''' || '''Причина''' || '''Решение''' ||
     239|| `Could not resolve placeholder 'AWS_S3_REGION'` (или слична променлива) || Недостасува променлива во `.env` || Додајте ја во `backend/.env`; за нетестирани сервиси ставете dummy вредност ||
     240|| `GoogleCalendarException: Service account JSON not found` || Недостасува `service-account.json` || Види `Google Service Account` ||
     241|| `Connection refused` кон PostgreSQL || Базата не работи или е погрешен URL || Проверете дали PostgreSQL е стартуван и дали `SPRING_DATASOURCE_URL` е точен ||
     242|| CORS грешка во конзолата на прелистувачот || `ALLOWED_ORIGINS` не ја содржи адресата на frontend-от || Додајте `http://localhost:5173` во `ALLOWED_ORIGINS` ||
     243|| Мрежни грешки во frontend-от / празни податоци || Недостасува `frontend/.env` || Создајте `.env` со `VITE_BACKEND_URL=http://localhost:8080` и рестартирајте `npm run dev` ||
     244|| `WeakKeyException` при најава || `JWT_CONFIG_SECRET` е пократок од 32 знаци || Поставете подолг таен клуч ||
     245|| Грешки „cannot find symbol“ за getter/setter методи во IDE || Исклучено annotation processing (Lombok/MapStruct) || Вклучете `Enable annotation processing` во IDE-то ||
     246|| Vite не се подига || Стара верзија на Node.js || Инсталирајте Node.js 20.19+ или 22.12+ ||
     247
     248----
     249
     250== Инструкции за тестирање ==
     251
     252Shifter е '''веб-апликација''', па се тестира преку веб-прелистувач.
     253
     254=== Каде се пушта апликацијата ===
     255
     256|| '''Што''' || '''Адреса''' ||
     257|| Frontend (корисничкиот дел) || http://localhost:5173 ||
     258|| Автоматско пренасочување со јазичен префикс || http://localhost:5173/en или http://localhost:5173/mk ||
     259|| Backend REST API || http://localhost:8080/api ||
     260|| Health check || http://localhost:8080/actuator/health ||
     261|| Најава со Google || http://localhost:8080/oauth2/authorization/google ||
     262
     263=== Кориснички имиња и лозинки ===
     264
     265Апликацијата '''нема однапред креирани (seed) корисници'''. При првото стартување базата е празна и '''сметката се креира преку формата за регистрација'''.
     266
     267|| '''Тип на пристап''' || '''Корисничко име''' || '''Лозинка''' ||
     268|| Апликација (регистриран корисник) || вашата емаил адреса, пр. `test@example.com` || лозинка што ја бирате при регистрација, пр. `Test123!` ||
     269|| Апликација (Google најава) || вашата Google сметка || управувана од Google (нема лозинка во апликацијата) ||
     270|| PostgreSQL база || `shifter` (или `postgres`) || онаа што сте ја поставиле, пр. `shifter` ||
     271
     272'''Правила за лозинката при регистрација''' – се проверуваат во формата:
     273
     274* најмалку една '''голема буква''' (A–Z)
     275* најмалку една '''цифра''' (0–9)
     276* најмалку еден '''специјален знак''' (`!@#$%^&*(),.?":{}|<>`)
     277* двете полиња за лозинка мора да се совпаѓаат
     278
     279Пример за валидна тест-сметка: `test@example.com` / `Test123!`
     280
     281'''Совет за тестирање без валиден емаил-клуч:''' регистрацијата преку емаил испраќа порака за верификација преку ZeptoMail и, ако клучот не е валиден, целата регистрација паѓа бидејќи трансакцијата се враќа назад. Ако немате валиден `ZEPTOMAIL_API_KEY`, тестирајте со '''Најава преку Google''' – тој тек не испраќа емаил и корисникот автоматски се означува како верификуван.
     282
     283=== Мини-водич низ главните елементи ===
     284
     285Долниот водич ги поминува главните екрани по редослед на нормално користење.
     286
     287'''Чекор 1: Почетна страница'''
     288
     289* Отворете http://localhost:5173 – автоматски ќе бидете пренасочени на `/en` (или `/mk`).
     290* '''Navbar''' (горе): линкови до `Курсеви`, `Менторство`, `Консалтинг`, `Академии`, `За Нас`, `Контакт`, `Бесплатна Сесија` и копче `Најави се / Регистрирај се`.
     291* '''Јазичен прекинувач''' (долу десно, знаменце): менува меѓу '''EN''' и '''MK'''; јазикот се одразува во URL-то (`/en/...` ↔ `/mk/...`).
     292* '''Footer''': контакт информации и линкови до социјални мрежи.
     293
     294'''Чекор 2: Регистрација'''
     295
     296* Кликнете `Најави се / Регистрирај се` → `Регистрирај се` (`/en/register`).
     297* Внесете емаил, лозинка и потврда на лозинката – види `Кориснички имиња и лозинки`.
     298* Алтернативно кликнете '''„Continue with Google“''' за најава преку Google сметка.
     299* По успешна регистрација, апликацијата автоматски ве носи на страницата за персонализација (`/welcome`).
     300
     301'''Чекор 3: Верификација и персонализација (`/welcome`)'''
     302
     303* Страницата го чита `token` параметарот од URL-то и ја верифицира вашата емаил адреса.
     304* Пополнете ги полињата: '''Целосно име''', '''Работно место''' и '''Големина на компанијата''' (Фриленсер, Микро, Мала, Средна, Среден пазар, Голема компанија, Друго).
     305* Кликнете `Започни да користиш Shifter`. Профилот сега е комплетен и сите заштитени страници стануваат достапни.
     306* Ако верификацијата не успее, постои копче `Испрати нов емаил` за нов линк за верификација.
     307
     308'''Чекор 4: Најава (`/login`)'''
     309
     310* Внесете емаил и лозинка, или користете `Continue with Google`.
     311* По најава access token се чува во меморија, а refresh token во `HttpOnly` колаче; сесијата се обновува автоматски при истек (401 → `/api/auth/refresh`).
     312
     313'''Чекор 5: Профил (`/profile`)'''
     314
     315* '''Мој Профил''' – измена на име, работна позиција и големина на компанијата; се зачувува со `Зачувај Промени`.
     316* '''Интереси''' и '''Стекнати Вештини''' – кликнете на секцијата за да отворите модал со теми и изберете барем една.
     317* '''Одјави се''' – ја затвора сесијата.
     318
     319'''Чекор 6: Бесплатна сесија (`/free-consultation`)'''
     320
     321Ова е најкомплексниот тек и ги користи Google Calendar, Zoom и емаил интеграциите:
     322
     323* Апликацијата ги повлекува '''слободните термини''' на експертот од Google Calendar – работни денови, 08:00–16:30, во вашата временска зона.
     324* Изберете '''датум''' и '''час'''.
     325* Пополнете ги полињата: основни информации, за компанијата, предизвици и дополнителни информации.
     326* Кликнете на копчето за закажување. Во позадина се креира настан во Google Calendar, се отвора Zoom состанок и се испраќаат емаил потврди до вас и до експертот.
     327* Секој корисник има право на '''една''' бесплатна консултација – при обид за втора се појавува порака дека веќе е искористена.
     328
     329'''Чекор 7: Контакт (`/contact`)'''
     330
     331* Полињата '''Име''' и '''Е-пошта''' се автоматски пополнети од вашиот профил.
     332* Внесете '''Причина за контакт''' и '''Порака''', па кликнете `Испрати`.
     333* Пораката се испраќа до експертот преку ZeptoMail; се појавува потврда на екранот.
     334
     335'''Чекор 8: Информативни страници'''
     336
     337* '''За Нас''' (`/about`) – мисија, вредности и претставување на тимот. Јавно достапна.
     338* '''Менторство''' (`/mentoring`), '''Консалтинг''' (`/consulting`), '''Академии''' (`/academies`) – опис на услугите. '''Достапни само за најавени корисници.'''
     339* '''Курсеви''' (`/courses`) – моментално прикажува страница „Дигитални Курсеви – Наскоро“; модулот за курсеви и учење е подготвен во backend-от, но е привремено исклучен во frontend-от.
     340
     341=== Автоматски тестови ===
     342
     343{{{#!sh
     344cd backend
     345./mvnw test
     346}}}