Documentation
¶
Overview ¶
Package api provides the HTTP API handlers for minimaldoc-server.
Index ¶
- Constants
- func AdminMiddleware() gin.HandlerFunc
- func AdminUIAuthMiddleware(cfg *config.Config) gin.HandlerFunc
- func AuthMiddleware(cfg *config.Config) gin.HandlerFunc
- func AuthorOrAboveMiddleware() gin.HandlerFunc
- func CORSMiddleware(allowedOrigins []string) gin.HandlerFunc
- func CanEditPostMiddleware() gin.HandlerFunc
- func EditorOrAboveMiddleware() gin.HandlerFunc
- func LoggerMiddleware() gin.HandlerFunc
- func OptionalAuthMiddleware(cfg *config.Config) gin.HandlerFunc
- func SecurityHeadersMiddleware() gin.HandlerFunc
- func SiteMiddleware() gin.HandlerFunc
- func TracingMiddleware() gin.HandlerFunc
- type BlogCommentRequest
- type BlogPostRequest
- type BlogPostResponse
- type BootstrapRequest
- type BootstrapResult
- type CheckAccessRequest
- type CheckAccessResponse
- type CreateDocAccessRequest
- type DocAccessRule
- type DurationRequest
- type EventRequest
- type FeedbackRequest
- type ForumBanRequest
- type ForumCategoryRequest
- type ForumCategoryResponse
- type ForumFlagRequest
- type ForumPostRequest
- type ForumPostResponse
- type ForumTagRequest
- type ForumTagResponse
- type ForumTopicRequest
- type ForumTopicResponse
- type ForumUserStatsResponse
- type LoginRequest
- type RSSChannel
- type RSSFeed
- type RSSItem
- type RegisterRequest
- type Router
- type ScheduleRequest
- type StatCard
- type SubscribeRequest
- type TableColumn
- type TableRow
- type TrackRequest
- type UpdateDocAccessRequest
Constants ¶
const ( ErrBadRequest = "BAD_REQUEST" ErrDatabaseError = "DATABASE_ERROR" ErrInternalError = "INTERNAL_ERROR" ErrForbidden = "FORBIDDEN" ErrNotFound = "NOT_FOUND" ErrConflict = "CONFLICT" ErrRateLimited = "RATE_LIMITED" ErrNotAvailable = "NOT_AVAILABLE" ErrMissingParams = "MISSING_PARAMETERS" ErrInvalidRequest = "INVALID_REQUEST" )
General
const ( ErrInvalidCredentials = "INVALID_CREDENTIALS" ErrInvalidBootstrapToken = "INVALID_BOOTSTRAP_TOKEN" ErrInvalidRefreshToken = "INVALID_REFRESH_TOKEN" ErrInvalidState = "INVALID_STATE" ErrInvalidVerifyToken = "INVALID_VERIFY_TOKEN" ErrTokenGenerationFailed = "TOKEN_GENERATION_FAILED" ErrPasswordRequired = "PASSWORD_REQUIRED" ErrPasswordTooShort = "PASSWORD_TOO_SHORT" ErrPasswordHashFailed = "PASSWORD_HASH_FAILED" ErrUserNotFound = "USER_NOT_FOUND" ErrUserAlreadyExists = "USER_ALREADY_EXISTS" ErrUserCreationFailed = "USER_CREATION_FAILED" ErrEmailVerifyFailed = "EMAIL_VERIFY_FAILED" ErrRegistrationRequired = "REGISTRATION_REQUIRED" ErrUnknownProvider = "UNKNOWN_PROVIDER" ErrOAuthLinkFailed = "OAUTH_LINK_FAILED" ErrMissingSiteContext = "MISSING_SITE_CONTEXT" ErrCannotModifySelf = "CANNOT_MODIFY_SELF" ErrInsufficientPermission = "INSUFFICIENT_PERMISSION" ErrOwnPostsOnly = "OWN_POSTS_ONLY" ErrBanned = "BANNED" )
Authentication & Authorization
const ( ErrSiteNotFound = "SITE_NOT_FOUND" ErrSiteInvalid = "SITE_INVALID" ErrSiteCreationFailed = "SITE_CREATION_FAILED" ErrSiteUpdateFailed = "SITE_UPDATE_FAILED" ErrSiteDeleteFailed = "SITE_DELETE_FAILED" ErrSiteIDRequired = "SITE_ID_REQUIRED" ErrAPIKeyGenFailed = "API_KEY_GENERATION_FAILED" ErrBootstrapDone = "BOOTSTRAP_ALREADY_DONE" )
Site
const ( ErrSubscribeFailed = "SUBSCRIBE_FAILED" ErrUnsubscribeFailed = "UNSUBSCRIBE_FAILED" ErrIDGenFailed = "ID_GENERATION_FAILED" )
Newsletter
const ( ErrPostNotFound = "POST_NOT_FOUND" ErrPostCreationFailed = "POST_CREATION_FAILED" ErrPostUpdateFailed = "POST_UPDATE_FAILED" ErrPostDeleteFailed = "POST_DELETE_FAILED" ErrPostPublishFailed = "POST_PUBLISH_FAILED" ErrSlugExists = "SLUG_EXISTS" ErrInvalidContent = "INVALID_CONTENT" ErrInvalidDatetime = "INVALID_DATETIME" ErrSchedulePastDate = "SCHEDULE_PAST_DATE" ErrCommentFailed = "COMMENT_FAILED" ErrDailyLimitReached = "DAILY_LIMIT_REACHED" ErrAuthRequired = "AUTHENTICATION_REQUIRED" )
Blog
const ( ErrTopicNotFound = "TOPIC_NOT_FOUND" ErrTopicCreationFailed = "TOPIC_CREATION_FAILED" ErrTopicClosed = "TOPIC_CLOSED" ErrCategoryNotFound = "CATEGORY_NOT_FOUND" ErrTagNotFound = "TAG_NOT_FOUND" ErrTagExists = "TAG_EXISTS" )
Forum
const ( ErrDocNotFound = "DOCUMENT_NOT_FOUND" ErrAccessDenied = "ACCESS_DENIED" ErrInvalidAPIKey = "INVALID_API_KEY" ErrInvalidPath = "INVALID_PATH" ErrPathRequired = "PATH_REQUIRED" ErrRuleNotFound = "RULE_NOT_FOUND" ErrRuleExists = "RULE_EXISTS" ErrRuleIDRequired = "RULE_ID_REQUIRED" )
Document Access
const ( ErrUploadFailed = "UPLOAD_FAILED" ErrUploadNotFound = "UPLOAD_NOT_FOUND" ErrNoFileProvided = "NO_FILE_PROVIDED" ErrStorageNotConfig = "STORAGE_NOT_CONFIGURED" ErrNotUploadOwner = "NOT_UPLOAD_OWNER" )
Upload
const (
ErrDBUnreachable = "DATABASE_UNREACHABLE"
)
Health
Variables ¶
This section is empty.
Functions ¶
func AdminMiddleware ¶
func AdminMiddleware() gin.HandlerFunc
AdminMiddleware ensures the user has admin role.
func AdminUIAuthMiddleware ¶
func AdminUIAuthMiddleware(cfg *config.Config) gin.HandlerFunc
AdminUIAuthMiddleware validates JWT for admin UI routes. Redirects to login page instead of returning JSON error.
func AuthMiddleware ¶
func AuthMiddleware(cfg *config.Config) gin.HandlerFunc
AuthMiddleware validates JWT tokens or session cookies.
func AuthorOrAboveMiddleware ¶
func AuthorOrAboveMiddleware() gin.HandlerFunc
AuthorOrAboveMiddleware requires admin, editor, or author role.
func CORSMiddleware ¶
func CORSMiddleware(allowedOrigins []string) gin.HandlerFunc
CORSMiddleware handles Cross-Origin Resource Sharing.
func CanEditPostMiddleware ¶
func CanEditPostMiddleware() gin.HandlerFunc
CanEditPostMiddleware checks if user can edit a specific post. Admin/editor can edit any post, author can only edit own posts. Requires post_id param and author_id to be fetched before this middleware.
func EditorOrAboveMiddleware ¶
func EditorOrAboveMiddleware() gin.HandlerFunc
EditorOrAboveMiddleware requires admin or editor role.
func LoggerMiddleware ¶
func LoggerMiddleware() gin.HandlerFunc
LoggerMiddleware logs HTTP requests.
func OptionalAuthMiddleware ¶
func OptionalAuthMiddleware(cfg *config.Config) gin.HandlerFunc
OptionalAuthMiddleware tries to authenticate the user but doesn't require it. If a valid token is present, it sets user info in context. If not, it continues without setting user info (for anonymous access).
func SecurityHeadersMiddleware ¶
func SecurityHeadersMiddleware() gin.HandlerFunc
SecurityHeadersMiddleware adds common security headers to responses.
func SiteMiddleware ¶
func SiteMiddleware() gin.HandlerFunc
SiteMiddleware validates and sets site context from user's JWT. For API key-based requests, handlers validate the key directly.
func TracingMiddleware ¶
func TracingMiddleware() gin.HandlerFunc
TracingMiddleware creates a span per HTTP request with method, path, and status attributes.
Types ¶
type BlogCommentRequest ¶
type BlogCommentRequest struct {
AuthorName string `json:"author_name" form:"author_name"`
AuthorEmail string `json:"author_email" form:"author_email"`
Content string `json:"content" form:"content" binding:"required,min=1,max=5000"`
ParentID string `json:"parent_id" form:"parent_id"`
}
BlogCommentRequest represents a comment submission. AuthorName and AuthorEmail are optional for authenticated users (auto-filled from profile).
type BlogPostRequest ¶
type BlogPostRequest struct {
Slug string `json:"slug" binding:"required"`
Title string `json:"title" binding:"required"`
Description string `json:"description"`
Content string `json:"content" binding:"required"`
FeaturedImage string `json:"featured_image"`
Tags string `json:"tags"` // JSON array string
Category string `json:"category"`
Visibility string `json:"visibility"` // public, authenticated, role_viewer, role_author, role_editor, role_admin
ScheduledAt string `json:"scheduled_at"` // ISO 8601 datetime for scheduled publishing
}
BlogPostRequest represents the request body for creating/updating a blog post.
type BlogPostResponse ¶
type BlogPostResponse struct {
ID string `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
Content string `json:"content,omitempty"`
ContentHTML string `json:"content_html,omitempty"`
FeaturedImage string `json:"featured_image,omitempty"`
Tags string `json:"tags,omitempty"`
Category string `json:"category,omitempty"`
Status string `json:"status"`
Visibility string `json:"visibility"`
PublishedAt string `json:"published_at,omitempty"`
ScheduledAt string `json:"scheduled_at,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
AuthorName string `json:"author_name,omitempty"`
ReadingTime int `json:"reading_time,omitempty"`
}
BlogPostResponse is the JSON-friendly response for a blog post.
type BootstrapRequest ¶
type BootstrapRequest struct {
SiteName string `json:"site_name" binding:"required"`
Domain string `json:"domain"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password"`
BootstrapToken string `json:"bootstrap_token"`
}
BootstrapRequest represents bootstrap parameters.
type BootstrapResult ¶
type BootstrapResult struct {
SiteID string
SiteName string
APIKey string
UserID string
Email string
Password string
}
BootstrapResult contains the created site and user info.
type CheckAccessRequest ¶
type CheckAccessRequest struct {
Path string `json:"path" form:"path" binding:"required"`
}
CheckAccessRequest is the request for checking doc access.
type CheckAccessResponse ¶
type CheckAccessResponse struct {
Path string `json:"path"`
IsProtected bool `json:"is_protected"`
RequiredRole string `json:"required_role,omitempty"`
HasAccess bool `json:"has_access"`
Reason string `json:"reason,omitempty"`
}
CheckAccessResponse is the response for access check.
type CreateDocAccessRequest ¶
type CreateDocAccessRequest struct {
PathPattern string `json:"path_pattern" binding:"required"`
RequiredRole string `json:"required_role" binding:"required,oneof=viewer author editor admin"`
Description string `json:"description"`
}
CreateDocAccessRequest is the request for creating a doc access rule.
type DocAccessRule ¶
type DocAccessRule struct {
ID string `json:"id"`
PathPattern string `json:"path_pattern"`
RequiredRole string `json:"required_role"`
Description string `json:"description,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
DocAccessRule is the API representation of a doc access rule.
type DurationRequest ¶
type DurationRequest struct {
SiteID string `json:"site_id" binding:"required,max=64"`
Path string `json:"path" binding:"required,max=512"`
Duration int `json:"duration" binding:"required,min=1,max=3600"`
SessionHash string `json:"session_hash" binding:"max=64"`
IsBounce *bool `json:"is_bounce"`
}
DurationRequest represents a page duration update.
type EventRequest ¶
type EventRequest struct {
SiteID string `json:"site_id" binding:"required,max=64"`
Name string `json:"name" binding:"required,max=128"`
Category string `json:"category" binding:"max=64"`
Path string `json:"path" binding:"max=512"`
Value string `json:"value" binding:"max=1024"`
SessionHash string `json:"session_hash" binding:"max=64"`
}
EventRequest represents a custom event tracking request.
type FeedbackRequest ¶
type FeedbackRequest struct {
SiteID string `json:"site_id" binding:"required"`
Path string `json:"path" binding:"required"`
Rating int `json:"rating" binding:"required,min=1,max=5"`
Feedback string `json:"feedback"`
SessionHash string `json:"session_hash"`
}
FeedbackRequest represents a feedback submission.
type ForumBanRequest ¶
type ForumCategoryRequest ¶
type ForumCategoryRequest struct {
Slug string `json:"slug" binding:"required"`
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Color string `json:"color"`
Icon string `json:"icon"`
Position int `json:"position"`
ParentID string `json:"parent_id"`
IsLocked bool `json:"is_locked"`
}
type ForumCategoryResponse ¶
type ForumCategoryResponse struct {
ID string `json:"id"`
Slug string `json:"slug"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Color string `json:"color,omitempty"`
Icon string `json:"icon,omitempty"`
Position int `json:"position"`
IsLocked bool `json:"is_locked"`
TopicCount int64 `json:"topic_count"`
PostCount int64 `json:"post_count"`
ParentID string `json:"parent_id,omitempty"`
Children []ForumCategoryResponse `json:"children,omitempty"`
CreatedAt string `json:"created_at"`
}
type ForumFlagRequest ¶
type ForumPostRequest ¶
type ForumPostResponse ¶
type ForumPostResponse struct {
ID string `json:"id"`
TopicID string `json:"topic_id"`
Content string `json:"content"`
ContentHTML string `json:"content_html"`
LikeCount int64 `json:"like_count"`
IsSolution bool `json:"is_solution"`
ParentID string `json:"parent_id,omitempty"`
AuthorID string `json:"author_id,omitempty"`
AuthorName string `json:"author_name,omitempty"`
AuthorAvatar string `json:"author_avatar,omitempty"`
EditedAt string `json:"edited_at,omitempty"`
EditorName string `json:"editor_name,omitempty"`
CreatedAt string `json:"created_at"`
IsLiked bool `json:"is_liked,omitempty"`
}
type ForumTagRequest ¶
type ForumTagResponse ¶
type ForumTopicRequest ¶
type ForumTopicResponse ¶
type ForumTopicResponse struct {
ID string `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
Content string `json:"content,omitempty"`
ContentHTML string `json:"content_html,omitempty"`
Status string `json:"status"`
IsPinned bool `json:"is_pinned"`
IsSolved bool `json:"is_solved"`
ViewCount int64 `json:"view_count"`
LikeCount int64 `json:"like_count"`
PostCount int64 `json:"post_count"`
CategoryID string `json:"category_id,omitempty"`
CategoryName string `json:"category_name,omitempty"`
CategorySlug string `json:"category_slug,omitempty"`
AuthorID string `json:"author_id,omitempty"`
AuthorName string `json:"author_name,omitempty"`
AuthorAvatar string `json:"author_avatar,omitempty"`
Tags []string `json:"tags,omitempty"`
LastPostAt string `json:"last_post_at,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
IsLiked bool `json:"is_liked,omitempty"`
IsBookmarked bool `json:"is_bookmarked,omitempty"`
}
type ForumUserStatsResponse ¶
type ForumUserStatsResponse struct {
UserID string `json:"user_id"`
UserName string `json:"user_name"`
UserAvatar string `json:"user_avatar,omitempty"`
Reputation int64 `json:"reputation"`
TopicCount int64 `json:"topic_count"`
PostCount int64 `json:"post_count"`
LikesGiven int64 `json:"likes_given"`
LikesRecv int64 `json:"likes_received"`
}
type LoginRequest ¶
type LoginRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required"`
SiteID string `json:"site_id" binding:"required"`
}
LoginRequest represents login credentials.
type RSSChannel ¶
type RSSFeed ¶
type RSSFeed struct {
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
Channel RSSChannel `xml:"channel"`
}
RSS Feed structures
type RegisterRequest ¶
type RegisterRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=8"`
Name string `json:"name"`
SiteID string `json:"site_id" binding:"required"`
}
RegisterRequest represents public registration parameters.
type Router ¶
Router wraps the Gin engine with dependencies.
func NewAdminRouter ¶
func NewAdminRouter(cfg *config.Config, db store.Store, emailSender email.Sender, store storage.Storage) *Router
NewAdminRouter creates the admin API and UI router. This handles: authentication, dashboard, management APIs. Should be on a separate port, not publicly accessible.
func NewPublicRouter ¶
NewPublicRouter creates the public-facing API router. This handles: tracking, feedback submission, newsletter subscribe. No authentication required, no admin access.
type ScheduleRequest ¶
type ScheduleRequest struct {
ScheduledAt string `json:"scheduled_at" binding:"required"` // ISO 8601 datetime
}
ScheduleRequest represents the request to schedule a post.
type SubscribeRequest ¶
type SubscribeRequest struct {
SiteID string `json:"site_id" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
SubscribeRequest represents a newsletter subscription request.
type TableColumn ¶
TableColumn defines a column in a data table.
type TrackRequest ¶
type TrackRequest struct {
SiteID string `json:"site_id" binding:"required,max=64"`
Path string `json:"path" binding:"required,max=512"`
Referrer string `json:"referrer" binding:"max=1024"`
Country string `json:"country" binding:"max=8"`
DeviceType string `json:"device_type" binding:"max=16"`
Browser string `json:"browser" binding:"max=64"`
OS string `json:"os" binding:"max=64"`
SessionHash string `json:"session_hash" binding:"max=64"`
}
TrackRequest represents a page view tracking request.
type UpdateDocAccessRequest ¶
type UpdateDocAccessRequest struct {
PathPattern string `json:"path_pattern" binding:"required"`
RequiredRole string `json:"required_role" binding:"required,oneof=viewer author editor admin"`
Description string `json:"description"`
}
UpdateDocAccessRequest is the request for updating a doc access rule.
Source Files
¶
- bootstrap.go
- errors.go
- fragments.go
- fragments_audit.go
- fragments_blog.go
- fragments_blog_public.go
- fragments_docs.go
- fragments_forum.go
- fragments_users.go
- handlers.go
- handlers_admin.go
- handlers_analytics.go
- handlers_audit.go
- handlers_auth.go
- handlers_blog.go
- handlers_docs.go
- handlers_feedback.go
- handlers_forum.go
- handlers_newsletter.go
- handlers_sites.go
- handlers_upload.go
- handlers_users.go
- helpers.go
- middleware.go
- router.go