diff --git a/.gitea/workflows/docs.yml b/.gitea/workflows/docs.yml new file mode 100644 index 0000000..3efc73d --- /dev/null +++ b/.gitea/workflows/docs.yml @@ -0,0 +1,28 @@ +name: Build docs + +on: + push: + branches: [main] + +jobs: + build-docs: + runs-on: ubuntu-latest + container: + image: git.kjan.de/actions/runner-latex:latest + env: + # Edit here with the names of your latex file and directory (can use ".") + DIR: docs + FILE: projektdokumentation.tex + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: LaTeX compile + working-directory: ${{ env.DIR }} + run: latexmk -pdf -xelatex ${{ env.FILE }} + + - name: Upload artifacts + uses: https://git.kjan.de/actions/upload-artifact@v4 + with: + name: Doku + path: docs/projektdokumentation.pdf diff --git a/backend/Readme.md b/backend/Readme.md index 8f945dc..228842e 100644 --- a/backend/Readme.md +++ b/backend/Readme.md @@ -1,59 +1,137 @@ -# Starter für das LF08 Projekt +# Casino Gaming Platform - Backend API -## Requirements -* Docker https://docs.docker.com/get-docker/ -* Docker compose (bei Windows und Mac schon in Docker enthalten) https://docs.docker.com/compose/install/ +A Spring Boot backend application providing REST APIs for a casino gaming platform with multiple games, user management, authentication, and payment processing. -## Endpunkt -``` -http://localhost:8080 -``` -## Swagger -``` -http://localhost:8080/swagger -``` +## Features +### Games +- **Blackjack** - Classic card game with deck management +- **Coinflip** - Simple heads/tails betting game +- **Dice** - Dice rolling game +- **Slots** - Slot machine with symbols and payouts +- **Lootboxes** - Reward system with configurable prizes -# Postgres -### Terminal öffnen -für alles gilt, im Terminal im Ordner docker/local sein +### User Management +- User registration and authentication +- OAuth2 integration (Google, GitHub) +- Email verification and password reset +- Balance management and transaction history + +### Payment System +- Deposit functionality with webhook support +- Transaction tracking and status management +- Balance updates and fund validation + +## Tech Stack +- **Java 17** with Spring Boot +- **Spring Security** with JWT authentication +- **Spring Data JPA** with PostgreSQL +- **OAuth2** for social login +- **Email service** for notifications +- **OpenAPI/Swagger** for API documentation + +## Build & Run + +### Prerequisites +- Java 17+ +- Gradle +- Docker & Docker Compose (for PostgreSQL) + +### Build Commands ```bash +# Build the application +./gradlew build + +# Clean build +./gradlew clean build + +# Run the application +./gradlew bootRun + +# Generate JAR file +./gradlew bootJar +``` + +### Testing +```bash +# Run all tests +./gradlew test + +# Run specific test class +./gradlew test --tests "FullyQualifiedClassName" + +# Run checkstyle +./gradlew checkstyleMain checkstyleTest +``` + +## API Endpoints + +The application runs on `http://localhost:8080` + +### API Documentation +- **Swagger UI**: `http://localhost:8080/swagger-ui.html` +- **OpenAPI Spec**: `http://localhost:8080/v3/api-docs` + +### Main Endpoints +- `/api/auth/**` - Authentication and user management +- `/api/games/blackjack/**` - Blackjack game operations +- `/api/games/coinflip/**` - Coinflip game operations +- `/api/games/dice/**` - Dice game operations +- `/api/games/slots/**` - Slot machine operations +- `/api/lootboxes/**` - Lootbox management +- `/api/deposits/**` - Payment and deposit handling +- `/api/users/**` - User profile management +- `/api/health` - Health check endpoint + +## Database Setup + +### PostgreSQL with Docker +```bash +# Start PostgreSQL container cd docker/local -``` -### Postgres starten -```bash docker compose up -``` -Achtung: Der Docker-Container läuft dauerhaft! Wenn er nicht mehr benötigt wird, sollten Sie ihn stoppen. -### Postgres stoppen -```bash +# Stop PostgreSQL container docker compose down -``` -### Postgres Datenbank wipen, z.B. bei Problemen -```bash +# Reset database (if needed) docker compose down docker volume rm local_lf8_starter_postgres_data docker compose up ``` -### Intellij-Ansicht für Postgres Datenbank einrichten -```bash -1. Lasse den Docker-Container mit der PostgreSQL-Datenbank laufen -2. im Ordner resources die Datei application.properties öffnen und die URL der Datenbank kopieren -3. rechts im Fenster den Reiter Database öffnen -4. In der Database-Symbolleiste auf das Datenbanksymbol mit dem Schlüssel klicken -5. auf das Pluszeichen klicken -6. Datasource from URL auswählen -7. URL der DB einfügen und PostgreSQL-Treiber auswählen, mit OK bestätigen -8. Username lf8_starter und Passwort secret eintragen (siehe application.properties), mit Apply bestätigen -9. im Reiter Schemas alle Häkchen entfernen und lediglich vor lf8_starter_db und public Häkchen setzen -10. mit Apply und ok bestätigen -``` -# Keycloak +### Database Configuration +Database connection settings are configured in `src/main/resources/application.properties` -### Keycloak Token -1. Auf der Projektebene [GetBearerToken.http](../GetBearerToken.http) öffnen. -2. Neben der Request auf den grünen Pfeil drücken -3. Aus dem Reponse das access_token kopieren \ No newline at end of file +### IntelliJ Database Setup +1. Start the PostgreSQL Docker container +2. Open `application.properties` and copy the database URL +3. In IntelliJ, open the Database tab (right panel) +4. Click the database icon with key in the toolbar +5. Click the plus (+) icon +6. Select "Datasource from URL" +7. Paste the database URL and select PostgreSQL driver +8. Enter credentials (username: `lf8_starter`, password: `secret`) +9. In Schemas tab, uncheck all except `lf8_starter_db` and `public` +10. Apply and confirm + +## Authentication + +The application supports multiple authentication methods: +- JWT-based authentication +- OAuth2 (Google, GitHub) +- Email/password with verification + +### Getting Bearer Token +For API testing, use the provided HTTP client file: +1. Open `GetBearerToken.http` at project root +2. Execute the request +3. Copy the `access_token` from the response +4. Use in Authorization header: `Bearer ` + +## Configuration + +Key configuration files: +- `application.properties` - Main application configuration +- `SecurityConfig.java` - Security and CORS settings +- `OpenAPIConfiguration.java` - API documentation setup \ No newline at end of file diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 1d73b90..548c9aa 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -39,7 +39,7 @@ repositories { } dependencies { - implementation("com.stripe:stripe-java:29.1.0") + implementation("com.stripe:stripe-java:29.2.0") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-web") compileOnly("org.projectlombok:lombok") @@ -47,13 +47,13 @@ dependencies { testImplementation("org.springframework.boot:spring-boot-starter-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.4.5") - implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.4.5") + implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.5.0") + implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.5.0") runtimeOnly("org.postgresql:postgresql") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8") - implementation("io.jsonwebtoken:jjwt-api:0.11.5") - runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") - runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") + implementation("io.jsonwebtoken:jjwt-api:0.12.6") + runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6") + runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") implementation("org.springframework.boot:spring-boot-starter-mail") } diff --git a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java b/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java index 1a7d08d..b34f1e1 100644 --- a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java +++ b/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java @@ -91,7 +91,7 @@ public class JwtUtils { } private Claims extractAllClaims(String token) { - return Jwts.parserBuilder() + return Jwts.parser() .setSigningKey(getSigningKey()) .build() .parseClaimsJws(token) diff --git a/frontend/README.md b/frontend/README.md index daf35fe..a67f78f 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,18 +1,106 @@ # Casino Gaming Platform - Frontend -This is the frontend application for the Casino Gaming Platform. It's built with Angular 18 and TailwindCSS, providing a responsive and modern UI for the casino gaming experience. +A modern Angular 20 casino gaming platform featuring multiple games including Blackjack, Coinflip, Dice, Slots, and Lootboxes. Built with Angular 20, TailwindCSS 4, and powered by Bun for fast development. -## Development +## 🎮 Features -### Commands +- **Multiple Games**: Blackjack, Coinflip, Dice, Slots, Lootboxes +- **User Authentication**: OAuth2, email verification, password recovery +- **Real-time Gaming**: Interactive game mechanics with animations +- **Payment Integration**: Stripe integration for deposits +- **Responsive Design**: Mobile-first design with TailwindCSS +- **Audio Experience**: Game sounds and audio feedback +- **Transaction History**: Complete betting and transaction tracking -- **Build**: `bun run build` or `bunx @angular/cli build` -- **Start Dev Server**: `bun run start` or `bunx @angular/cli serve --proxy-config src/proxy.conf.json` -- **Format Code**: `bun run format` or `prettier --write "src/**/*.{ts,html,css,scss}"` -- **Lint**: `bun run lint` or `ng lint` -- **Test**: `bun run test` or `bunx @angular/cli test` +## 🚀 Getting Started + +### Prerequisites + +- [Bun](https://bun.sh/) (recommended) or Node.js 18+ +- Angular CLI 20+ + +### Installation + +```bash +# Install dependencies +bun install + +# Start development server +bun run start +``` + +The app will be available at `http://localhost:4200` + +## 📋 Commands + +### Development +- **Start Dev Server**: `bun run start` - Starts dev server with proxy configuration +- **Build**: `bun run build` - Production build +- **Watch Build**: `bun run watch` - Development build with file watching + +### Code Quality +- **Format**: `bun run format` - Format code with Prettier +- **Format Check**: `bun run format:check` - Check code formatting +- **Lint**: `bun run lint` - Run ESLint +- **OxLint**: `bun run oxlint` - Run OxLint with strict warnings + +### Testing +- **Test All**: `bun run test` - Run all tests with Karma/Jasmine - **Test Single File**: `bunx @angular/cli test --include=path/to/test.spec.ts` +## 🛠️ Technology Stack + +### Core +- **Angular 20**: Latest Angular framework with standalone components +- **TypeScript 5.8**: Strongly typed JavaScript +- **RxJS 7.8**: Reactive programming for HTTP and state management + +### Styling & UI +- **TailwindCSS 4**: Utility-first CSS framework +- **PostCSS**: CSS processing and optimization +- **FontAwesome**: Icon library with Angular integration + +### Animation & Interaction +- **GSAP**: High-performance animations +- **CountUp.js**: Number animation effects +- **Custom Audio Service**: Game sound effects and feedback + +### Development Tools +- **Bun**: Fast JavaScript runtime and package manager +- **ESLint + Angular ESLint**: Code linting with Angular-specific rules +- **OxLint**: Fast Rust-based linter +- **Prettier**: Code formatting +- **Karma + Jasmine**: Testing framework + +### Payment & APIs +- **Stripe**: Payment processing integration +- **Custom HTTP Interceptors**: API communication and error handling + +## 🏗️ Architecture + +### Project Structure +``` +src/ +├── app/ +│ ├── feature/ # Feature modules +│ │ ├── auth/ # Authentication (login, register, OAuth2) +│ │ ├── game/ # Game modules (blackjack, coinflip, dice, slots) +│ │ ├── lootboxes/ # Lootbox system +│ │ └── deposit/ # Payment and deposits +│ ├── model/ # Data models and interfaces +│ ├── service/ # Core services (auth, user, transaction) +│ └── shared/ # Shared components, directives, services +├── environments/ # Environment configurations +└── public/ # Static assets (images, sounds) +``` + +### Key Components +- **Game Components**: Modular game implementations with services +- **Shared Components**: Reusable UI components (navbar, footer, modals) +- **Services**: Business logic and API communication +- **Guards**: Route protection and authentication +- **Interceptors**: HTTP request/response handling + ## Style Guide ### Color Palette diff --git a/frontend/angular.json b/frontend/angular.json index a9f9a84..d8c3879 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -21,7 +21,8 @@ { "glob": "**/*", "input": "public" - } + }, + "src/assets" ], "styles": [ "src/styles.css" diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index 88f4fe1..f6611b9 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -62,14 +62,12 @@ export const routes: Routes = [ loadComponent: () => import('./feature/lootboxes/lootbox-selection/lootbox-selection.component'), canActivate: [authGuard], - children: [ - { - path: 'open/:id', - loadComponent: () => - import('./feature/lootboxes/lootbox-opening/lootbox-opening.component'), - canActivate: [authGuard], - }, - ], + }, + { + path: 'lootboxes/open/:id', + loadComponent: () => + import('./feature/lootboxes/lootbox-opening/lootbox-opening.component'), + canActivate: [authGuard], }, { path: 'dice', diff --git a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts index 6e61c0e..9b07eee 100644 --- a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts @@ -61,6 +61,9 @@ export class AnimatedNumberComponent implements OnChanges, AfterViewInit { this.countUp = new CountUp(this.numberElement.nativeElement, this.value, { startVal: this.previousValue, duration: this.duration, + decimalPlaces: 2, + useEasing: true, + useGrouping: false, easingFn: (t, b, c, d) => { if (this.ease === 'power1.out') { return c * (1 - Math.pow(1 - t / d, 1)) + b; diff --git a/frontend/src/app/feature/home/home.component.html b/frontend/src/app/feature/home/home.component.html index b0b77d3..9b79a9e 100644 --- a/frontend/src/app/feature/home/home.component.html +++ b/frontend/src/app/feature/home/home.component.html @@ -4,7 +4,7 @@
-
+

