21 Commits
v0.0.7 ... main

Author SHA1 Message Date
github-actions[bot]
5bf01c59b5 chore(release): bump version to v0.0.15 and update changelog [skip ci] 2026-02-22 17:58:39 +00:00
burakalmazlar
6ba8d8b7ce degisiklik
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m59s
2026-02-22 20:58:29 +03:00
github-actions[bot]
5b0ea13ba0 chore(release): bump version to v0.0.14 and update changelog [skip ci] 2026-02-22 16:06:48 +00:00
almazlar
53cb84dd14 feat: replace rich cerulean color variables with a new color palette for improved theming
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m51s
2026-02-22 19:06:37 +03:00
github-actions[bot]
649c9f8d69 chore(release): bump version to v0.0.13 and update changelog [skip ci] 2026-02-22 15:50:28 +00:00
almazlar
fe20a69482 feat: update button and input styles with new color variables and hover/focus states
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m46s
2026-02-22 18:50:17 +03:00
github-actions[bot]
4c6eebe61f chore(release): bump version to v0.0.12 and update changelog [skip ci] 2026-02-22 15:39:04 +00:00
almazlar
24424cc226 feat: update CSS variables for improved theming and styling
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m46s
2026-02-22 18:38:54 +03:00
github-actions[bot]
a45d2269eb chore(release): bump version to v0.0.11 and update changelog [skip ci] 2026-02-22 15:21:10 +00:00
almazlar
f450b6fdce fix: correct spelling of 'application' in README
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m45s
2026-02-22 18:20:57 +03:00
github-actions[bot]
1479827612 chore(release): bump version to v0.0.10 and update changelog [skip ci] 2026-02-22 15:10:24 +00:00
almazlar
b3f09d5dfc feat: add deployment steps for Backend and Frontend to Dokploy
Some checks failed
Release and Build Docker Images / release-and-build (push) Failing after 2m14s
2026-02-22 18:05:39 +03:00
almazlar
4c83f6670d fix: update VITE_BASE_URL to use port 8080 in Dockerfile
Some checks failed
Release and Build Docker Images / release-and-build (push) Has been cancelled
2026-02-22 17:46:20 +03:00
almazlar
d9e69e03ad fix: update server port to 8080 in Dockerfile and application properties
Some checks failed
Release and Build Docker Images / release-and-build (push) Has been cancelled
2026-02-22 17:29:04 +03:00
github-actions[bot]
c1c326aa5d chore(release): bump version to v0.0.9 and update changelog [skip ci] 2026-02-22 12:03:26 +00:00
almazlar
c26ee4f400 feat: add createdAt field to Todo entity and update database migration script
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m45s
2026-02-22 15:03:11 +03:00
github-actions[bot]
0f7339d5c1 chore(release): bump version to v0.0.8 and update changelog [skip ci] 2026-02-22 11:08:47 +00:00
almazlar
386f5137c6 fix: update Dockerfile, application properties, and controller mappings for health check and CORS support
All checks were successful
Release and Build Docker Images / release-and-build (push) Successful in 1m38s
2026-02-22 14:08:31 +03:00
almazlar
b5dcba1e11 fix: update application properties and Dockerfile for local development configuration 2026-02-22 13:18:15 +03:00
almazlar
854a0bace8 fix: update Dockerfile to run tests during build and adjust TodoController request mapping 2026-02-22 13:18:15 +03:00
almazlar
fda1f39901 fix: add CrossOrigin annotation to TodoController for CORS support 2026-02-22 13:18:15 +03:00
17 changed files with 246 additions and 76 deletions

View File

@@ -147,3 +147,11 @@ jobs:
build-args: |
VITE_APP_VERSION=${{ steps.generate.outputs.new_tag }}
VITE_BASE_URL=https://todo.almazlar.com/api
- name: Deploy to Dokploy (Backend)
run: |
curl -X POST "${{ secrets.DOKPLOY_BACKEND_WEBHOOK_URL }}"
- name: Deploy to Dokploy (Frontend)
run: |
curl -X POST "${{ secrets.DOKPLOY_FRONTEND_WEBHOOK_URL }}"

