chore: merge backend repo history into monorepo at backend/

git-subtree-dir: backend
git-subtree-mainline: dc11190527
git-subtree-split: acae976622
This commit is contained in:
2026-09-27 10:30:16 +03:30
67 changed files with 6835 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
package dto
// CreateOptionRequest ساخت یک گزینه‌ی جدید در یک دسته
type CreateOptionRequest struct {
Title string `json:"title" binding:"required,min=1,max=150"`
SortOrder int `json:"sort_order"`
}
// UpdateOptionRequest ویرایش یک گزینه
type UpdateOptionRequest struct {
Title *string `json:"title"`
SortOrder *int `json:"sort_order"`
IsActive *bool `json:"is_active"`
}
// UpdateCategoryRequest ویرایش تنظیمات یک دسته (مثلاً تغییر حداقل/حداکثر انتخاب)
type UpdateCategoryRequest struct {
Title *string `json:"title"`
MinSelect *int `json:"min_select"`
MaxSelect *int `json:"max_select"`
}
// CreateProfileQuestionRequest ساخت سوال جدید پروفایل
type CreateProfileQuestionRequest struct {
Text string `json:"text" binding:"required,min=3,max=255"`
SortOrder int `json:"sort_order"`
}
// UpdateProfileQuestionRequest ویرایش سوال پروفایل
type UpdateProfileQuestionRequest struct {
Text *string `json:"text"`
SortOrder *int `json:"sort_order"`
IsActive *bool `json:"is_active"`
}
// RejectUserRequest رد کردن درخواست عضویت یک کاربر توسط ادمین (دلیل الزامی است)
type RejectUserRequest struct {
Reason string `json:"reason" binding:"required,min=3,max=500"`
}
// BlockUserRequest بلاک کردن یک کاربر توسط ادمین (دلیل الزامی است)
type BlockUserRequest struct {
Reason string `json:"reason" binding:"required,min=3,max=500"`
}
// ReportUserRequest ثبت یک یادداشت نظارتی روی یک کاربر (دلیل الزامی است)
type ReportUserRequest struct {
Reason string `json:"reason" binding:"required,min=3,max=500"`
}
+64
View File
@@ -0,0 +1,64 @@
package dto
import "time"
// RequestOTPRequest بدنه‌ی درخواست ارسال کد تایید
type RequestOTPRequest struct {
Phone string `json:"phone" binding:"required"`
}
// VerifyOTPRequest بدنه‌ی درخواست تایید کد
type VerifyOTPRequest struct {
Phone string `json:"phone" binding:"required"`
OTP string `json:"otp" binding:"required"`
}
// RefreshTokenRequest بدنه‌ی درخواست رفرش توکن
type RefreshTokenRequest struct {
RefreshToken string `json:"refresh_token" binding:"required"`
}
// TokenPair جفت توکن access/refresh
type TokenPair struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
// AuthResponse پاسخ استاندارد بعد از ورود موفق
type AuthResponse struct {
Tokens TokenPair `json:"tokens"`
User UserProfile `json:"user"`
IsNewUser bool `json:"is_new_user"`
OnboardingDone bool `json:"onboarding_done"`
}
// UserProfile نمایش خلاصه‌ی پروفایل کاربر (بدون داده‌های حساس)
type UserProfile struct {
ID uint `json:"id"`
Phone string `json:"phone"`
FirstName string `json:"first_name,omitempty"`
Gender *string `json:"gender,omitempty"`
BirthDate *string `json:"birth_date,omitempty"`
HeightCM *int `json:"height_cm,omitempty"`
WeightKG *int `json:"weight_kg,omitempty"`
CurrentStep int `json:"current_step"`
IsOnboarded bool `json:"is_onboarded"`
ApprovalStatus string `json:"approval_status"`
RejectionReason *string `json:"rejection_reason,omitempty"`
IsAdmin bool `json:"is_admin"`
State string `json:"state"`
BlockedReason *string `json:"blocked_reason,omitempty"`
BlockedAt *time.Time `json:"blocked_at,omitempty"`
Bio *string `json:"bio,omitempty"`
StreakCount int `json:"streak_count"`
NotifyMatches bool `json:"notify_matches"`
NotifyMessages bool `json:"notify_messages"`
NotifyLikes bool `json:"notify_likes"`
}
// UserProfileWithPhotos برای لیست‌های ادمینی که علاوه بر خلاصه‌ی پروفایل، عکس
// کاربر رو هم نشون می‌دن (مثلاً کاربران در انتظار تایید).
type UserProfileWithPhotos struct {
UserProfile
Photos []string `json:"photos"`
}
+89
View File
@@ -0,0 +1,89 @@
package dto
// DiscoverCandidate یک پروفایل پیشنهادی توی صفحه‌ی دوستیابی
type DiscoverCandidate struct {
ID uint `json:"id"`
FirstName string `json:"first_name"`
Age int `json:"age"`
Bio string `json:"bio,omitempty"`
Photos []string `json:"photos"`
DistanceKM *float64 `json:"distance_km,omitempty"`
Interests []string `json:"interests,omitempty"`
}
// SwipeRequest بدنه‌ی درخواست ثبت لایک/ردّ
type SwipeRequest struct {
Action string `json:"action" binding:"required,oneof=like pass superlike"`
}
// SwipeResponse نتیجه‌ی یک سواپ؛ اگه Matched=true باشه یعنی مچ تازه (یا از قبل) ساخته شده
type SwipeResponse struct {
Matched bool `json:"matched"`
Match *MatchView `json:"match,omitempty"`
}
// MatchView خلاصه‌ی یک مچ برای نمایش در لیست مچ‌ها/گفتگوها. برای پیش‌نمایش
// آخرین پیام، سرور رمزگشایی نمی‌کنه (نمی‌تونه) — CipherText/Nonce خودِ آخرین
// پیام رو برمی‌گردونه تا کلاینت خودش رمزگشایی کنه؛ LastMessage فقط برای
// پیام‌های قدیمیِ قبل از E2EE پر می‌شه.
type MatchView struct {
ID uint `json:"id"`
UserID uint `json:"user_id"`
FirstName string `json:"first_name"`
Photos []string `json:"photos"`
CreatedAt string `json:"created_at"`
LastMessage *string `json:"last_message,omitempty"`
LastMessageCipherText *string `json:"last_message_cipher_text,omitempty"`
LastMessageNonce *string `json:"last_message_nonce,omitempty"`
LastAt *string `json:"last_at,omitempty"`
// PartnerPublicKey کلید عمومی X25519 طرف مقابل (base64) برای رمزنگاری
// سرتاسری؛ اگه طرف مقابل هنوز کلیدی ثبت نکرده باشه خالیه.
PartnerPublicKey *string `json:"partner_public_key,omitempty"`
}
// MessageView یک پیام در یک گفتگو. یا Text (پیام قدیمیِ قبل از E2EE) پر
// می‌شه، یا CipherText+Nonce (پیام رمزنگاری‌شده) — سرور خودش نمی‌دونه محتوای
// رمزنگاری‌شده چیه، فقط بین دو طرف مچ ردوبدلش می‌کنه.
type MessageView struct {
ID uint `json:"id"`
MatchID uint `json:"match_id"`
SenderID uint `json:"sender_id"`
Text string `json:"text,omitempty"`
CipherText *string `json:"cipher_text,omitempty"`
Nonce *string `json:"nonce,omitempty"`
CreatedAt string `json:"created_at"`
IsMine bool `json:"is_mine"`
}
// SendMessageRequest بدنه‌ی درخواست ارسال پیام رمزنگاری‌شده. متن خام پیام
// هیچ‌وقت به سرور نمی‌رسه؛ کلاینت قبل از ارسال با کلید عمومی طرف مقابل
// رمزنگاریش می‌کنه.
type SendMessageRequest struct {
CipherText string `json:"cipher_text" binding:"required,min=1,max=12000"`
Nonce string `json:"nonce" binding:"required,len=32"`
}
// CandidateAnswer پاسخ یک سوال پروفایل، برای نمایش عمومی
type CandidateAnswer struct {
Question string `json:"question"`
Answer string `json:"answer"`
}
// CandidateDetail پروفایل کامل یک کاربر دیگه (برای نمایش صفحه‌ی جزئیات پروفایل)
type CandidateDetail struct {
ID uint `json:"id"`
FirstName string `json:"first_name"`
Age int `json:"age"`
Bio string `json:"bio,omitempty"`
Photos []string `json:"photos"`
DistanceKM *float64 `json:"distance_km,omitempty"`
HeightCM *int `json:"height_cm,omitempty"`
WeightKG *int `json:"weight_kg,omitempty"`
Education string `json:"education,omitempty"`
FieldOfStudy string `json:"field_of_study,omitempty"`
Occupations []string `json:"occupations,omitempty"`
Interests []string `json:"interests,omitempty"`
ImportantInRelationship []string `json:"important_in_relationship,omitempty"`
LookingFor string `json:"looking_for,omitempty"`
Answers []CandidateAnswer `json:"profile_answers,omitempty"`
}
+56
View File
@@ -0,0 +1,56 @@
package dto
// BasicInfoRequest مرحله ۱: جنسیت، اسم کوچک، تاریخ تولد
type BasicInfoRequest struct {
Gender string `json:"gender" binding:"required,oneof=male female"`
FirstName string `json:"first_name" binding:"required,min=2,max=50"`
// فرمت: YYYY-MM-DD
BirthDate string `json:"birth_date" binding:"required"`
}
// BodyInfoRequest مرحله ۲: قد و وزن
type BodyInfoRequest struct {
HeightCM int `json:"height_cm" binding:"required,min=100,max=250"`
WeightKG int `json:"weight_kg" binding:"required,min=30,max=250"`
}
// ProfileQuestionAnswerInput یک جفت (سوال انتخاب‌شده، پاسخ) از سوالات پروفایل
type ProfileQuestionAnswerInput struct {
QuestionID uint `json:"question_id" binding:"required"`
Answer string `json:"answer" binding:"required,min=1,max=1000"`
}
// ProfileQuestionsRequest مرحله ۳: دقیقاً ۳ سوال انتخابی همراه با پاسخ
type ProfileQuestionsRequest struct {
Answers []ProfileQuestionAnswerInput `json:"answers" binding:"required,len=3,dive"`
}
// EducationRequest مرحله ۴: سطح تحصیلات + رشته تحصیلی (هر دو از لیست‌های ادمین)
type EducationRequest struct {
EducationLevelOptionID uint `json:"education_level_option_id" binding:"required"`
FieldOfStudyOptionID uint `json:"field_of_study_option_id" binding:"required"`
}
// OptionSelectionRequest برای مراحلی که فقط یک لیست از option_id ارسال می‌شود
// (کارها، اهمیت‌های رابطه، علاقه‌مندی‌ها، دنبال چی می‌گردی)
type OptionSelectionRequest struct {
OptionIDs []uint `json:"option_ids" binding:"required,min=1,dive"`
}
// OnboardingStatusResponse وضعیت فعلی آنبوردینگ کاربر
type OnboardingStatusResponse struct {
CurrentStep int `json:"current_step"`
CurrentStepKey string `json:"current_step_key"`
IsOnboarded bool `json:"is_onboarded"`
// ApprovalStatus بعد از تکمیل آنبوردینگ معنا پیدا می‌کنه: pending/approved/rejected.
// وقتی pending هست، اپ باید صفحه‌ی «در انتظار تایید ادمین» رو نشون بده.
ApprovalStatus string `json:"approval_status"`
RejectionReason *string `json:"rejection_reason,omitempty"`
Steps []StepView `json:"steps"`
}
type StepView struct {
Step int `json:"step"`
Key string `json:"key"`
Done bool `json:"done"`
}
+32
View File
@@ -0,0 +1,32 @@
package dto
// UpdateLocationRequest به‌روزرسانی موقعیت مکانی کاربر (برای محاسبه‌ی فاصله‌ی تقریبی)
type UpdateLocationRequest struct {
Latitude float64 `json:"latitude" binding:"required"`
Longitude float64 `json:"longitude" binding:"required"`
}
// UpdateBioRequest ویرایش بیوگرافی کوتاه پروفایل
type UpdateBioRequest struct {
Bio string `json:"bio" binding:"max=300"`
}
// CheckInResult نتیجه‌ی ثبت ورود روزانه (برای استریک گیمیفیکیشن)
type CheckInResult struct {
StreakCount int `json:"streak_count"`
IsNewToday bool `json:"is_new_today"`
}
// UpdateNotificationSettingsRequest ترجیحات اعلان کاربر
type UpdateNotificationSettingsRequest struct {
NotifyMatches bool `json:"notify_matches"`
NotifyMessages bool `json:"notify_messages"`
NotifyLikes bool `json:"notify_likes"`
}
// UpdatePublicKeyRequest ثبت/به‌روزرسانی کلید عمومی X25519 کاربر برای
// رمزنگاری سرتاسری پیام‌ها. کلید باید دقیقاً ۳۲ بایت خام باشه که به‌صورت
// base64 استاندارد (۴۴ کاراکتر، شامل padding) کدگذاری شده.
type UpdatePublicKeyRequest struct {
PublicKey string `json:"public_key" binding:"required,len=44"`
}