feat(server): скелет Go-сервера с healthz, readyz и api/v1/meta

- internal/config: конфигурация из env с валидацией и дефолтами (§5.1, §9.1)
- internal/httpx: middleware (request id, slog-логи, recover, security-заголовки),
  единый формат ошибок §8.5 и лимит тела запроса
- internal/database: SQLite WAL + busy_timeout + foreign_keys, один writer
  и пул чтения, goose-миграции embedded, PRAGMA optimize по расписанию
- internal/meta: полезная нагрузка /api/v1/meta (версия, фичи, лимиты)
- internal/server: маршруты, SPA-раздача собранного клиента, OpenAPI 3.1
- cmd/glchat: точка входа с graceful shutdown и JSON-логами
- тесты: конфиг, миграции и идемпотентность, HTTP-эндпоинты, статика, 404/405
This commit is contained in:
2026-09-19 18:20:56 +03:00
parent 9839dbeede
commit 69aa98e18c
22 changed files with 1887 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
package httpx
import (
"net/http"
)
const defaultJSONBodyLimit = 1 << 20
func JSONBodyLimit(limit int64) Middleware {
if limit <= 0 {
limit = defaultJSONBodyLimit
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost, http.MethodPatch, http.MethodPut, http.MethodDelete:
r.Body = http.MaxBytesReader(w, r.Body, limit)
}
next.ServeHTTP(w, r)
})
}
}
func MethodNotAllowed(w http.ResponseWriter, _ *http.Request) {
WriteErrorStatus(w, http.StatusMethodNotAllowed, CodeBadRequest, "method not allowed")
}
func NotFound(w http.ResponseWriter, _ *http.Request) {
WriteError(w, NewError(CodeNotFound, "resource not found"))
}