package model import "time" // Admin DTOs — read-only projections served only to admins via /api/v1/admin/*. // They deliberately differ from the public-facing models: they may expose // fields (email, role, reporter identity) that the normal API hides. // AdminUser is a row in the admin users table. type AdminUser struct { ID string `json:"id"` Email *string `json:"email"` Handle string `json:"handle"` Name string `json:"name"` AvatarURL *string `json:"avatar_url"` Role string `json:"role"` Plan string `json:"plan"` EmailVerifiedAt *time.Time `json:"email_verified_at"` BannedAt *time.Time `json:"banned_at"` // AdminRole is the staff role key, nil for ordinary accounts. AdminRole *string `json:"admin_role,omitempty"` PostCount int `json:"post_count"` CreatedAt time.Time `json:"created_at"` // Connected auth methods. HasPassword means email+password login is set up; // Providers lists linked OAuth providers (e.g. "google", "facebook"). HasPassword bool `json:"has_password"` Providers []string `json:"providers"` // Effective save limits in force for this user (plan default merged with any // admin override); -1 means unlimited. The admin UI pre-fills the "Edit // limits" modal with these. BookmarkLimit int `json:"bookmark_limit"` PublicCollectionLimit int `json:"public_collection_limit"` PrivateCollectionLimit int `json:"private_collection_limit"` // Direct-disciple link. DiscipleID is the raw Mongo ObjectID stored on the // users row; DiscipleName is hydrated from Mongo by the admin service so the // panel can show who the account is linked to (nil when unlinked, or when // the id no longer resolves to a disciple document). DiscipleID *string `json:"disciple_id"` DiscipleName *string `json:"disciple_name"` } // AdminDisciple is one option in the admin panel's disciple picker — enough to // disambiguate similarly-named disciples, plus the handle of the account that // already claims it (nil when free to link). type AdminDisciple struct { ID string `json:"id"` InitiatedName string `json:"initiated_name"` Suffix string `json:"suffix"` InitiationDate *time.Time `json:"initiation_date"` InitiationPlace *string `json:"initiation_place"` // LinkedHandle is the @handle of the user already linked to this disciple, // so the picker can grey the row out instead of failing on submit. LinkedHandle *string `json:"linked_handle"` } // AdminPost is a row in the admin posts table. type AdminPost struct { ID string `json:"id"` UserID string `json:"user_id"` Caption string `json:"caption"` SourceTitle string `json:"source_title"` SourceURL string `json:"source_url"` IsHidden bool `json:"is_hidden"` DeletedAt *time.Time `json:"deleted_at"` CreatedAt time.Time `json:"created_at"` AuthorName string `json:"author_name"` AuthorHandle string `json:"author_handle"` LikesCount int `json:"likes_count"` CommentsCount int `json:"comments_count"` } // AdminCollection is a row in the admin collections table. type AdminCollection struct { ID string `json:"id"` UserID string `json:"user_id"` Title string `json:"title"` Description *string `json:"description"` IsPublic bool `json:"is_public"` ItemCount int `json:"item_count"` CreatedAt time.Time `json:"created_at"` OwnerName string `json:"owner_name"` OwnerHandle string `json:"owner_handle"` } // AdminFeedback is a row in the admin feedback table (includes the reply). type AdminFeedback struct { ID string `json:"id"` Category string `json:"category"` Message string `json:"message"` ContactEmail *string `json:"contact_email"` CreatedAt time.Time `json:"created_at"` AcknowledgedAt *time.Time `json:"acknowledged_at"` ResolvedAt *time.Time `json:"resolved_at"` RepliedAt *time.Time `json:"replied_at"` ReplyMessage *string `json:"reply_message"` AuthorHandle *string `json:"author_handle"` AuthorName *string `json:"author_name"` AuthorEmail *string `json:"author_email"` } // AdminReport is a unified projection over the three report tables // (post_reports, comment_reports, user_reports). Type says which one. type AdminReport struct { ID string `json:"id"` Type string `json:"type"` // "post" | "comment" | "user" Category string `json:"category"` Reason string `json:"reason"` CreatedAt time.Time `json:"created_at"` ResolvedAt *time.Time `json:"resolved_at"` ReporterHandle *string `json:"reporter_handle"` ReporterName *string `json:"reporter_name"` // ResolutionNote is the admin's note left when resolving (nil while open). ResolutionNote *string `json:"resolution_note"` // TargetRemoved is true when the reported content is currently removed — // a soft-deleted post/comment, or a banned account — so the UI can offer // "Undo" instead of "Delete"/"Ban". TargetRemoved bool `json:"target_removed"` // Target of the report. TargetID is the post/comment/user id; TargetText // is the post caption, comment body, or reported user's handle so the // admin sees what was flagged without a second fetch. TargetAuthorHandle // is the handle of the content's author (nil for user reports). TargetID string `json:"target_id"` TargetText *string `json:"target_text"` TargetAuthorHandle *string `json:"target_author_handle"` }