Developer Info
Technische details over deze website - een showcase van full-stack development vaardigheden met Angular, Spring Boot en moderne DevOps praktijken.
Tech Stack
Frontend
Backend
Database
DevOps
Documentation
Monitoring
Security
Architectuur
Framework: Angular 22
Features:
- 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
Structuur: Component-based architecture with services
Framework: Spring Boot 4.1 (Java 21)
Features:
- REST API
- JPA/Hibernate
- Spring Security
- Rate limiting (Bucket4j)
- Email service (Brevo SMTP)
- Sentry error tracking
- Flyway migrations
- Springdoc OpenAPI
- OWASP Encoder
Structuur: Layered architecture: Controller → Service → Repository → Entity
Type: PostgreSQL 18
Features:
- JPA entities
- Repository pattern
- Flyway database migrations
- Version-controlled schema
- Production-ready migration management
Containers:
- Frontend (Nginx)
- Backend (Spring Boot 4.1)
- Database (PostgreSQL 18)
Orchestratie: Docker Compose
API Documentatie
Alle beschikbare API endpoints met details, request/response voorbeelden en rate limiting informatie.
Base URL
- Development:
http://localhost:8080/api - Production:
https://fuber-technics.be/api
Opmerking: In Docker deployment worden <code>/api/</code> requests geproxied door de frontend nginx container naar de backend container intern. Directe backend toegang (<code>localhost:8080</code>) werkt alleen als de backend poort exposed is (alleen voor development). In productie gaan alle API calls via de frontend nginx of reverse proxy.
Authenticatie
Alle endpoints zijn publiek toegankelijk. Geen authenticatie vereist.
Rate Limiting
Het /contact endpoint heeft rate limiting: 5 requests per minuut, 20 requests per uur per IP adres.
Methode:GET
Path:/api/ping
Beschrijving: Health check endpoint voor monitoring en load balancers.
Succesvolle Response:
{
"status": "ok"
}Voorbeeld:
cURL:
curl -X GET http://localhost:8080/api/pingJavaScript:
const response = await fetch('http://localhost:8080/api/ping');
const data = await response.json();Methode:POST
Path:/api/contact
Beschrijving: Verstuurt een contact bericht. Rate limited: 5/min, 20/hour per IP.
Request Body:
{
"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)"
}Succesvolle Response (201):
{
"id": 1,
"message": "Bericht succesvol verzonden",
"status": "success"
}Error Responses:
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
}Voorbeeld:
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();Methode:GET
Path:/api/projects
Beschrijving: Haalt alle projecten op uit het portfolio, gesorteerd op aanmaakdatum (nieuwste eerst).
Query Parameters:
page- integer (optional, default: 0): Pagina nummer (0-indexed)size- integer (optional): Aantal items per pagina. Als niet opgegeven, worden alle resultaten teruggegeven.
Succesvolle Response:
[{
"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"
}]Voorbeeld:
cURL:
curl -X GET http://localhost:8080/api/projectsJavaScript:
const projects = await fetch('http://localhost:8080/api/projects')
.then(res => res.json());Methode:GET
Path:/api/skills
Beschrijving: Haalt technische skills op. Kan gefilterd worden op categorie.
Query Parameters:
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)
Succesvolle Response:
[{
{ "id": 1, "name": "Java", "category": "backend", "orderIndex": 1 },
{ "id": 2, "name": "Spring Boot", "category": "backend", "orderIndex": 2 }
}]Voorbeeld:
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());Methode:GET
Path:/api/postal-codes/{postalCode}
Beschrijving: Zoekt de stad op voor een Belgische postcode.
Path Parameters:
postalCode- string (required): 4-cijferige Belgische postcode
Succesvolle Response:
{
"postalCode": "1000",
"city": "Brussel"
}Error Responses (400):
{
"error": "Invalid postal code format",
"message": "Postal code must be 4 digits"
}Voorbeeld:
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());Methode:GET
Path:/api/postal-codes/{postalCode}/validate
Beschrijving: Valideert of een postcode bestaat in België.
Path Parameters:
postalCode- string (required): 4-cijferige Belgische postcode
Succesvolle Response:
{
"postalCode": "1000",
"valid": true
}Voorbeeld:
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());Security Features & Code Kwaliteit
- 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)
Testing
Framework: JUnit 5 + Mockito
Tools:
- JUnit 5
- Mockito
- Spring Boot Test
- MockMvc
- H2 in-memory database
- Spring Security Test
Coverage: JaCoCo (50% target)
Test types:
- Unit tests
- Integration tests
Framework: Jest + Cypress
Tools:
- Jest
- Cypress E2E
- Angular Testing Utilities
- HttpTestingController
- jest-preset-angular
Coverage: Jest coverage reports
Test types:
- Unit tests (services, components)
- E2E tests (Cypress)
Test Commando's
./test-all.sh (Unix) or test-all.bat (Windows)- Alle tests uitvoeren (backend, frontend unit, E2E)./gradlew test- Backend testsnpm test- Frontend unit testsnpm run e2e- E2E tests (Cypress)