View File

@@ -1,3 +1,40 @@
## [v0.0.15] - 2026-02-22
* degisiklik (6ba8d8b)
## [v0.0.14] - 2026-02-22
* feat: replace rich cerulean color variables with a new color palette for improved theming (53cb84d)
## [v0.0.13] - 2026-02-22
* feat: update button and input styles with new color variables and hover/focus states (fe20a69)
## [v0.0.12] - 2026-02-22
* feat: update CSS variables for improved theming and styling (24424cc)
## [v0.0.11] - 2026-02-22
* fix: correct spelling of 'application' in README (f450b6f)
## [v0.0.10] - 2026-02-22
* feat: add deployment steps for Backend and Frontend to Dokploy (b3f09d5)
* fix: update VITE_BASE_URL to use port 8080 in Dockerfile (4c83f66)
* fix: update server port to 8080 in Dockerfile and application properties (d9e69e0)
## [v0.0.9] - 2026-02-22
* feat: add createdAt field to Todo entity and update database migration script (c26ee4f)
## [v0.0.8] - 2026-02-22
* fix: update Dockerfile, application properties, and controller mappings for health check and CORS support (386f513)
* fix: update application properties and Dockerfile for local development configuration (b5dcba1)
* fix: update Dockerfile to run tests during build and adjust TodoController request mapping (854a0ba)
* fix: add CrossOrigin annotation to TodoController for CORS support (fda1f39)
## [v0.0.7] - 2026-02-22
* fix: update API base URL and add healthcheck for backend service (4050c08)

View File

@@ -1,2 +1,2 @@
# todo
# Simple TODO applicatoon to use as template.

View File

@@ -1,15 +1,25 @@
# Build stage
# Build stage ---------------------------------------------------------------
FROM maven:3.9.12-eclipse-temurin-25 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
RUN mvn clean package
# Run stage
# Run stage ---------------------------------------------------------------
FROM eclipse-temurin:25-jre
WORKDIR /app
ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}
# Install curl (required for the healthcheck)
RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/api/actuator/health || exit 1

View File

@@ -1,30 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.3</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>backend</name>
<description>Demo project for Spring Boot</description>
<url/>
<url />
<licenses>
<license/>
<license />
</licenses>
<developers>
<developer/>
<developer />
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>25</java.version>
@@ -65,8 +66,23 @@
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-flyway</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -76,4 +92,4 @@
</plugins>
</build>
</project>
</project>

View File

