-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 유저 태그 도메인 설계 및 유저 태그 생성 API #121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
328852d
479b3b6
f65b9d6
1702c6c
88eaad7
25891a8
f682e56
bbe6383
9eb0a3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package com.capturecat.core.domain.user; | ||
|
|
||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.FetchType; | ||
| import jakarta.persistence.GeneratedValue; | ||
| import jakarta.persistence.GenerationType; | ||
| import jakarta.persistence.Id; | ||
| import jakarta.persistence.JoinColumn; | ||
| import jakarta.persistence.ManyToOne; | ||
| import jakarta.persistence.Table; | ||
| import jakarta.persistence.UniqueConstraint; | ||
|
|
||
| import lombok.AccessLevel; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| import com.capturecat.core.domain.BaseTimeEntity; | ||
| import com.capturecat.core.domain.tag.Tag; | ||
|
|
||
| @Entity | ||
| @Table(name = "user_tag", | ||
| uniqueConstraints = @UniqueConstraint(name = "uk_user_tag_user_tag", columnNames = {"user_id", "tag_id"}) | ||
| ) | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| public class UserTag extends BaseTimeEntity { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "user_id") | ||
| private User user; | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "tag_id") | ||
| private Tag tag; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||||||||||||||||||||||||||||||
| create table if not exists users | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint not null primary key, | ||||||||||||||||||||||||||||||||||||||||||
| nickname varchar(50) not null, | ||||||||||||||||||||||||||||||||||||||||||
| email varchar(50) not null, | ||||||||||||||||||||||||||||||||||||||||||
| username varchar(50) not null unique, | ||||||||||||||||||||||||||||||||||||||||||
| password varchar(70), | ||||||||||||||||||||||||||||||||||||||||||
| role varchar(255) not null constraint users_role_check check (role in ('ADMIN', 'PREMIUM_USER', 'USER')), | ||||||||||||||||||||||||||||||||||||||||||
| tutorial_completed boolean not null, | ||||||||||||||||||||||||||||||||||||||||||
| provider varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| social_id varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists user_social_account | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint not null primary key, | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| provider varchar(30) not null, | ||||||||||||||||||||||||||||||||||||||||||
| social_id varchar(100) not null, | ||||||||||||||||||||||||||||||||||||||||||
| unlink_key varchar(512), | ||||||||||||||||||||||||||||||||||||||||||
| user_id bigint not null constraint fk998rgv7jn090iyc77f8e1xsnq references users, | ||||||||||||||||||||||||||||||||||||||||||
| constraint uksj2lqxj8h0xuqf9v1dvtlkegt unique (provider, social_id) | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists refresh_token | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint not null primary key, | ||||||||||||||||||||||||||||||||||||||||||
| refresh_token_expiration bigint not null, | ||||||||||||||||||||||||||||||||||||||||||
| expiration varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| refresh_token varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| username varchar(255) | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+28
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion refresh_token: ambiguous expirations and missing FK to user.
-create table if not exists refresh_token
+create table if not exists refresh_token
(
- id bigint not null primary key,
- refresh_token_expiration bigint not null,
- expiration varchar(255),
+ id bigint generated by default as identity primary key,
+ refresh_token_expiration bigint not null,
refresh_token varchar(255),
- username varchar(255)
+ username varchar(50) not null,
+ constraint fk_refresh_token_user_username foreign key (username) references users(username) on delete cascade
);If you truly need two expirations, rename with clear semantics. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists withdraw_log | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint generated by default as identity primary key, | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| image_cleanup_status varchar(255) not null constraint withdraw_log_image_cleanup_status_check check (image_cleanup_status in ('PENDING', 'DONE', 'FAILED')), | ||||||||||||||||||||||||||||||||||||||||||
| reason text, | ||||||||||||||||||||||||||||||||||||||||||
| user_id bigint not null | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion withdraw_log: add FK for user_id. Currently no FK; risks orphaned rows. create table if not exists withdraw_log
(
id bigint generated by default as identity primary key,
created_date timestamp(6) not null,
last_modified_date timestamp(6) not null,
image_cleanup_status varchar(255) not null constraint withdraw_log_image_cleanup_status_check check (image_cleanup_status in ('PENDING', 'DONE', 'FAILED')),
reason text,
- user_id bigint not null
+ user_id bigint not null constraint fk_withdraw_log_user references users
);Optionally add 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create index if not exists idx_withdraw_log_user_id on withdraw_log (user_id); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create index if not exists idx_withdraw_log_created_date on withdraw_log (created_date); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create index if not exists idx_withdraw_log_cleanup_status on withdraw_log (image_cleanup_status, created_date); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists images | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint generated by default as identity primary key, | ||||||||||||||||||||||||||||||||||||||||||
| size bigint, | ||||||||||||||||||||||||||||||||||||||||||
| file_name varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| file_url varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| capture_date date, | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| user_id bigint constraint fk13ljqfrfwbyvnsdhihwta8cpr references users | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists tag | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint generated by default as identity primary key, | ||||||||||||||||||||||||||||||||||||||||||
| name varchar(255), | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists image_tag | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint generated by default as identity primary key, | ||||||||||||||||||||||||||||||||||||||||||
| image_id bigint constraint fk6q9wuvp5j846qtqod6xu3gma1 references images, | ||||||||||||||||||||||||||||||||||||||||||
| tag_id bigint constraint fk28yowgjl7oksr7dc0wj7f5il references tag, | ||||||||||||||||||||||||||||||||||||||||||
| created_date timestamp(6) not null, | ||||||||||||||||||||||||||||||||||||||||||
| last_modified_date timestamp(6) not null | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+73
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion image_tag: prevent duplicates and add indexes.
create table if not exists image_tag
(
id bigint generated by default as identity primary key,
- image_id bigint constraint fk6q9wuvp5j846qtqod6xu3gma1 references images,
- tag_id bigint constraint fk28yowgjl7oksr7dc0wj7f5il references tag,
+ image_id bigint not null constraint fk6q9wuvp5j846qtqod6xu3gma1 references images,
+ tag_id bigint not null constraint fk28yowgjl7oksr7dc0wj7f5il references tag,
created_date timestamp(6) not null,
last_modified_date timestamp(6) not null
);
+
+create unique index if not exists uk_image_tag_image_tag on image_tag (image_id, tag_id);
+create index if not exists idx_image_tag_image_id on image_tag (image_id);
+create index if not exists idx_image_tag_tag_id on image_tag (tag_id);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| create table if not exists bookmark | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| id bigint generated by default as identity primary key, | ||||||||||||||||||||||||||||||||||||||||||
| image_id bigint constraint fkpowbsxsu0qwcon1yoxbsqkw4w references images, | ||||||||||||||||||||||||||||||||||||||||||
| user_id bigint constraint fko4vbqvq5trl11d85bqu5kl870 references users | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+82
to
+87
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion bookmark: prevent duplicates and add indexes. Enforce one bookmark per (user, image) and speed lookups. create table if not exists bookmark
(
id bigint generated by default as identity primary key,
image_id bigint constraint fkpowbsxsu0qwcon1yoxbsqkw4w references images,
user_id bigint constraint fko4vbqvq5trl11d85bqu5kl870 references users
);
+
+create unique index if not exists uk_bookmark_user_image on bookmark (user_id, image_id);
+create index if not exists idx_bookmark_image_id on bookmark (image_id);
+create index if not exists idx_bookmark_user_id on bookmark (user_id);🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,9 @@ | ||||||
| create table if not exists user_tag | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid IF NOT EXISTS in versioned migrations. Flyway migrations should be deterministic; IF NOT EXISTS can hide drift and let incompatible schemas slip through. -create table if not exists user_tag
+create table user_tagIf the table might already exist in some envs, prefer a separate repeatable migration or conditional precheck script, not IF NOT EXISTS in V2. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| ( | ||||||
| id bigint generated by default as identity primary key, | ||||||
| user_id bigint constraint fk_user_tag_user references users, | ||||||
| tag_id bigint constraint fk_user_tag_tag references tag, | ||||||
|
Comment on lines
+4
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion FKs should be NOT NULL and consider ON DELETE CASCADE. A user_tag without user/tag is invalid. Also consider cascading deletes to avoid orphans when a user/tag is removed. Option A (edit V2 before merge): - user_id bigint constraint fk_user_tag_user references users,
- tag_id bigint constraint fk_user_tag_tag references tag,
+ user_id bigint not null
+ constraint fk_user_tag_user references users(id) on delete cascade,
+ tag_id bigint not null
+ constraint fk_user_tag_tag references tag(id) on delete cascade,If V2 may already be applied locally, create V3 with: alter table user_tag
alter column user_id set not null,
alter column tag_id set not null;
alter table user_tag
drop constraint if exists fk_user_tag_user,
add constraint fk_user_tag_user foreign key (user_id) references users(id) on delete cascade;
alter table user_tag
drop constraint if exists fk_user_tag_tag,
add constraint fk_user_tag_tag foreign key (tag_id) references tag(id) on delete cascade;🤖 Prompt for AI Agents |
||||||
| created_date timestamp(6) not null, | ||||||
| last_modified_date timestamp(6) not null, | ||||||
| constraint uk_user_tag_user_tag unique (user_id, tag_id) | ||||||
| ); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Confirm BaseTimeEntity column names match DDL (created_date/last_modified_date).
If BaseTimeEntity uses camelCase without @column overrides, naming strategy must map to snake_case. Otherwise inserts will fail.
Run:
🏁 Script executed:
Length of output: 678
Explicitly define snake_case column names for audit fields
In BaseTimeEntity.java, annotate the fields with name overrides to match the DDL:
@Column(name = "created_date", nullable = false, updatable = false)@Column(name = "last_modified_date", nullable = false)🤖 Prompt for AI Agents