Alle Spiele

@@ -18,24 +18,54 @@
-
-
-
- -
+
+ +
+
+
+
-

{{ game.name }}

- +
+

{{ game.name }}

+ +
+
+
+
+
+ + +
+
+
+ +
+
+

{{ game.name }}

+ +
@@ -43,53 +73,5 @@
- -
-
-

Konto

-
- - - - -
-
- - - -
-

Letzte Transaktionen

-
-
-
-

{{ transaction.status }}

-

- {{ transaction.createdAt | date: 'd.m.y H:m' }} -

-
- - {{ transaction.amount | currency: 'EUR' }} - -
-
-
-
diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts index ef947f9..f032246 100644 --- a/frontend/src/app/feature/home/home.component.ts +++ b/frontend/src/app/feature/home/home.component.ts @@ -1,34 +1,18 @@ -import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; -import { AsyncPipe, CurrencyPipe, DatePipe, NgFor } from '@angular/common'; -import { DepositComponent } from '../deposit/deposit.component'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { NgFor } from '@angular/common'; import { ActivatedRoute, Router } from '@angular/router'; -import { ConfirmationComponent } from '@shared/components/confirmation/confirmation.component'; import { Game } from 'app/model/Game'; -import { Observable } from 'rxjs'; -import { TransactionService } from '@service/transaction.service'; import format from 'ajv/dist/vocabularies/format'; -import { TransactionHistoryComponent } from '../transaction-history/transaction-history.component'; -import { TransactionData } from '../../model/TransactionData'; @Component({ selector: 'app-homepage', standalone: true, - imports: [ - CurrencyPipe, - NgFor, - DepositComponent, - ConfirmationComponent, - AsyncPipe, - DatePipe, - TransactionHistoryComponent, - ], + imports: [NgFor], templateUrl: './home.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export default class HomeComponent implements OnInit { - isDepositModalOpen = false; isDepositSuccessful = false; - isTransactionModalOpen = false; constructor( public route: ActivatedRoute, @@ -78,35 +62,10 @@ export default class HomeComponent implements OnInit { }, ]; - allGames: Game[] = [...this.featuredGames]; - - recentTransactionData: Observable = - inject(TransactionService).getUsersTransactions(5); - - openDepositModal() { - this.isDepositModalOpen = true; - } - - closeDepositModal() { - this.isDepositModalOpen = false; - } - openDepositConfirmationModal() { this.isDepositSuccessful = true; } - openTransactionModal() { - this.isTransactionModalOpen = true; - } - - closeDepositConfirmationModal() { - this.isDepositSuccessful = false; - } - - closeTransactionModal() { - this.isTransactionModalOpen = false; - } - navigateToGame(route: string) { this.router.navigate([route]); } diff --git a/frontend/src/app/feature/landing/landing.component.html b/frontend/src/app/feature/landing/landing.component.html index ae963a9..a7cb79e 100644 --- a/frontend/src/app/feature/landing/landing.component.html +++ b/frontend/src/app/feature/landing/landing.component.html @@ -21,13 +21,7 @@ (click)="showRegisterForm()" class="w-full sm:w-auto button-primary px-6 sm:px-8 py-3 shadow-lg" > - Konto erstellen - - }
@@ -46,58 +40,108 @@

Slots

Klassische Spielautomaten

- Jetzt Spielen + @if (isLoggedIn()) { + + Jetzt Spielen + + } @else { + + }
+
-
-
-

Poker

-

Texas Hold'em & mehr

- Jetzt Spielen -
-

Dice

Würfelspiel

- Jetzt Spielen + @if (isLoggedIn()) { + + Jetzt Spielen + + } @else { + + }
@@ -165,7 +209,7 @@
24/7
-
Support *
+
Support
diff --git a/frontend/src/app/feature/landing/landing.component.ts b/frontend/src/app/feature/landing/landing.component.ts index d354fa4..93b9e84 100644 --- a/frontend/src/app/feature/landing/landing.component.ts +++ b/frontend/src/app/feature/landing/landing.component.ts @@ -23,15 +23,14 @@ import RecoverPasswordComponent from '../auth/recover-password/recover-password. }) export class LandingComponent implements OnInit, OnDestroy { currentSlide = 0; - private autoplayInterval: ReturnType | undefined; authService: AuthService = inject(AuthService); route: ActivatedRoute = inject(ActivatedRoute); showLogin = signal(false); showRegister = signal(false); showRecoverPassword = signal(false); + isLoggedIn = signal(this.authService.isLoggedIn()); ngOnInit() { - this.startAutoplay(); document.body.style.overflow = 'auto'; if (this.route.snapshot.queryParamMap.get('login') === 'true') { this.showLoginForm(); @@ -39,7 +38,6 @@ export class LandingComponent implements OnInit, OnDestroy { } ngOnDestroy() { - this.stopAutoplay(); document.body.style.overflow = 'auto'; } @@ -73,33 +71,13 @@ export class LandingComponent implements OnInit, OnDestroy { prevSlide() { this.currentSlide = this.currentSlide === 0 ? 1 : 0; - this.resetAutoplay(); } nextSlide() { this.currentSlide = this.currentSlide === 1 ? 0 : 1; - this.resetAutoplay(); } goToSlide(index: number) { this.currentSlide = index; - this.resetAutoplay(); - } - - private startAutoplay() { - this.autoplayInterval = setInterval(() => { - this.nextSlide(); - }, 5000); - } - - private stopAutoplay() { - if (this.autoplayInterval) { - clearInterval(this.autoplayInterval); - } - } - - private resetAutoplay() { - this.stopAutoplay(); - this.startAutoplay(); } } diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html index 79cf823..ef2de86 100644 --- a/frontend/src/app/shared/components/footer/footer.component.html +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -5,24 +5,19 @@ -
- @@ -54,10 +49,6 @@ Google Pay - @@ -65,10 +56,6 @@
diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts index 2cb56e1..b47b6fd 100644 --- a/frontend/src/app/shared/components/footer/footer.component.ts +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -1,13 +1,14 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faCreditCard, faMoneyBillTransfer, faWallet } from '@fortawesome/free-solid-svg-icons'; -import { faApplePay, faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; +import { faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; +import { RouterLink } from '@angular/router'; @Component({ selector: 'app-footer', standalone: true, templateUrl: './footer.component.html', - imports: [FontAwesomeModule], + imports: [FontAwesomeModule, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, }) export class FooterComponent { @@ -18,5 +19,4 @@ export class FooterComponent { faMoneyBillTransfer = faMoneyBillTransfer; faWallet = faWallet; faGooglePay = faGooglePay; - faApplePay = faApplePay; } diff --git a/frontend/src/app/shared/components/navbar/navbar.component.html b/frontend/src/app/shared/components/navbar/navbar.component.html index 7e010fa..608f3de 100644 --- a/frontend/src/app/shared/components/navbar/navbar.component.html +++ b/frontend/src/app/shared/components/navbar/navbar.component.html @@ -1,40 +1,120 @@ -