Info Développeur
Détails techniques sur ce site web - une vitrine des compétences de développement full-stack avec Angular, Spring Boot et les pratiques DevOps modernes.
Stack Technique
Frontend
Backend
Database
DevOps
Documentation
Monitoring
Security
Architecture
Framework: Angular 22
Fonctionnalités:
- Standalone components
- Angular Material UI components
- 3-language i18n (Transloco)
- Reactive forms
- HTTP client
- Router
- Sentry error tracking
- Web Vitals performance monitoring
- Bootstrap 5 UI
- TypeScript 6
Structure: Component-based architecture with services
Framework: Spring Boot 4.1 (Java 21)
Fonctionnalités:
- REST API
- JPA/Hibernate
- Spring Security
- Rate limiting (Bucket4j)
- Email service (Brevo SMTP)
- Sentry error tracking
- Flyway migrations
- Springdoc OpenAPI
- OWASP Encoder
Structure: Layered architecture: Controller → Service → Repository → Entity
Type: PostgreSQL 18
Fonctionnalités:
- JPA entities
- Repository pattern
- Flyway database migrations
- Version-controlled schema
- Production-ready migration management
Conteneurs:
- Frontend (Nginx)
- Backend (Spring Boot 4.1)
- Database (PostgreSQL 18)
Orchestration: Docker Compose
Documentation API
Tous les endpoints API disponibles avec détails, exemples de requêtes/réponses et informations sur la limitation de débit.
URL de base
- Développement:
http://localhost:8080/api - Production:
https://fuber-technics.be/api
Note: Dans le déploiement Docker, les requêtes <code>/api/</code> sont proxifiées par le conteneur nginx frontend vers le conteneur backend en interne. L'accès direct au backend (<code>localhost:8080</code>) ne fonctionne que si le port backend est exposé (développement uniquement). En production, tous les appels API passent par le nginx frontend ou le reverse proxy.
Authentification
Tous les endpoints sont accessibles publiquement. Aucune authentification requise.
Limitation de débit
L'endpoint /contact a une limitation de débit: 5 requêtes par minute, 20 requêtes par heure par adresse IP.
Méthode:GET
Chemin:/api/ping
Description: Health check endpoint voor monitoring en load balancers.
Réponse de succès:
{
"status": "ok"
}Exemple:
cURL:
curl -X GET http://localhost:8080/api/pingJavaScript:
const response = await fetch('http://localhost:8080/api/ping');
const data = await response.json();Méthode:POST
Chemin:/api/contact
Description: Verstuurt een contact bericht. Rate limited: 5/min, 20/hour per IP.
Corps de la requête:
{
"name": "string (required, max 100)",
"email": "string (required, valid email)",
"phone": "string (optional, max 20)",
"subject": "string (required, max 200)",
"message": "string (required, max 5000)"
}Réponse de succès (201):
{
"id": 1,
"message": "Bericht succesvol verzonden",
"status": "success"
}Réponses d'erreur:
400 Bad Request:
{
"error": "Validatiefouten",
"details": [{ "field": "email", "message": "Ongeldig e-mailadres" }]
}429 Too Many Requests:
{
"error": "Te veel verzoeken. Probeer het later opnieuw.",
"retryAfterSeconds": 60
}Exemple:
cURL:
curl -X POST http://localhost:8080/api/contact \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "[email protected]", "subject": "Project Inquiry", "message": "I would like to discuss a potential project."}'JavaScript:
const response = await fetch('http://localhost:8080/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'John Doe',
email: '[email protected]',
subject: 'Project Inquiry',
message: 'I would like to discuss a potential project.'
})
});
const data = await response.json();Méthode:GET
Chemin:/api/projects
Description: Haalt alle projecten op uit het portfolio, gesorteerd op aanmaakdatum (nieuwste eerst).
Paramètres de requête:
page- integer (optional, default: 0): Pagina nummer (0-indexed)size- integer (optional): Aantal items per pagina. Als niet opgegeven, worden alle resultaten teruggegeven.
Réponse de succès:
[{
"id": 1,
"title": "E-Commerce Platform",
"type": "Web Application",
"stack": "Spring Boot, Angular, PostgreSQL",
"role": "Full Stack Developer",
"highlights": ["Implemented payment integration"],
"githubUrl": "https://github.com/example/project",
"demoUrl": "https://demo.example.com",
"description": "A full-featured e-commerce platform",
"createdAt": "2024-01-15T10:00:00",
"updatedAt": "2024-01-20T14:30:00"
}]Exemple:
cURL:
curl -X GET http://localhost:8080/api/projectsJavaScript:
const projects = await fetch('http://localhost:8080/api/projects')
.then(res => res.json());Méthode:GET
Chemin:/api/skills
Description: Haalt technische skills op. Kan gefilterd worden op categorie.
Paramètres de requête:
category- string (optional): Filter op categorie. Mogelijke waarden: backend, frontend, databases, devops, toolspage- integer (optional, default: 0): Pagina nummer (alleen gebruikt als category niet opgegeven is)size- integer (optional): Aantal items per pagina (alleen gebruikt als category niet opgegeven is)
Réponse de succès:
[{
{ "id": 1, "name": "Java", "category": "backend", "orderIndex": 1 },
{ "id": 2, "name": "Spring Boot", "category": "backend", "orderIndex": 2 }
}]Exemple:
cURL:
curl -X GET "http://localhost:8080/api/skills?category=backend"JavaScript:
const backendSkills = await fetch(
'http://localhost:8080/api/skills?category=backend'
).then(res => res.json());Méthode:GET
Chemin:/api/postal-codes/{postalCode}
Description: Zoekt de stad op voor een Belgische postcode.
Paramètres de chemin:
postalCode- string (required): 4-cijferige Belgische postcode
Réponse de succès:
{
"postalCode": "1000",
"city": "Brussel"
}Réponses d'erreur (400):
{
"error": "Invalid postal code format",
"message": "Postal code must be 4 digits"
}Exemple:
cURL:
curl -X GET http://localhost:8080/api/postal-codes/1000JavaScript:
const postalCode = '1000';
const result = await fetch(
`http://localhost:8080/api/postal-codes/${postalCode}`
).then(res => res.json());Méthode:GET
Chemin:/api/postal-codes/{postalCode}/validate
Description: Valideert of een postcode bestaat in België.
Paramètres de chemin:
postalCode- string (required): 4-cijferige Belgische postcode
Réponse de succès:
{
"postalCode": "1000",
"valid": true
}Exemple:
cURL:
curl -X GET http://localhost:8080/api/postal-codes/1000/validateJavaScript:
const postalCode = '1000';
const result = await fetch(
`http://localhost:8080/api/postal-codes/${postalCode}/validate`
).then(res => res.json());Fonctionnalités de sécurité & Qualité du code
- CORS configuration with allowed origins
- CSRF protection (disabled for public API endpoints)
- Rate limiting (5 req/min, 20 req/hour per IP)
- Input validation and sanitization (OWASP Encoder)
- XSS protection
- SQL injection protection via JPA
- Security headers (CSP, X-Frame-Options)
- Error tracking and monitoring (Sentry) for production debugging
- Error handling with proper HTTP status codes
- DTO/Entity separation
- Input validation (Bean Validation)
- Structured logging
- Dependency locking for security (Gradle lock mode: STRICT)
- Database migrations with Flyway (version control, rollback support)
- Clean code principles
- Production error tracking with Sentry (frontend & backend)
- Performance monitoring (no session replay)
- Code quality tools: Checkstyle, SpotBugs
- Test coverage: JaCoCo (50% target)
Tests
Framework: JUnit 5 + Mockito
Outils:
- JUnit 5
- Mockito
- Spring Boot Test
- MockMvc
- H2 in-memory database
- Spring Security Test
Couverture: JaCoCo (50% target)
Types de tests:
- Unit tests
- Integration tests
Framework: Jest + Cypress
Outils:
- Jest
- Cypress E2E
- Angular Testing Utilities
- HttpTestingController
- jest-preset-angular
Couverture: Jest coverage reports
Types de tests:
- Unit tests (services, components)
- E2E tests (Cypress)
Commandes de test
./test-all.sh (Unix) or test-all.bat (Windows)- Exécuter tous les tests (backend, frontend unit, E2E)./gradlew test- Tests backendnpm test- Tests unitaires frontendnpm run e2e- Tests E2E (Cypress)