chore(tooling): oxlint + oxfmt frontend, lefthook gate, govulncheck (#21)

- apps/frontend: oxlint 1.85 (typescript/unicorn/oxc — no react rules,
  SolidJS), oxfmt scripts; lint script now oxlint && tsc --noEmit
- backend: gofmt; bump x/text 0.39.0, quic-go 0.59.1, pgx 5.9.2
  (govulncheck 0 reachable vulns, was 3)
- ci: go vet + govulncheck in Go job (frontend job already gates via
  lint:frontend)
- lefthook pre-push: frontend lint + gofmt + vet/test + gitleaks

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomáš DvořákandDevin authored and GitHub committed 2026-09-26 16:41:35 +02:00
1 parent 7a31f55f81
commit 1cd14046de
10 files changed
+872 -34

No files matched your search

+4 -4
View File
@@ -9,7 +9,7 @@ require (
github.com/gin-gonic/gin v1.12.0
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.9.1
github.com/jackc/pgx/v5 v5.9.2
github.com/stripe/stripe-go/v81 v81.0.0
golang.org/x/crypto v0.48.0
golang.org/x/time v0.9.0
@@ -39,14 +39,14 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/quic-go/quic-go v0.59.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
golang.org/x/arch v0.23.0 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sync v0.21.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/text v0.39.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
)
+8 -8
View File
@@ -48,8 +48,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc=
github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -75,8 +75,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -108,8 +108,8 @@ golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVo
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -117,8 +117,8 @@ golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+18 -18
View File
@@ -286,11 +286,11 @@ func TestAvailabilityHonorsTenantWideBlockedDay(t *testing.T) {
t.Fatalf("parse day: %v", err)
}
if _, err := repo.CreateBlockedDay(context.Background(), db.CreateBlockedDayParams{
TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148",
StartsAt: dayStart.UTC(),
EndsAt: dayStart.Add(26 * time.Hour).UTC(),
Kind: "blocked",
Reason: "holiday",
TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148",
StartsAt: dayStart.UTC(),
EndsAt: dayStart.Add(26 * time.Hour).UTC(),
Kind: "blocked",
Reason: "holiday",
}); err != nil {
t.Fatalf("create blocked day: %v", err)
}
@@ -709,16 +709,16 @@ func TestCreateArmsSmsReminderWhenEnabled(t *testing.T) {
}
}
resp, err := service.Create(ctx, domain.CreateBookingRequest{
TenantSlug: "studio-atelier",
BookingMode: "appointment",
ServiceID: slot.ServiceID,
StaffID: slot.StaffID,
LocationID: slot.LocationID,
CustomerName: "SMS Test",
CustomerEmail: "[email protected]",
CustomerPhone: "+420777123456",
StartsAt: slot.StartsAt,
EndsAt: slot.EndsAt,
TenantSlug: "studio-atelier",
BookingMode: "appointment",
ServiceID: slot.ServiceID,
StaffID: slot.StaffID,
LocationID: slot.LocationID,
CustomerName: "SMS Test",
CustomerEmail: "[email protected]",
CustomerPhone: "+420777123456",
StartsAt: slot.StartsAt,
EndsAt: slot.EndsAt,
})
if err != nil {
t.Fatalf("create: %v", err)
@@ -830,9 +830,9 @@ func TestStaffMetricsAggregatesPerStaff(t *testing.T) {
}
seed(-5, "confirmed", true)
seed(-3, "confirmed", true) // already ended → completed too
seed(-2, "cancelled", false) // cancelled → no revenue
seed(-40, "confirmed", true) // outside the 30-day window
seed(-3, "confirmed", true) // already ended → completed too
seed(-2, "cancelled", false) // cancelled → no revenue
seed(-40, "confirmed", true) // outside the 30-day window
// Class booking (no staff) must not appear in per-staff metrics.
sessionID := "4bf74c12-44dd-45ca-86bb-b104f16f2435"
if _, err := repo.CreateBooking(ctx, db.CreateBookingParams{
+2 -2
View File
@@ -4,8 +4,8 @@ import "testing"
func TestStripeCheckoutConfigured(t *testing.T) {
cfg := Config{
StripeAPIKey: "sk_test_123",
StripeWebhookKey: "whsec_test_123",
StripeAPIKey: "sk_test_123", // gitleaks:allow — test fixture, not a real key
StripeWebhookKey: "whsec_test_123", // gitleaks:allow — test fixture, not a real key
StripePriceMatrix: map[string]map[string]string{
"starter": {"czk": "price_starter_czk", "usd": "price_starter_usd"},
"pro": {"czk": "price_pro_czk", "usd": "price_pro_usd"},
@@ -152,7 +152,6 @@ func TestExportRequiresMembership(t *testing.T) {
}
}
func TestWriteStaffReportCSV(t *testing.T) {
repo := db.NewMemoryRepository()
serviceID := "d5d76a61-3d49-467c-8dd4-bf61ee754e39"
+9
View File
@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"ignorePatterns": ["dist/**", "node_modules/**"],
"plugins": ["typescript", "unicorn", "oxc"],
"rules": {
"typescript/no-explicit-any": "warn",
"unicorn/filename-case": "off"
}
}
+5 -1
View File
@@ -7,7 +7,9 @@
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"lint": "tsc --noEmit"
"lint": "oxlint && tsc --noEmit",
"format": "oxfmt",
"format:check": "oxfmt --check"
},
"dependencies": {
"@bookra/api-client": "0.1.0",
@@ -20,6 +22,8 @@
"devDependencies": {
"@types/node": "^24.0.0",
"autoprefixer": "^10.4.20",
"oxfmt": "^0.70.0",
"oxlint": "^1.85.0",
"postcss": "^8.5.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",