# Ticketsystem A ticket system with backend and frontend components. ## Components - **[Backend](../backend/index.html)** - The server-side API and business logic - **[Frontend](../frontend/index.html)** - The client-side user interface ## Usage ### Prerequisite #### IMPORTANT Before compiling the programm you have to install the rust toolchain. For a guide to do this, visit: A instance of a postgresql has to be accessible to the backend. Place the connection details in a .env file into the variable `DATABASE_URL` To setup the tables you either can create them manually by following the sheme specified in `backend/migrations` or apply them with sqlx To install sqlx run `cargo install sqlx` and then in the `backend` directory run `sqlx migrate run` to create the tables ### Environment The .env file has to be in the root directory of the project or in the same directory as the executable Keys: `DATABASE_URL`: Specifying the url and connection details for the database `TOKEN_SECRET`: The JWT token secret, can theoretically be anything but is more secure when generated with a tool, e.g: `ORIGIN`: The origin of the frontend, used for CORS rules `BACKEND_PORT`: The port which the backend should use to run on ### Backend The backend can either be run via `cargo run --release` or `cargo build --release` using the correct target architecture, e.g. 'x86_64-unknown-linux-gnu', the executable will be placed in the `target/release` directory and can then be run via any method ### Frontend The HTML code for the frontend can be generated by using `trunk build`. The resulting files will end up in the `frontend/dist` directory and can be served over any webserver supporting wasm #### NOTE To install trunk run `cargo install trunk` #### IMPORTANT Requests from the frontend to /api/* have to be proxied to the Backend Example with nginx and frontend running at localhost:8000 and backend at localhost:9000 : ```nginx location /api/ { proxy_pass http://localhost:9000/api; } ``` ## Diagramms ### Class Diagram ```mermaid classDiagram class backend_src_cookie_Error { +status: &'static str +message: String } class backend_src_TicketResponse { +id: i32 +category: String +betreff: String +description: String +room: i16 +status: String +date: chrono::DateTime~chrono::Utc~ +user_id: i16 +user_first_name: String +user_last_name: String } class backend_src_User { +id: i16 +last_name: String +first_name: String +username: String +is_admin: bool +pwd: String } class backend_src_TicketCreateScheme { +category: String +betreff: String +description: String +room: i16 } class backend_src_TicketUpdateScheme { +status: String } class backend_src_UserUpdateScheme { +id: i16 +first_name: String +last_name: String +username: String +make_admin: bool +new_pwd: String } class backend_src_UserCreateScheme { +first_name: String +last_name: String +username: String +is_admin: bool +pwd: String } class backend_src_LoginScheme { +username: String +pwd: String } class backend_src_FilteredUser { +id: i16 +first_name: String +last_name: String +username: String +is_admin: bool } class backend_src_Claims { +sub: String +issued: usize +expires: usize } class backend_src_AppState { -db: PgPool -env: backend_src_Env } class backend_src_Env { +db_url: String +token_secret: String +origin: String +backend_port: String +load() backend_src_Env } class backend_target_debug_build_chrono-tz-56cec396bfb3cea1_out_FromStr { +from_str(s:&str) Result~Self, Self::Err~ } class backend_target_debug_build_chrono-tz-56cec396bfb3cea1_out_Tz { +name() &'static str } class backend_target_debug_build_chrono-tz-56cec396bfb3cea1_out_Debug { +fmt(f:&mut Formatter) fmt::Result } class backend_target_debug_build_chrono-tz-56cec396bfb3cea1_out_Display { +fmt(f:&mut Formatter) fmt::Result } class backend_target_debug_build_chrono-tz-56cec396bfb3cea1_out_TimeSpans { +timespans() FixedTimespanSet } class backend_target_debug_build_chrono-tz-261584f9cc573a32_out_FromStr { +from_str(s:&str) Result~Self, Self::Err~ } class backend_target_debug_build_chrono-tz-261584f9cc573a32_out_Tz { +name() &'static str } class backend_target_debug_build_chrono-tz-261584f9cc573a32_out_Debug { +fmt(f:&mut Formatter) fmt::Result } class backend_target_debug_build_chrono-tz-261584f9cc573a32_out_Display { +fmt(f:&mut Formatter) fmt::Result } class backend_target_debug_build_chrono-tz-261584f9cc573a32_out_TimeSpans { +timespans() FixedTimespanSet } class frontend_src_pages_TicketCreateScheme { +category: String +betreff: String +description: String +room: i16 } class frontend_src_pages_TicketUpdateScheme { +status: String } class frontend_src_pages_Ticket { +id: i32 +category: String +betreff: String +description: String +room: i16 +status: String +date: chrono::DateTime~chrono::Utc~ +user_id: i16 +user_first_name: String +user_last_name: String } class frontend_src_pages_TicketProps { +id: i32 } class frontend_src_pages_ActiveUser { +id: Option~i16~ +is_admin: bool } class frontend_src_pages_ApiError { -message: String -_status: String } class frontend_src_pages_SidebarExpandState { +ticket_open: bool +users_open: bool } class frontend_src_pages_Default { +default() Self } class frontend_src_pages_SidebarState { +expand: frontend_src_pages_SidebarExpandState +set_tickets_open: Callback~bool~ +toggle_tickets: Callback~()~ +set_users_open: Callback~bool~ +toggle_users: Callback~()~ +new(expand:frontend_src_pages_SidebarExpandState, set_tickets_open:Callback~bool~, toggle_tickets:Callback~()~, set_users_open:Callback~bool~, toggle_users:Callback~()~) Self } class frontend_src_pages_SidebarProps { +children: Children } class frontend_src_pages_TicketPartial { -date: DateTime~Utc~ -room: i16 -user_id: i16 } class frontend_src_pages_UserPartial { -id: i16 -first_name: String -last_name: String } class frontend_src_pages_RoomTotalsProps { -tickets: Vec~frontend_src_pages_TicketPartial~ } class frontend_src_pages_UserTotalProps { -users: Vec~frontend_src_pages_UserPartial~ -tickets: Vec~frontend_src_pages_TicketPartial~ } class frontend_src_pages_AdminSetupScheme { +first_name: String +last_name: String +username: String +pwd: String } class frontend_src_pages_UserCreateScheme { +first_name: String +last_name: String +username: String +is_admin: bool +pwd: String } class frontend_src_pages_LoginScheme { +username: String +pwd: String } class frontend_src_pages_UserUpdateScheme { +id: i16 +first_name: String +last_name: String +username: String +make_admin: bool +new_pwd: String } class frontend_src_pages_FilteredUser { +id: i16 +first_name: String +last_name: String +username: String +is_admin: bool } class frontend_src_pages_UserProps { +id: i16 } class frontend_src_pages_ApiError { -message: String -_status: String } class frontend_src_AuthState { +is_authenticated: Option~bool~ +is_admin: Option~bool~ } class frontend_src_ProtectedRouteProps { +children: Children +admin_page: bool } class frontend_src_SidebarShellProps { +children: Children } class frontend_src_AdminCheckWrapperProps { +children: Children } backend_src_AppState --> backend_src_Env backend_src_Env ..> backend_src_Env frontend_src_pages_SidebarState --> frontend_src_pages_SidebarExpandState frontend_src_pages_RoomTotalsProps --> frontend_src_pages_TicketPartial frontend_src_pages_UserTotalProps --> frontend_src_pages_UserPartial frontend_src_pages_UserTotalProps --> frontend_src_pages_TicketPartial ``` ## Usage of AI Github Copilot CLI was used with the model Claude Haiku 4.5 to generate most of the documentation: ### Prompt Generate comments for cargo doc describing the indivilual components and create links to relevant structs, functions etc. ### Output The comments with `///` or `//!` I've gone over most of it and modified it to my needs and opinions