chore: wire APP_OPENAI_MODEL and upgrade Go/deps

This commit is contained in:
Ruidy 2026-02-18 18:25:34 +01:00
parent 584d81f7bd
commit df1cd66cf1
No known key found for this signature in database
GPG key ID: 705C24D202990805
13 changed files with 69 additions and 71 deletions

View file

@ -1,11 +1,12 @@
DATABASE_URL=
DEBUG=
LOG_LEVEL=
ORIGINS=
PORT=
SENTRY_DSN=
ADMIN=
ADMIN_SECRET=
API_KEY=
SECRET_KEY=
SESSION_SECRET=
APP_DATABASE_URL=
APP_DEBUG=
APP_LOG_LEVEL=
APP_ORIGINS=
APP_PORT=
APP_SENTRY_DSN=
APP_ADMIN=
APP_ADMIN_SECRET=
APP_API_KEY=
APP_SECRET_KEY=
APP_SESSION_SECRET=
APP_OPENAI_MODEL=gpt-5-nano

View file

@ -1,52 +1,43 @@
# Repository Guidelines
## Project Structure & Module Organization
- `main.go`: Application entrypoint (HTTP server on `:8000`).
- `internal/`: Private app code (e.g., `server/`, `service/`, `repository/`, `driver/`,
`config/`, `view/`). Templ views live in `internal/view` and generate `*_templ.go`.
- `pkg/`: Reusable packages shared across app layers.
- `cmd/`: Optional binaries/entrypoints.
- `assets/`: Static assets and images.
- `docs/`: Project documentation.
- `scripts/`, `tmp/`: Dev tooling and build artifacts (Air uses `tmp/`).
- `main.go`: application entrypoint (HTTP server).
- `internal/`: core app code by layer:
- `server/` (HTTP handlers/routes), `service/` (business logic), `repository/` (data access), `driver/` (external integrations), `config/` (env config), `view/` (templ views/viewmodels).
- `internal/view/*.templ` are source templates; generated files are `internal/view/*_templ.go`.
- `cmd/cron/`: cron entrypoint.
- `assets/`: static assets. `docs/`: documentation/images. `scripts/` and `tmp/`: tooling/artifacts.
- Tests live next to code as `*_test.go`.
## Build, Test, and Development Commands
- `make dev`: Start dev container with live reload (Air) on `http://localhost:8000`.
- `make run`: Build and run the Docker image with `PORT` and `DATABASE_URL`.
- `make test`: Run `go test ./...` inside the running dev container.
- `make format`: Run `templ generate`, `templ fmt`, and `go fmt`.
- `make lint`: Run `golangci-lint`.
- Local alternative: `air -c .air.toml`, `go test ./...`, `go run .`.
- `make dev`: run local dev stack with Docker Compose and hot reload.
- `make run`: build and run production image locally.
- `make test`: run `go test ./...`.
- `make format`: run `templ generate`, `templ fmt`, and `go fmt`.
- `make lint`: run `golangci-lint run ./...`.
- `make stop`: stop dev containers.
- Local (without Docker): `go run .`, `go test ./...`.
## Coding Style & Naming Conventions
- Go formatting: Use `go fmt` (tabs, standard import ordering). CI helpers:
`make format`.
- Linting: `golangci-lint run ./...` via `make lint` (fix issues before PR).
- Packages: lowercase, no underscores; files: lowercase with underscores; exported
identifiers: `PascalCase`; unexported: `camelCase`.
- Templ: keep `.templ` in `internal/view`; commit sources, not generated `*_templ.go`.
- Go style is standard `go fmt` (tabs, canonical imports).
- Package names: lowercase, no underscores.
- File names: lowercase with underscores when needed.
- Exported identifiers: `PascalCase`; unexported: `camelCase`.
- Keep handler/controller code thin; place business rules in `internal/service`.
## Testing Guidelines
- Framework: standard `testing` with table-driven tests.
- Files: `*_test.go`; functions: `TestXxx`, benchmarks: `BenchmarkXxx`.
- Run: `make test` (in container) or `go test ./...` locally.
- Aim for meaningful coverage on new/changed code; include error paths.
- Use Go `testing` with table-driven tests where practical.
- Name files `*_test.go`; tests `TestXxx`; benchmarks `BenchmarkXxx`.
- Cover success and failure paths for changed logic.
- Run `make test` (or `go test ./...`) before opening a PR.
## Commit & Pull Request Guidelines
- Messages: Prefer Conventional Commits (e.g., `feat(parser): ...`,
`fix(config): ...`). Short, imperative first line; scope optional.
- PRs: Provide clear description, link issues (e.g., `#45`), include screenshots
for UI, and note breaking changes/migrations.
- Keep diffs focused; run `make format` and `make lint` before opening.
- Prefer Conventional Commits: `feat(scope): ...`, `fix(scope): ...`, `chore: ...`.
- Keep commits focused and atomic.
- PRs should include: clear summary, linked issue (e.g., `#51`), and screenshots for UI changes.
- Call out config/env changes and any migration or deployment impact.
## Security & Configuration Tips
- Environment: Use `.env`/`prod.env`; never commit secrets.
Example: `DATABASE_URL="host=... user=... database=..."`.
- Ports: default `8000`; configure via `PORT`.
- Dependencies: use `go mod tidy` and `make up-deps` when updating.
- Config is environment-driven with `APP_` prefix (see `internal/config/config.go`).
- Example parser model override: `APP_OPENAI_MODEL=gpt-5-nano`.
- Never commit secrets; keep them in local `.env` / deployment secret manager.

View file

@ -1,4 +1,4 @@
FROM golang:1.25-alpine AS builder
FROM golang:1.26-alpine AS builder
RUN apk update && apk add --no-cache \
build-base \

View file

@ -1,5 +1,5 @@
# ----------- Builder Stage -----------
FROM golang:1.25-alpine AS builder
FROM golang:1.26-alpine AS builder
WORKDIR /app
RUN apk add --no-cache build-base
@ -22,7 +22,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
go build -ldflags="-s -w" -o rentease main.go
# ----------- Dev Stage -----------
FROM golang:1.25-alpine AS dev
FROM golang:1.26-alpine AS dev
WORKDIR /app
# Install runtime dependencies

View file

@ -83,6 +83,7 @@ APP_ORIGINS=http://localhost:8000
APP_PORT=8000
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_OPENAI_MODEL=gpt-5-nano
APP_STRIPE_SECRET_KEY=
APP_STRIPE_WEBHOOK_SECRET=
APP_SENTRY_DSN=

View file

@ -15,6 +15,7 @@ services:
APP_LOG_LEVEL: debug
APP_PORT: 8000
APP_ORIGINS: http://localhost:8000
APP_OPENAI_MODEL: gpt-5-nano
APP_DATABASE_URL: postgres://rentease:rentease@db:5432/rentease?sslmode=disable
APP_ADMIN: admin@example.com
APP_ADMIN_SECRET: supersecret

10
go.mod
View file

@ -1,11 +1,11 @@
module github.com/rjNemo/rentease
go 1.25.4
go 1.26
require (
github.com/a-h/templ v0.3.977
github.com/getsentry/sentry-go v0.40.0
github.com/go-chi/chi/v5 v5.2.3
github.com/getsentry/sentry-go v0.42.0
github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/cors v1.2.2
github.com/gorilla/sessions v1.4.0
github.com/joho/godotenv v1.5.1
@ -36,6 +36,6 @@ require (
github.com/openai/openai-go v1.12.0
github.com/sethvargo/go-envconfig v1.3.0
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.32.0
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0
)

16
go.sum
View file

@ -5,10 +5,10 @@ github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo=
github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/getsentry/sentry-go v0.42.0 h1:eeFMACuZTbUQf90RE8dE4tXeSe4CZyfvR1MBL7RLEt8=
github.com/getsentry/sentry-go v0.42.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s=
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@ -75,10 +75,10 @@ golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
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/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -25,6 +25,8 @@ type Config struct {
Port int `env:"PORT, default=4200"`
// SentryDsn is the DSN for Sentry error reporting
SentryDsn string `env:"SENTRY_DSN"`
// OpenAIModel is the OpenAI model used by the booking parser
OpenAIModel string `env:"OPENAI_MODEL, default=gpt-5-nano"`
// Auth
// Admin is the email used to access the admin panel
Admin string `env:"ADMIN, required"`

View file

@ -16,11 +16,13 @@ import (
type BookingAgentParser struct {
systemPrompt string
llmClient openai.Client
model string
}
func NewBookingAgentParser() *BookingAgentParser {
func NewBookingAgentParser(model string) *BookingAgentParser {
return &BookingAgentParser{
llmClient: openai.NewClient(),
model: model,
systemPrompt: ` Extract the following fields from the booking content and return a JSON object with this exact structure (all fields required, use null or empty string if not available):
{
@ -71,7 +73,7 @@ func (p *BookingAgentParser) Parse(rawContent string) (*booking.Booking, error)
resp, err := p.llmClient.Responses.New(ctx, responses.ResponseNewParams{
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(prompt)},
Model: openai.ChatModelChatgpt4oLatest,
Model: p.model,
})
if err != nil {
return nil, fmt.Errorf("error sending request to OpenAI: %w", err)

View file

@ -47,7 +47,7 @@ func TestBookingAgentParser_Parse(t *testing.T) {
Les conversations avec vos clients apparaîtront ici.
Booking.com reçoit tous les messages écrits ici et les traite selon sa Charte de confidentialité et informations sur les cookies Conditions `
parser := NewBookingAgentParser()
parser := NewBookingAgentParser("gpt-5-nano")
booking, err := parser.Parse(input)
if err != nil {
t.Fatalf("Parse failed: %v", err)

View file

@ -165,7 +165,7 @@ func buildPaymentLinkCreateParams(params CreatePaymentLinkParams) (*stripe.Payme
ProductData: &stripe.PaymentLinkCreateLineItemPriceDataProductDataParams{
Name: stripe.String(strings.TrimSpace(params.Description)),
},
UnitAmount: stripe.Int64(amountCents),
UnitAmount: new(amountCents),
},
Quantity: stripe.Int64(1),
},

View file

@ -71,7 +71,7 @@ func run(ctx context.Context, appConfig *config.Config, appLogger *slog.Logger)
return fmt.Errorf("error starting pdf client %w", err)
}
parsingClient := parser.NewBookingAgentParser()
parsingClient := parser.NewBookingAgentParser(appConfig.OpenAIModel)
var stripeClient payment.StripeClient
if appConfig.StripeSecretKey != "" {