diff --git a/README.md b/README.md
index e38e1de..68fe254 100644
--- a/README.md
+++ b/README.md
@@ -36,11 +36,18 @@ cd backend
./mvnw quarkus:dev
```
-Default database settings already point to the local Docker PostgreSQL instance:
+Default database settings point to the local Docker PostgreSQL instance, including in the `dev` profile:
-- database: `timetrack`
-- user: `timetrack`
-- password: `timetrack`
+- database: `beetask`
+- user: `beetask`
+- password: `beetask`
+- JDBC URL: `jdbc:postgresql://localhost:5432/beetask`
+
+If needed, you can override them with:
+
+- `DB_URL`
+- `DB_USER`
+- `DB_PASSWORD`
Main API endpoints:
diff --git a/backend/pom.xml b/backend/pom.xml
index d7ba451..4746dd9 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -51,6 +51,10 @@
io.quarkus
quarkus-smallrye-openapi
+
+ io.quarkus
+ quarkus-smallrye-health
+
io.quarkus
quarkus-flyway
diff --git a/backend/src/main/java/net/beetechgroup/beetask/frameworks/persistence/entities/TaskEntity.java b/backend/src/main/java/net/beetechgroup/beetask/frameworks/persistence/entities/TaskEntity.java
index 7769d19..da079f0 100644
--- a/backend/src/main/java/net/beetechgroup/beetask/frameworks/persistence/entities/TaskEntity.java
+++ b/backend/src/main/java/net/beetechgroup/beetask/frameworks/persistence/entities/TaskEntity.java
@@ -3,9 +3,9 @@ package net.beetechgroup.beetask.frameworks.persistence.entities;
import java.util.List;
import jakarta.persistence.CascadeType;
-import jakarta.persistence.CollectionTable;
-import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@@ -23,6 +23,7 @@ public class TaskEntity {
private Long id;
private String title;
private String description;
+ @Enumerated(EnumType.STRING)
private TaskStatus status;
private java.time.LocalDateTime finishedAt;
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index d2d6ea4..afcf60d 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -3,22 +3,18 @@ quarkus.http.cors=true
quarkus.http.cors.origins=http://localhost:5173
quarkus.datasource.db-kind=postgresql
-quarkus.datasource.username=${DB_USER:timetrack}
-quarkus.datasource.password=${DB_PASSWORD:timetrack}
-quarkus.datasource.jdbc.url=${DB_URL:jdbc:postgresql://localhost:5432/timetrack}
+quarkus.datasource.username=${DB_USER:beetask}
+quarkus.datasource.password=${DB_PASSWORD:beetask}
+quarkus.datasource.jdbc.url=${DB_URL:jdbc:postgresql://localhost:5432/beetask}
-%dev.quarkus.datasource.db-kind=h2
-%dev.quarkus.datasource.jdbc.url=jdbc:h2:file:./data/beetask;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE
-%dev.quarkus.h2.console=true
-%dev.quarkus.hibernate-orm.database.generation=update
-
-quarkus.flyway.migrate-at-start=false
+quarkus.flyway.migrate-at-start=true
quarkus.hibernate-orm.database.generation=validate
# Swagger & OpenAPI
quarkus.smallrye-openapi.path=/openapi
quarkus.swagger-ui.path=/swagger
quarkus.swagger-ui.always-include=true
+quarkus.smallrye-health.root-path=/status
# JWT Security
mp.jwt.verify.issuer=https://beetech.net
diff --git a/backend/src/main/resources/db/migration/V1__create_tasks.sql b/backend/src/main/resources/db/migration/V1__create_tasks.sql
deleted file mode 100644
index 0895825..0000000
--- a/backend/src/main/resources/db/migration/V1__create_tasks.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-CREATE TABLE tasks (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- title VARCHAR(255) NOT NULL,
- description VARCHAR(2000),
- status VARCHAR(32) NOT NULL,
- project VARCHAR(255)
-);
-
-CREATE TABLE task_activities (
- task_id BIGINT NOT NULL,
- activity VARCHAR(255),
- CONSTRAINT fk_task_activities_task FOREIGN KEY (task_id) REFERENCES tasks (id)
-);
diff --git a/backend/src/main/resources/db/migration/V1__first_version.sql b/backend/src/main/resources/db/migration/V1__first_version.sql
new file mode 100644
index 0000000..40e4cba
--- /dev/null
+++ b/backend/src/main/resources/db/migration/V1__first_version.sql
@@ -0,0 +1,82 @@
+CREATE TABLE users_entity (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ photo VARCHAR(1000),
+ CONSTRAINT uk_users_entity_email UNIQUE (email)
+);
+
+CREATE TABLE organizations (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(255) NOT NULL
+);
+
+CREATE TABLE projects (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ organization_id BIGINT,
+ CONSTRAINT fk_projects_organization
+ FOREIGN KEY (organization_id) REFERENCES organizations (id)
+);
+
+CREATE TABLE user_organizations (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ user_id BIGINT,
+ organization_id BIGINT,
+ role VARCHAR(32),
+ status VARCHAR(32),
+ CONSTRAINT fk_user_organizations_user
+ FOREIGN KEY (user_id) REFERENCES users_entity (id),
+ CONSTRAINT fk_user_organizations_organization
+ FOREIGN KEY (organization_id) REFERENCES organizations (id),
+ CONSTRAINT uk_user_organizations_user_org UNIQUE (user_id, organization_id),
+ CONSTRAINT chk_user_organizations_role
+ CHECK (role IN ('OWNER', 'ADMIN', 'MEMBER')),
+ CONSTRAINT chk_user_organizations_status
+ CHECK (status IN ('PENDING', 'ACTIVE', 'REJECTED'))
+);
+
+CREATE TABLE project_users (
+ project_id BIGINT NOT NULL,
+ user_id BIGINT NOT NULL,
+ CONSTRAINT pk_project_users PRIMARY KEY (project_id, user_id),
+ CONSTRAINT fk_project_users_project
+ FOREIGN KEY (project_id) REFERENCES projects (id),
+ CONSTRAINT fk_project_users_user
+ FOREIGN KEY (user_id) REFERENCES users_entity (id)
+);
+
+CREATE TABLE tasks (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ title VARCHAR(255),
+ description VARCHAR(255),
+ status VARCHAR(32),
+ finished_at TIMESTAMP(6),
+ project_id BIGINT,
+ user_id BIGINT,
+ CONSTRAINT fk_tasks_project
+ FOREIGN KEY (project_id) REFERENCES projects (id),
+ CONSTRAINT fk_tasks_user
+ FOREIGN KEY (user_id) REFERENCES users_entity (id),
+ CONSTRAINT chk_tasks_status
+ CHECK (status IN ('NOT_STARTED', 'IN_PROGRESS', 'COMPLETED', 'CANCELED'))
+);
+
+CREATE TABLE task_history (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ start_at TIMESTAMP(6),
+ end_at TIMESTAMP(6),
+ task_id BIGINT,
+ CONSTRAINT fk_task_history_task
+ FOREIGN KEY (task_id) REFERENCES tasks (id)
+);
+
+CREATE INDEX idx_projects_organization_id ON projects (organization_id);
+CREATE INDEX idx_user_organizations_user_id ON user_organizations (user_id);
+CREATE INDEX idx_user_organizations_organization_id ON user_organizations (organization_id);
+CREATE INDEX idx_project_users_user_id ON project_users (user_id);
+CREATE INDEX idx_tasks_project_id ON tasks (project_id);
+CREATE INDEX idx_tasks_user_id ON tasks (user_id);
+CREATE INDEX idx_tasks_status ON tasks (status);
+CREATE INDEX idx_task_history_task_id ON task_history (task_id);
diff --git a/backend/src/main/resources/import.sql b/backend/src/main/resources/import.sql
index 16aa523..e69de29 100644
--- a/backend/src/main/resources/import.sql
+++ b/backend/src/main/resources/import.sql
@@ -1,6 +0,0 @@
--- This file allow to write SQL commands that will be emitted in test and dev.
--- The commands are commented as their support depends of the database
--- insert into myentity (id, field) values(1, 'field-1');
--- insert into myentity (id, field) values(2, 'field-2');
--- insert into myentity (id, field) values(3, 'field-3');
--- alter sequence myentity_seq restart with 4;
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index aea32f1..41b8182 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,40 +1,21 @@
services:
postgres:
image: postgres:18.3
- container_name: timetrack-postgres
+ container_name: bee-task-postgres
environment:
- POSTGRES_USER: timetrack
- POSTGRES_PASSWORD: timetrack
- POSTGRES_DB: timetrack
+ POSTGRES_USER: beetask
+ POSTGRES_PASSWORD: beetask
+ POSTGRES_DB: beetask
ports:
- "5432:5432"
volumes:
- - postgres_data:/var/lib/postgresql
+ - postgres_data:/var/lib/postgresql/data
- ./docker/postgres/init:/docker-entrypoint-initdb.d
healthcheck:
- test: ["CMD-SHELL", "pg_isready -U timetrack"]
+ test: ["CMD-SHELL", "pg_isready -U beetask"]
interval: 10s
timeout: 5s
retries: 5
- keycloak:
- image: quay.io/keycloak/keycloak:26.6.1
- container_name: timetrack-keycloak
- command: start-dev
- environment:
- KEYCLOAK_ADMIN: admin
- KEYCLOAK_ADMIN_PASSWORD: admin
- KC_DB: postgres
- KC_DB_URL_HOST: postgres
- KC_DB_URL_PORT: 5432
- KC_DB_URL_DATABASE: keycloak
- KC_DB_USERNAME: timetrack
- KC_DB_PASSWORD: timetrack
- ports:
- - "8081:8080"
- depends_on:
- postgres:
- condition: service_healthy
-
volumes:
postgres_data: