Changes between Version 4 and Version 5 of ApplicationDevelopment


Ignore:
Timestamp:
09/30/25 23:12:33 (2 weeks ago)
Author:
223075
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • ApplicationDevelopment

    v4 v5  
    11= Развој на апликација (App Development) =
    22
    3 Овде докажуваме дека апликацијата ги користи DB можностите (погледи, транскации, складирани функции, индекси) преку HTTP рути.
     3На оваа страна докажуваме дека апликацијата ги користи DB можностите (погледи, транскации, складирани функции, индекси) преку HTTP рути, со JWT автентикација.
    44
    55== Важни рути ==
    66
    7 === Транскација + функција ===
    8 **POST** `/api/book-class`
    9 - Body (JWT или userId во body): `{"classId":7}` или `{"userId":12,"classId":7}`
    10 - Користи `BEGIN/COMMIT` и `SELECT book_class($1,$2)`.
    11 
    12 Пример очекуван одговор:
     7=== Login (JWT) ===
     8POST /api/login
     9Body: {"type":"user","email":"...","password":"..."}
     10
     11Враќа token (JWT) кој потоа се праќа во Authorization: Bearer <token>.
     12
     13=== Транскација + складирана функција ===
     14POST /api/book-class
     15
     16Body (со JWT или со userId во body): {"classId":7} или {"userId":12,"classId":7}
     17
     18Користи BEGIN/COMMIT и SELECT book_class($1,$2); тригери блокираат преполнување и одржуваат seats_available.
     19
     20Пример одговори:
    1321{{{
    1422{ "success": true, "code": "OK" }
     
    2028
    2129=== Извештаи од погледи (Views) ===
    22 **GET** `/api/reports/top-spenders`  → vw_user_spend 
    23 **GET** `/api/reports/class-utilization` → vw_class_utilization 
    24 **GET** `/api/reports/training-pop-monthly` → vw_training_pop_monthly
    25 
     30GET /api/reports/top-spenders → vw_user_spend
     31GET /api/reports/class-utilization → vw_class_utilization
     32GET /api/reports/training-pop-monthly → vw_training_pop_monthly
    2633
    2734=== EXPLAIN/ANALYZE преку апликацијата ===
    28 **GET** `/api/debug/explain-events` 
    29 **GET** `/api/debug/explain-class-join`
    30 
     35GET /api/debug/explain-events
     36GET /api/debug/explain-class-join
     37(Со мал сет, planner понекогаш избира Seq Scan; за принуден Index Scan може да се види на страната „Напредни извештаи“.)
     38
     39== Докази ==
     40
     41=== 1) JWT Login → добиваме токен ===
     42Команда:
     43{{{
     44curl -X POST http://localhost:5000/api/login
     45 ^
     46-H "Content-Type: application/json" ^
     47-d "{"type":"user","email":"newstudent@gmail.com
     48","password":"Newstudent!15"}"
     49}}}
     50Одговор:
     51{{{
     52{ "success": true,
     53"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....(скратено)...",
     54"role": "user",
     55"userId": "17"
     56}
     57}}}
     58
     59=== 2) Транскација + функција: book_class (со JWT) ===
     60Команда:
     61{{{
     62curl -X POST http://localhost:5000/api/book-class
     63 ^
     64-H "Content-Type: application/json" ^
     65-H "Authorization: Bearer eyJhbGciOi...X3E" ^
     66-d "{"classId":7}"
     67}}}
     68Одговор:
     69{{{
     70{ "success": true, "code": "OK" }
     71}}}
     72
     73=== 3) book_class без JWT (одбиено од апликацијата) ===
     74Команда:
     75{{{
     76curl -X POST http://localhost:5000/api/book-class
     77 ^
     78-H "Content-Type: application/json" ^
     79-d "{"classId":7}"
     80}}}
     81Одговор:
     82{{{
     83{ "success": false, "error": "Missing user identity" }
     84}}}
     85
     86(Овие два излези заедно докажуваат: JWT заштита на критична рута и транскација + тригери во базата.)
     87
     88=== 4) Views → извештаи ===
     89
     90GET /api/reports/top-spenders:
     91{{{
     92[{"user_id":"8","username":"mikiYoga","email":"miki@example.com
     93","spend_packages":"45.00","spend_merch":"12.00","total_spend":"57.00","spend_rank":"1"},
     94{"user_id":"13","username":"bojan","email":"bojan@example.com
     95","spend_packages":"0","spend_merch":"30.00","total_spend":"30.00","spend_rank":"2"},
     96{"user_id":"12","username":"ana","email":"ana@example.com
     97","spend_packages":"25.00","spend_merch":"0","total_spend":"25.00","spend_rank":"3"},
     98{"user_id":"9","username":"davidG","email":"david@example.com
     99","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
     100{"user_id":"10","username":"proba1","email":"proba1@gmail.com
     101","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
     102{"user_id":"14","username":"ciro","email":"ciro@example.com
     103","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
     104{"user_id":"16","username":"proba2","email":"proba2@gmail.com
     105","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"},
     106{"user_id":"17","username":"newstudent","email":"newstudent@gmail.com
     107","spend_packages":"0","spend_merch":"0","total_spend":"0","spend_rank":"4"}]
     108}}}
     109
     110GET /api/reports/class-utilization:
     111{{{
     112[{"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"},
     113{"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"},
     114{"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"}]
     115}}}
     116
     117GET /api/reports/training-pop-monthly:
     118{{{
     119[{"training_id":"7","training_name":"Vinyasa","month":"2025-08-31T22:00:00.000Z","num_bookings":"2","rank_in_month":"1"},
     120{"training_id":"8","training_name":"Yin","month":"2025-08-31T22:00:00.000Z","num_bookings":"2","rank_in_month":"1"},
     121{"training_id":"6","training_name":"Hatha Basics","month":"2025-05-31T22:00:00.000Z","num_bookings":"1","rank_in_month":"1"},
     122{"training_id":"5","training_name":"Vinyasa Flow","month":"2025-05-31T22:00:00.000Z","num_bookings":"1","rank_in_month":"1"}]
     123}}}
     124
     125=== 5) EXPLAIN/ANALYZE преку апликацијата ===
     126
     127GET /api/debug/explain-events (мал сет → Seq Scan во оваа снимка)
     128Извадок:
     129{{{
     130[{"Plan":{"Node Type":"Limit", "Plans":[
     131{"Node Type":"Sort", "Plans":[
     132{"Node Type":"Seq Scan", "Relation Name":"Event", "Filter":"(date >= CURRENT_DATE)"}
     133]}
     134]},"Planning Time":0.701,"Execution Time":0.108}]
     135}}}
     136
     137GET /api/debug/explain-class-join (мал сет → Seq Scans во оваа снимка)
     138Извадок:
     139{{{
     140[{"Plan":{"Node Type":"Limit","Plans":[
     141{"Node Type":"Sort","Plans":[
     142{"Node Type":"Aggregate","Plans":[
     143{"Node Type":"Sort","Plans":[
     144{"Node Type":"Nested Loop","Plans":[
     145{"Node Type":"Seq Scan","Relation Name":"Class","Filter":"(date >= CURRENT_DATE)"},
     146{"Node Type":"Seq Scan","Relation Name":"User_Booked_Class"}
     147] } ] } ] } ] } ] },"Planning Time":1.033,"Execution Time":0.303}]
     148}}}
     149
     150Забелешка: Овде planner не мора секогаш да избере индекс поради мал број редови. На страната „Напредни извештаи“ имаме EXPLAIN (FORCED) JSON каде се гледа "Index Scan" со имињата idx_event_date_time, idx_class_date_time, idx_ubc_class.
    31151
    32152== Како тестираме ==
    33 1. Стартуваме backend:
     153
     154Стартуваме backend:
    34155{{{
    35156cd backend
    36157node index.js
    37158}}}
    38 2. Потоа отвораме во прелистувач / Postman:
    39 - http://localhost:5000/api/reports/top-spenders
    40 - http://localhost:5000/api/debug/explain-events
    41 - POST http://localhost:5000/api/book-class
     159
     160Примери за тест:
     161
     162Login (JWT):
     163{{{
     164curl -X POST http://localhost:5000/api/login
     165 ^
     166-H "Content-Type: application/json" ^
     167-d "{"type":"user","email":"newstudent@gmail.com
     168","password":"Newstudent!15"}"
     169}}}
     170
     171Book class (со JWT):
     172{{{
     173curl -X POST http://localhost:5000/api/book-class
     174 ^
     175-H "Content-Type: application/json" ^
     176-H "Authorization: Bearer <JWT>" ^
     177-d "{"classId":7}"
     178}}}
     179
     180Book class (без JWT):
     181{{{
     182curl -X POST http://localhost:5000/api/book-class
     183 ^
     184-H "Content-Type: application/json" ^
     185-d "{"classId":7}"
     186}}}
     187
     188Reports (во прелистувач):
     189
     190http://localhost:5000/api/reports/top-spenders
     191
     192http://localhost:5000/api/reports/class-utilization
     193
     194http://localhost:5000/api/reports/training-pop-monthly
     195
     196EXPLAIN (во прелистувач):
     197
     198http://localhost:5000/api/debug/explain-events
     199
     200http://localhost:5000/api/debug/explain-class-join
     201