wiki:ApplicationDevelopment

Version 7 (modified by 223075, 2 weeks ago) ( diff )

--

Развој на апликација (App Development)

На оваа страна докажуваме дека апликацијата ги користи DB можностите (погледи, транскации, складирани функции, индекси) преку HTTP рути, со JWT автентикација.

Важни рути

Login (JWT)

POST /api/login Body: {"type":"user","email":"...","password":"..."}

Враќа token (JWT) кој потоа се праќа во Authorization: Bearer <token>.

Транскација + складирана функција

POST /api/book-class

Body (со JWT или со userId во body): {"classId":7} или {"userId":12,"classId":7}

Користи BEGIN/COMMIT и SELECT book_class($1,$2); тригери блокираат преполнување и одржуваат seats_available.

Пример одговори:

{ "success": true, "code": "OK" }

или:

{ "success": false, "code": "CLASS_FULL" }

Извештаи од погледи (Views)

GET /api/reports/top-spenders → vw_user_spend GET /api/reports/class-utilization → vw_class_utilization GET /api/reports/training-pop-monthly → vw_training_pop_monthly

EXPLAIN/ANALYZE преку апликацијата

GET /api/debug/explain-events GET /api/debug/explain-class-join (Со мал сет, planner понекогаш избира Seq Scan; за принуден Index Scan може да се види на страната „Напредни извештаи“.)

Докази

1) JWT Login → добиваме токен

Команда:

curl -X POST http://localhost:5000/api/login
 ^
-H "Content-Type: application/json" ^
-d "{"type":"user","email":"newstudent@gmail.com
","password":"Newstudent!15"}"

Одговор:

{ "success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....(скратено)...",
"role": "user",
"userId": "17"
}

2) Транскација + функција: book_class (со JWT)

Команда:

curl -X POST http://localhost:5000/api/book-class
 ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer eyJhbGciOi...X3E" ^
-d "{"classId":7}"

Одговор:

{ "success": true, "code": "OK" }

3) book_class без JWT (одбиено од апликацијата)

Команда:

curl -X POST http://localhost:5000/api/book-class
 ^
-H "Content-Type: application/json" ^
-d "{"classId":7}"

Одговор:

{ "success": false, "error": "Missing user identity" }

(Овие два излези заедно докажуваат: JWT заштита на критична рута и транскација + тригери во базата.)

4) Views → извештаи

GET /api/reports/top-spenders:

[{"user_id":"8","username":"mikiYoga","email":"miki@example.com
","spend_packages":"45.00","spend_merch":"12.00","total_spend":"57.00","spend_rank":"1"},
{"user_id":"13","username":"bojan","email":"bojan@example.com
","spend_packages":"0","spend_merch":"30.00","total_spend":"30.00","spend_rank":"2"},
{"user_id":"12","username":"ana","email":"ana@example.com
","spend_packages":"25.00","spend_merch":"0","total_spend":"25.00","spend_rank":"3"},
{"user_id":"9","username":"davidG","email":"david@example.com
","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
{"user_id":"10","username":"proba1","email":"proba1@gmail.com
","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
{"user_id":"14","username":"ciro","email":"ciro@example.com
","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
{"user_id":"16","username":"proba2","email":"proba2@gmail.com
","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
{"user_id":"17","username":"newstudent","email":"newstudent@gmail.com
","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"}]

GET /api/reports/class-utilization:

[{"class_id":"5","date":"2025-06-09T22:00:00.000Z","start_time":"08:00:00","end_time":"09:00:00","location":"Studio A","capacity":20,"booked":"1","utilization_pct":"5.00","instructor_id":"5","daily_rank":"2"},
{"class_id":"6","date":"2025-06-09T22:00:00.000Z","start_time":"09:30:00","end_time":"10:30:00","location":"Studio B","capacity":15","booked":"1","utilization_pct":"6.67","instructor_id":"6","daily_rank":"1"},
{"class_id":"7","date":"2025-09-26T22:00:00.000Z","start_time":"18:00:00","end_time":"19:00:00","location":"Studio A","capacity":2,"booked":"2","utilization_pct":"100.00","instructor_id":"7","daily_rank":"1"}]

GET /api/reports/training-pop-monthly:

[{"training_id":"7","training_name":"Vinyasa","month":"2025-08-31T22:00:00.000Z","num_bookings":"2","rank_in_month":"1"},
{"training_id":"8","training_name":"Yin","month":"2025-08-31T22:00:00.000Z","num_bookings":"2","rank_in_month":"1"},
{"training_id":"6","training_name":"Hatha Basics","month":"2025-05-31T22:00:00.000Z","num_bookings":"1","rank_in_month":"1"},
{"training_id":"5","training_name":"Vinyasa Flow","month":"2025-05-31T22:00:00.000Z","num_bookings":"1","rank_in_month":"1"}]

5) EXPLAIN/ANALYZE преку апликацијата

GET /api/debug/explain-events (мал сет - Seq Scan) Извадок:

[{"Plan":{"Node Type":"Limit", "Plans":[
{"Node Type":"Sort", "Plans":[
{"Node Type":"Seq Scan", "Relation Name":"Event", "Filter":"(date >= CURRENT_DATE)"}
]}
]},"Planning Time":0.701,"Execution Time":0.108}]

GET /api/debug/explain-class-join (мал сет - Seq Scans) Извадок:

[{"Plan":{"Node Type":"Limit","Plans":[
{"Node Type":"Sort","Plans":[
{"Node Type":"Aggregate","Plans":[
{"Node Type":"Sort","Plans":[
{"Node Type":"Nested Loop","Plans":[
{"Node Type":"Seq Scan","Relation Name":"Class","Filter":"(date >= CURRENT_DATE)"},
{"Node Type":"Seq Scan","Relation Name":"User_Booked_Class"}
] } ] } ] } ] } ] },"Planning Time":1.033,"Execution Time":0.303}]

Забелешка: Овде planner не мора секогаш да избере индекс поради мал број редови. На страната „Напредни извештаи“ има EXPLAIN (FORCED) JSON каде се гледа "Index Scan" со имињата idx_event_date_time, idx_class_date_time, idx_ubc_class.

Како се тестира

Стартуваме backend:

cd backend
node index.js

Примери за тест:

Login (JWT):

curl -X POST http://localhost:5000/api/login
 ^
-H "Content-Type: application/json" ^
-d "{"type":"user","email":"newstudent@gmail.com
","password":"Newstudent!15"}"

Book class (со JWT):

curl -X POST http://localhost:5000/api/book-class
 ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer <JWT>" ^
-d "{"classId":7}"

Book class (без JWT):

curl -X POST http://localhost:5000/api/book-class
 ^
-H "Content-Type: application/json" ^
-d "{"classId":7}"

Reports (во прелистувач):

http://localhost:5000/api/reports/top-spenders

http://localhost:5000/api/reports/class-utilization

http://localhost:5000/api/reports/training-pop-monthly

EXPLAIN (во прелистувач):

http://localhost:5000/api/debug/explain-events

http://localhost:5000/api/debug/explain-class-join

Note: See TracWiki for help on using the wiki.