@@ -10,8 +10,7 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173", "http://localhost:3000", "http://localhost:8081",
"http://localhost:80", "https://todo.almazlar.com") // Typical Vite/React/Docker ports
.allowedOrigins("http://localhost:5173", "https://todo.almazlar.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);

View File

@@ -11,7 +11,7 @@ import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/todos")
@RequestMapping("/todos")
public class TodoController {
private final TodoService todoService;

View File

@@ -10,7 +10,7 @@ import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/version")
@RequestMapping("/version")
public class VersionController {
@Value("${APP_VERSION:dev}")

View File

@@ -1,5 +1,7 @@
package com.todo.backend.model;
import java.time.LocalDateTime;
import jakarta.persistence.*;
@Entity
@@ -19,6 +21,9 @@ public class Todo {
@Column(nullable = false)
private boolean completed = false;
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt = LocalDateTime.now();
// Default constructor is required by JPA
public Todo() {
}
@@ -62,4 +67,9 @@ public class Todo {
public void setCompleted(boolean completed) {
this.completed = completed;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
}

View File

@@ -1,7 +1,15 @@
server.port=8080
server.servlet.context-path=/api
spring.application.name=backend
spring.datasource.url=jdbc:postgresql://localhost:5432/tododb
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
# Flyway
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.baseline-on-migrate=true
# Database
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always

View File

@@ -0,0 +1,7 @@
CREATE TABLE todos (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
completed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

View File

@@ -7,6 +7,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.test.context.ActiveProfiles;
// Spring Boot 3.4+ replaces @MockBean with @MockitoBean
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.http.MediaType;
@@ -25,6 +26,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(TodoController.class)
@ActiveProfiles("test")
public class TodoControllerTest {
@Autowired
@@ -52,7 +54,7 @@ public class TodoControllerTest {
List<Todo> todos = Arrays.asList(todo1, todo2);
when(todoService.getAllTodos()).thenReturn(todos);
mockMvc.perform(get("/api/todos"))
mockMvc.perform(get("/todos"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].title", is(todo1.getTitle())))
@@ -63,7 +65,7 @@ public class TodoControllerTest {
void getTodoById_WhenExists_ReturnsTodo() throws Exception {
when(todoService.getTodoById(1L)).thenReturn(Optional.of(todo1));
mockMvc.perform(get("/api/todos/1"))
mockMvc.perform(get("/todos/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.title", is(todo1.getTitle())))
.andExpect(jsonPath("$.id", is(1)));
@@ -73,7 +75,7 @@ public class TodoControllerTest {
void getTodoById_WhenNotExists_ReturnsNotFound() throws Exception {
when(todoService.getTodoById(99L)).thenReturn(Optional.empty());
mockMvc.perform(get("/api/todos/99"))
mockMvc.perform(get("/todos/99"))
.andExpect(status().isNotFound());
}
@@ -85,7 +87,7 @@ public class TodoControllerTest {
when(todoService.createTodo(any(Todo.class))).thenReturn(savedTodo);
mockMvc.perform(post("/api/todos")
mockMvc.perform(post("/todos")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(newTodo)))
.andExpect(status().isCreated())
@@ -101,7 +103,7 @@ public class TodoControllerTest {
when(todoService.updateTodo(eq(1L), any(Todo.class))).thenReturn(updatedTodo);
mockMvc.perform(put("/api/todos/1")
mockMvc.perform(put("/todos/1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updatedInfo)))
.andExpect(status().isOk())
@@ -115,7 +117,7 @@ public class TodoControllerTest {
when(todoService.updateTodo(eq(99L), any(Todo.class))).thenReturn(null);
mockMvc.perform(put("/api/todos/99")
mockMvc.perform(put("/todos/99")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updatedInfo)))
.andExpect(status().isNotFound());
@@ -125,7 +127,7 @@ public class TodoControllerTest {
void deleteTodo_WhenExists_ReturnsNoContent() throws Exception {
when(todoService.deleteTodo(1L)).thenReturn(true);
mockMvc.perform(delete("/api/todos/1"))
mockMvc.perform(delete("/todos/1"))
.andExpect(status().isNoContent());
}
@@ -133,7 +135,9 @@ public class TodoControllerTest {
void deleteTodo_WhenNotExists_ReturnsNotFound() throws Exception {
when(todoService.deleteTodo(99L)).thenReturn(false);
mockMvc.perform(delete("/api/todos/99"))
mockMvc.perform(delete("/todos/99"))
.andExpect(status().isNotFound());
}
}

View File

@@ -4,3 +4,4 @@ spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

View File

@@ -22,7 +22,7 @@ services:
build: ./backend
container_name: todo-backend
ports:
- "8082:8080"
- "8082:8082"
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/tododb
- SPRING_DATASOURCE_USERNAME=postgres
@@ -31,7 +31,7 @@ services:
db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
test: ["CMD-SHELL", "curl -f http://localhost:8082/api/actuator/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
@@ -39,13 +39,12 @@ services:
frontend:
build:
context: ./frontend
args:
VITE_BASE_URL: "http://localhost:8082/api"
container_name: todo-frontend
ports:
- "5173:80"
depends_on:
- backend
backend:
condition: service_healthy
volumes:

View File

@@ -7,7 +7,7 @@ COPY . .
ARG VITE_APP_VERSION=dev
ENV VITE_APP_VERSION=${VITE_APP_VERSION}
ARG VITE_BASE_URL=https://todo.almazlar.com/api
ARG VITE_BASE_URL=http://localhost:8080/api
ENV VITE_BASE_URL=${VITE_BASE_URL}
RUN npm run build

View File

@@ -74,7 +74,7 @@ const TodoList = () => {
return (
<div className="todo-wrapper">
<h1 className="title">Tasks</h1>
<h1 className="title">Tasks List</h1>
<form className="todo-form" onSubmit={handleCreate}>
<input

View File

@@ -1,58 +1,129 @@
/* Existing CSS rules */
:root {
--bg-color: #0f172a;
--panel-bg: rgba(30, 41, 59, 0.7);
--text-main: #f8fafc;
--text-muted: #94a3b8;
--accent-primary: #8b5cf6;
--accent-secondary: #ec4899;
--success: #10b981;
--danger: #ef4444;
--border-color: rgba(255, 255, 255, 0.1);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--color1: #edf0f8;
--color2: #dae1f1;
--color3: #b6c3e2;
--color4: #91a5d4;
--color5: #6c87c6;
--color6: #4769b8;
--color7: #395493;
--color8: #2b3f6e;
--color9: #1d2a49;
--color10: #0e1525;
--color11: #0a0f1a;
--color12: #e8ebfc;
--color13: #d1d7fa;
--color14: #a3aff5;
--color15: #7588f0;
--color16: #4760eb;
--color17: #1938e6;
--color18: #142db8;
--color19: #0f228a;
--color20: #0a165c;
--color21: #050b2e;
--color22: #040820;
--color23: #02081c;
--color24: #fff4e5;
--color25: #ffe9cc;
--color26: #ffd399;
--color27: #ffbd66;
--color28: #ffa733;
--color29: #ff9100;
--color30: #cc7400;
--color31: #995700;
--color32: #663a00;
--color33: #331d00;
--color34: #241400;
--color35: #eef2f7;
--color36: #dce5ef;
--color37: #bacade;
--color38: #97b0ce;
--color39: #7495be;
--color40: #527bad;
--color41: #41628b;
--color42: #314a68;
--color43: #213145;
--color44: #101923;
--color45: #0b1118;
/* New CSS Variables */
--bg-color: var(--color45);
--panel-bg: rgba(30, 41, 59, 0.7);
--text-main: var(--color24);
--text-muted: var(--color36);
--accent-primary: var(--color41);
--accent-secondary: var(--color38);
--success: var(--color39);
--danger: var(--color30);
--border-color: rgba(255, 255, 255, 0.1);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-family);
background-color: var(--bg-color);
background-image: radial-gradient(circle at top right, rgba(139, 92, 246, 0.15), transparent 40%),
radial-gradient(circle at bottom left, rgba(236, 72, 153, 0.15), transparent 40%);
color: var(--text-main);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 4rem 1rem;
font-family: var(--font-family);
background-color: var(--bg-color);
background-image: radial-gradient(circle at top right, rgba(139, 92, 246, 0.15), transparent 40%),
radial-gradient(circle at bottom left, rgba(236, 72, 153, 0.15), transparent 40%);
color: var(--text-main);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 4rem 1rem;
}
@media (max-width: 768px) {
body {
padding: 2rem 1rem;
}
body {
padding: 2rem 1rem;
}
}
@media (max-width: 480px) {
body {
padding: 0;
align-items: flex-start;
}
body {
padding: 0;
align-items: flex-start;
}
}
button {
cursor: pointer;
font-family: inherit;
border: none;
outline: none;
transition: all 0.3s ease;
cursor: pointer;
font-family: inherit;
border: none;
outline: none;
transition: all 0.3s ease;
background-color: var(--color5); /* Default background color */
color: var(--text-main);
padding: 10px 20px;
border-radius: 4px;
&:hover {
background-color: var(--color6); /* Hover state background color */
}
}
input {
font-family: inherit;
outline: none;
font-family: inherit;
outline: none;
background-color: var(--bg-color);
color: var(--text-main);
padding: 8px 12px;
border: 1px solid var(--color3);
&:focus {
border-color: var(--color4); /* Focus state border color */
}
}
h1, h2, h3 {
color: var(--color5);
}