Skip to content

Commit f9bf79e

Browse files
authored
Add crud (#1)
* update deps * wip * --wip-- [skip ci] * --wip-- [skip ci] * --wip-- [skip ci] * tests * without sql * update * dependabot * add frontend * lint * fix build * rm github actions (step in project * add readme * add build frontend
1 parent 50a9e5c commit f9bf79e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+7787
-56
lines changed

.editorconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
indent_style = space
8+
indent_size = 2
9+
end_of_line = lf
10+
charset = utf-8
11+
trim_trailing_whitespace = true
12+
insert_final_newline = true
13+
14+
[Makefile]
15+
indent_style = tab
16+
17+
[*.java]
18+
indent_size = 4
19+
20+
[*.md]
21+
indent_size = 4

Makefile

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
test:
22
./gradlew test
33

4+
start: run
5+
46
run:
5-
./gradlew run
7+
./gradlew bootRun
68

79
update-gradle:
8-
./gradlew wrapper --gradle-version 9.1.0
10+
./gradlew wrapper --gradle-version 9.2.1
911

1012
update-deps:
1113
./gradlew refreshVersions
14+
15+
install:
16+
./gradlew dependencies
17+
18+
build:
19+
./gradlew build
20+
21+
lint:
22+
./gradlew spotlessCheck
23+
24+
lint-fix:
25+
./gradlew spotlessApply
26+
27+
.PHONY: build

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Project DevOps Deploy
2+
3+
Bulletin board service.
4+
5+
The default `dev` profile uses an in-memory H2 database and seeds 10 sample bulletins through `DataInitializer`, so the API works immediately after startup.
6+
7+
API documentation is available via Swagger UI at `http://localhost:8080/swagger-ui/index.html`.
8+
9+
## Requirements
10+
11+
- JDK 21+.
12+
- Gradle 9.2.1.
13+
- PostgreSQL only if you run the `prod` profile with an external database.
14+
- Make.
15+
16+
## Running
17+
18+
### Local profile
19+
1. Start the application:
20+
```bash
21+
22+
make run
23+
```
24+
3. Explore the API:
25+
- All bulletins: `GET http://localhost:8080/api/bulletins`
26+
- Swagger UI: `http://localhost:8080/swagger-ui/index.html`
27+
28+
### Production
29+
30+
Prepare your database and export connection parameters:
31+
32+
```bash
33+
export SPRING_PROFILES_ACTIVE=prod
34+
export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/bulletins
35+
export SPRING_DATASOURCE_USERNAME=postgres
36+
export SPRING_DATASOURCE_PASSWORD=postgres
37+
```
38+
39+
Build app:
40+
41+
```bash
42+
make build
43+
java -jar build/libs/project-devops-deploy-0.0.1-SNAPSHOT.jar
44+
```
45+
46+
### Useful commands
47+
48+
See [Makefile](./Makefile)
49+
50+
## Frontend
51+
52+
### Development
53+
54+
1. Install Node.js 20 LTS (or newer) and npm 10.
55+
2. Install dependencies and start the Vite dev server:
56+
```bash
57+
cd frontend
58+
make install
59+
make start
60+
```
61+
3. The dev server proxies `/api` requests to `http://localhost:8080`, so keep the backend running via `make run` (or `./gradlew bootRun`) in another terminal.
62+
63+
### Build and serve from the Java app
64+
65+
1. Build the production bundle:
66+
```bash
67+
cd frontend
68+
make install # run once
69+
make build # outputs to frontend/dist
70+
```
71+
2. Copy the compiled assets into Spring Boot’s static resources (served from `src/main/resources/static`):
72+
```bash
73+
rm -rf src/main/resources/static
74+
mkdir -p src/main/resources/static
75+
cp -R frontend/dist/* src/main/resources/static/
76+
```
77+
3. Restart the backend (`make run`) and open `http://localhost:8080/` — the React app will now be served directly by the Java application.

build.gradle.kts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
2+
import org.gradle.api.tasks.testing.logging.TestLogEvent
3+
14
plugins {
25
application
36
alias(libs.plugins.versions)
47
alias(libs.plugins.spotless)
58
alias(libs.plugins.spring.boot)
69
alias(libs.plugins.spring.dependency.management)
10+
alias(libs.plugins.lombok)
711
}
812

913
group = "com.example"
@@ -26,25 +30,51 @@ repositories {
2630

2731
dependencies {
2832
implementation(libs.springBootStarterWeb)
33+
implementation(libs.springBootStarterDataJpa)
34+
implementation(libs.springBootStarterValidation)
35+
implementation(libs.mapstruct)
36+
implementation(libs.instancioCore)
37+
implementation(libs.springdocOpenapi)
38+
developmentOnly(libs.springBootDevtools)
39+
annotationProcessor(libs.mapstructProcessor)
40+
compileOnly(libs.lombok)
41+
annotationProcessor(libs.lombok)
42+
annotationProcessor(libs.lombokMapstructBinding)
43+
testCompileOnly(libs.lombok)
44+
testAnnotationProcessor(libs.lombok)
45+
testAnnotationProcessor(libs.lombokMapstructBinding)
2946
// implementation "org.springframework.boot:spring-boot-starter"
3047
// testImplementation "org.springframework.boot:spring-boot-starter-test"
31-
// testRuntimeOnly "org.junit.platform:junit-platform-launcher"
3248
testImplementation(libs.springBootStarterTest)
3349
testImplementation(libs.springSecurityTest)
3450
testImplementation(platform(libs.junitBom))
3551
testImplementation(libs.junitJupiter)
3652
testRuntimeOnly(libs.junitPlatformLauncher)
53+
runtimeOnly("com.h2database:h2")
54+
runtimeOnly(libs.postgresql)
55+
56+
implementation(libs.jacksonDatabindNullable)
57+
implementation(libs.datafaker)
3758
}
3859

3960
tasks.test {
4061
useJUnitPlatform()
62+
testLogging {
63+
exceptionFormat = TestExceptionFormat.SHORT
64+
events = setOf(
65+
TestLogEvent.FAILED,
66+
TestLogEvent.PASSED,
67+
TestLogEvent.SKIPPED
68+
)
69+
showStandardStreams = true
70+
}
4171
}
4272

4373
spotless {
4474
java {
4575
importOrder()
4676
removeUnusedImports()
47-
eclipse().sortMembersEnabled(true)
77+
eclipse()
4878
formatAnnotations()
4979
leadingTabsToSpaces(4)
5080
}

frontend/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

frontend/Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
setup: install
2+
3+
install:
4+
npm ci
5+
6+
build:
7+
npm run build
8+
9+
start: dev
10+
11+
dev:
12+
npm run dev

frontend/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# project-devops-deploy
2+
3+
## Installation
4+
5+
Install the application dependencies by running:
6+
7+
```sh
8+
npm install
9+
```
10+
11+
## Development
12+
13+
Start the application in development mode by running:
14+
15+
```sh
16+
npm run dev
17+
```
18+
19+
## Production
20+
21+
Build the application in production mode by running:
22+
23+
```sh
24+
npm run build
25+
```
26+

frontend/eslint.config.mjs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import js from "@eslint/js";
2+
import { defineConfig, globalIgnores } from "eslint/config";
3+
import tseslint from "typescript-eslint";
4+
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
5+
import react from "eslint-plugin-react";
6+
import reactHooks from "eslint-plugin-react-hooks";
7+
import globals from "globals";
8+
9+
export default defineConfig([
10+
globalIgnores(["**/node_modules", "**/dist"]),
11+
{
12+
name: "eslint-js-recommended-rules",
13+
plugins: {
14+
js,
15+
},
16+
extends: ["js/recommended"],
17+
},
18+
tseslint.configs.recommended.map((conf) => ({
19+
...conf,
20+
files: ["**/*.ts", "**/*.tsx"],
21+
})),
22+
eslintPluginPrettierRecommended,
23+
{
24+
name: "react",
25+
...react.configs.flat.recommended,
26+
},
27+
reactHooks.configs["recommended-latest"],
28+
{
29+
languageOptions: {
30+
globals: {
31+
...globals.browser,
32+
...globals.node,
33+
},
34+
},
35+
rules: {
36+
"react/react-in-jsx-scope": "off",
37+
},
38+
settings: {
39+
react: {
40+
version: "detect",
41+
},
42+
},
43+
},
44+
]);

0 commit comments

Comments
 (0)