diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7fcbe42 --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# Database settings +DATABASE_USERNAME= +DATABASE_PASSWORD= +DATABASE_HOST= +DATABASE_PORT= +DATABASE_NAME= + +# Application settings +SPRING_PROFILES_ACTIVE=dev # OR: prod \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2f43530..95f1929 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,15 @@ +HELP.md target/ +!**/src/main/**/target/ +!**/src/test/**/target/ + +.env +!.env.example + +### Maven ### +.mvn +mvnw +mvnw.cmd pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup @@ -6,12 +17,31 @@ pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties -.mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar -.mvn/wrapper/maven-wrapper.jar -# Eclipse m2e generated files -# Eclipse Core -.project -# JDT-specific (Eclipse Java Development Tools) +### STS ### +.apt_generated .classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9c95e7a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM maven:3.9.9-eclipse-temurin-24 AS build +WORKDIR /app +COPY src ./src +COPY pom.xml ./ +RUN mvn -f ./pom.xml clean package -DskipTests + +FROM eclipse-temurin:24-jdk +WORKDIR /app +COPY --from=build /app/target/*.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/README.md b/README.md index bdb7e76..e1fc399 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,199 @@ -# devlink-backend-java +# DevLink Backend + +> see also: [DevLink Frontend](https://github.com/DevLink-dev/devlink-frontend-svelte)! + Backend for the DevLink platform - developed with Java Spring + +## Description + +The DevLink Backend allows developers to link up and share project ideas to work on as a community. + +This project provides a REST API that allows users to create and manage their own profiles. +They can also create, manage and join projects to work on as a community. +This allows developers to link up all around the world and learn new skills that will help them master coding and get the job they want. + +This project is developed using the [Java Spring Framework](https://spring.io). +It allows the use of [well-established tools](https://spring.io/projects) included in it. +This reduces the amount of work required to implement new features. +Using a widespread high-level language like Java also assures that the project is easy to maintain and update. +Tools like [Lombok](https://projectlombok.org/) are used to reduce boilerplate code. + +## Technology Overview + +- [Java Spring](https://spring.io/) for dependency injection + - [Spring Boot](https://spring.io/projects/spring-boot) as REST web server + - [Spring Data JPA](https://spring.io/projects/spring-data-jpa) as ORM +- [PostgreSQL](https://www.postgresql.org/) as DBMS +- [Lombok](https://projectlombok.org/) for boilerplate code reduction +- [Log4j 2](https://logging.apache.org/log4j/2.x/) for logging +- Unit testing: + - [JUnit](https://junit.org/junit5/) as testing framework + - [AssertJ](https://assertj.github.io/doc/) for assertions + - [mockito](https://site.mockito.org/) for mocking + - [Instancio](https://www.instancio.org/) for test data generation + +## Installation and Usage + +1. Have [Docker](https://www.docker.com/) set up and running +2. Clone the repository, e.g. with: + ```sh + git clone https://github.com/DevLink-dev/devlink-backend-java.git + cd devlink-backend-java + ``` +3. Make a **copy** of [`.env.example`](.env.example) and rename it to `.env` (will be git-ignored) +4. Add your environment secrets to [`.env`](.env) (will be used by both the database and the Spring application) +5. Start Docker containers for database and Spring application: + ```sh + docker compose up -d + ``` + +To use this project, it is advised to use the corresponding [Frontend](https://github.com/DevLink-dev/devlink-frontend-svelte). + +## Development + +This project is developed following the conventions listed below. + +### Conventions + +The following are lists of conventions that either *should* be followed or *must* be followed when contributing to this project. + +#### Java + +- URLs must be `kebab-case` +- Packages: + - Names must be `snake_case` +- Classes: + - Names must be `PascalCase` + - Annotations should have the following order: + - Spring: + - Bean type (`@Component`, `@Configuration`, `@RestController`, `@Service`, ...) + - JPA: + - `@Entity` + - Constraints (`@UniqueConstraint`, ...) + - Lombok: + - constructors: + - `@AllArgsConstructor` + - `@NoArgsConstructor` + - `@RequiredArgsConstructor` + - `@Getter` + - `@Setter` + - `@EqualsAndHashCode` + - ... + - Should be structured as follows: + - `static` constants and variables + - Instance attributes + - Constructors + - `static` functions + - Instance methods +- Interfaces: + - Names must begin with `I` and continue in `PascalCase` +- `static` Constants: + - Names must be `SCREAMING_SNAKE_CASE` +- Instance Attributes and Method Parameters: + - Names must be `camelCase` + - Should be `final` unless there is a reason to change +- Methods: + - Names must be `camelCase` + - Should be at most around **15** lines long + - Should reference down to other `private` methods unless there is a specific reason not to (top-down structure) + - Indentations should not be more than 3 levels deep (counting method indentation level in class as zero) + ```java + public class Foo { + // This is level 0. + public void bar() { + // This is level 1. + for (int i = 0; i < 10; i++) { + // This is level 2. + for (int j = 0; j < 10; j++) { + // This is level 3. + if ((i + j) % 2 == 0) { + // This is level 4 (forbidden). + break; + } + } + } + } + } + ``` +- Javadoc: + - Must be added to: + - `public` methods and functions of classes, excluding getters, setters and constructors + - Should be added to: + - all `private` members of which the purpose is not obvious or the logic is difficult to comprehend + - May be added to: + - `public static` constants + - other `private` members + - Should explain **what** the code does and maybe **why**, but never **how** +- Comments: + - Should be avoided except for Javadoc + - Necessary information regarding behavior should be added as Javadoc instead (e.g. `@apiNote`, `@implNote`, `@implSpec`) +- Lombok should be used to reduce boilerplate code and increase readability: + - Generation for: + - [Getters/Setters](https://projectlombok.org/features/GetterSetter) + - [Delegation](https://projectlombok.org/features/experimental/Delegate) + - [equals()/hashCode()](https://projectlombok.org/features/EqualsAndHashCode) + - [Constructors](https://projectlombok.org/features/constructor) + - [Copy Constructors as Setters](https://projectlombok.org/features/With) + - [toString()](https://projectlombok.org/features/ToString) + - [Builders](https://projectlombok.org/features/Builder) including with [inheritance](https://projectlombok.org/features/experimental/SuperBuilder) + - [Loggers](https://projectlombok.org/features/log): preferred is `@Log4j2` + - [Utilities](https://projectlombok.org/features/experimental/UtilityClass) + - [Exceptions](https://projectlombok.org/features/experimental/StandardException) + - Threading: + - [Synchronization](https://projectlombok.org/features/Synchronized) + - [Locking](https://projectlombok.org/features/Locked) + - Can be used to set access levels of methods ([Getters/Setters](https://projectlombok.org/features/GetterSetter) and [Constructors](https://projectlombok.org/features/constructor)) + - Can be used with annotations on methods and constructors using [onX](https://projectlombok.org/features/experimental/onX) + - Can be used to include or exclude fields for [equals()/hashCode()](https://projectlombok.org/features/EqualsAndHashCode) + - Other annotations than the ones mentioned above should not be used as some are difficult to comprehend or maintain +- Code must compile without Compiler Warnings +- Code should compile without relevant Sonar/SonarQube Warnings + +#### Git + +- There are no comments including `TODO` on the `main` or `develop` branches +- Branch names are as follows: + - features: `feature/_` + - bugs: `bugfix/_` +- Commit messages are written according to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): + - [List of Commit Types](https://github.com/pvdlg/conventional-commit-types?tab=readme-ov-file#commit-types) + +### Logging +with [Log4j 2](https://logging.apache.org/log4j/2.x/) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelUsage
TraceTrace events are used for extremely fine-grained diagnostic information, which can be helpful for tracking down very specific issues or understanding the detailed flow of a program.
DebugDebug is used for internal system events that are not necessarily observable from the outside, but useful when determining how something happened.
InfoInformation events describe things happening in the system that correspond to its responsibilities and functions.
WarnWhen service is degraded, endangered, or maybe behaving outside its expected parameters, Warning-level events are used.
ErrorWhen functionality is unavailable or expectations are broken, an Error event is used.
FatalThe most critical level, Fatal events demand immediate attention.
+ +Usage guidelines are taken from [here](https://github.com/solid-stack-solutions/voycar-backend/blob/main/README.md#logging). \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cb9c23f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + backend: + build: + dockerfile: Dockerfile + container_name: devlink-backend + environment: + SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE} + DATABASE_HOST: database + DATABASE_PORT: 5432 + DATABASE_NAME: ${DATABASE_NAME} + DATABASE_USERNAME: ${DATABASE_USERNAME} + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + ports: + - "8080:8080" + depends_on: + - database + + database: + image: postgres:17.4 + container_name: devlink-database + environment: + POSTGRES_USER: ${DATABASE_USERNAME} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + POSTGRES_DB: ${DATABASE_NAME} + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "${DATABASE_PORT}:5432" + +volumes: + postgres_data: \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a47f9d5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.5 + + + dev + devlink + 0.0.1-SNAPSHOT + DevLink + Backend for the DevLink platform - developed with Java Spring Boot + + + + + + + + + + + + + + + 24 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.9 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.postgresql + postgresql + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.instancio + instancio-junit + 5.4.1 + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/dev/devlink/DevLinkApplication.java b/src/main/java/dev/devlink/DevLinkApplication.java new file mode 100644 index 0000000..8c0308c --- /dev/null +++ b/src/main/java/dev/devlink/DevLinkApplication.java @@ -0,0 +1,13 @@ +package dev.devlink; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DevLinkApplication { + + public static void main(String[] args) { + SpringApplication.run(DevLinkApplication.class, args); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..b212557 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,14 @@ +spring: + config: + import: optional:file:.env[.properties] + application: + name: DevLink + profiles: + active: ${SPRING_PROFILES_ACTIVE} + datasource: + url: jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME} + username: ${DATABASE_USERNAME} + password: ${DATABASE_PASSWORD} + jpa: + hibernate: + ddl-auto: update \ No newline at end of file diff --git a/src/test/java/dev/devlink/DevLinkApplicationTests.java b/src/test/java/dev/devlink/DevLinkApplicationTests.java new file mode 100644 index 0000000..bc288bc --- /dev/null +++ b/src/test/java/dev/devlink/DevLinkApplicationTests.java @@ -0,0 +1,13 @@ +package dev.devlink; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DevLinkApplicationTests { + + @Test + void contextLoads() { + } + +}