chore(): docker-compose
This commit is contained in:
22
Dockerfile
Normal file
22
Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
FROM golang:1.24 as build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy module files and download dependencies
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the rest of the application source and build
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o /invoiceapi cmd/invoiceapi/main.go
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
FROM alpine:3
|
||||||
|
# the test program:
|
||||||
|
COPY --from=build /invoiceapi /invoiceapi
|
||||||
|
# the tls certificates:
|
||||||
|
# NB: this pulls directly from the upstream image, which already has ca-certificates:
|
||||||
|
|
||||||
|
CMD [ "/invoiceapi" ]
|
||||||
|
|
||||||
38
README.md
38
README.md
@@ -2,28 +2,24 @@ docker run --rm -p 3030:3000 gotenberg/gotenberg:8
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
This application is configured using a `config.json` file in the root of the project. You can use the `config.json.example` file as a starting point.
|
This application can be configured using a `config.json` file in the root of the project, or by using environment variables. Values set in environment variables will override the values from the `config.json` file.
|
||||||
|
|
||||||
```json
|
You can use the `config.example.json` file as a starting point for your `config.json`.
|
||||||
{
|
|
||||||
"email": {
|
### Environment Variables
|
||||||
"smtp": {
|
|
||||||
"host": "smtp.example.com",
|
The following environment variables can be used for configuration:
|
||||||
"port": 587,
|
|
||||||
"username": "user",
|
| Variable | Description |
|
||||||
"password": "password"
|
| --------------------- | --------------------------------------------- |
|
||||||
},
|
| `PDF_HOSTNAME` | The hostname of the PDF generator (Gotenberg) |
|
||||||
"from": "from@example.com"
|
| `GITEA_URL` | The URL of your Gitea instance |
|
||||||
},
|
| `GITEA_TOKEN` | Your Gitea API token |
|
||||||
"pdf": {
|
| `EMAIL_FROM` | The "From" address for sending emails |
|
||||||
"hostname": "http://localhost:3030"
|
| `EMAIL_SMTP_HOST` | The SMTP server host |
|
||||||
},
|
| `EMAIL_SMTP_PORT` | The SMTP server port |
|
||||||
"gitea": {
|
| `EMAIL_SMTP_USER` | The username for SMTP authentication |
|
||||||
"url": "https://gitea.example.com",
|
| `EMAIL_SMTP_PASSWORD` | The password for SMTP authentication |
|
||||||
"token": "your-gitea-token"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Endpoints
|
## API Endpoints
|
||||||
|
|
||||||
|
|||||||
22
docker-compose.yml
Normal file
22
docker-compose.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
services:
|
||||||
|
invoiceapi:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
depends_on:
|
||||||
|
- gotenberg
|
||||||
|
environment:
|
||||||
|
- PDF_HOSTNAME=http://gotenberg:3000
|
||||||
|
volumes:
|
||||||
|
- ./config.json:/config.json
|
||||||
|
develop:
|
||||||
|
watch:
|
||||||
|
- action: rebuild
|
||||||
|
path: .
|
||||||
|
ignore:
|
||||||
|
- .git
|
||||||
|
gotenberg:
|
||||||
|
image: gotenberg/gotenberg:8
|
||||||
|
restart: unless-stopped
|
||||||
1
go.mod
1
go.mod
@@ -4,6 +4,7 @@ go 1.24.5
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/sdk/gitea v0.21.0
|
code.gitea.io/sdk/gitea v0.21.0
|
||||||
|
github.com/caarlos0/env/v10 v10.0.0
|
||||||
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a
|
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a
|
||||||
github.com/jedib0t/go-pretty/v6 v6.6.8
|
github.com/jedib0t/go-pretty/v6 v6.6.8
|
||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -2,6 +2,8 @@ code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
|
|||||||
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
|
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
|
||||||
github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
|
github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
|
||||||
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
|
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
|
||||||
|
github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA=
|
||||||
|
github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
|
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func New(log *slog.Logger, invoice invoicer, mail mailer) *Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type invoicer interface {
|
type invoicer interface {
|
||||||
Generate(creditor, deptor model.Entity, mindur time.Duration, rate float64, repos []invoice.Repo) (document io.ReadCloser, report report.Report, err error)
|
Generate(creditor, deptor model.Entity, mindur time.Duration, rate float64, repos []invoice.Repo) (document io.ReadCloser, report *report.Report, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type mailer interface {
|
type mailer interface {
|
||||||
|
|||||||
@@ -5,37 +5,43 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.schreifuchs.ch/lou-taylor/accounting/internal/email"
|
"git.schreifuchs.ch/lou-taylor/accounting/internal/email"
|
||||||
|
"github.com/caarlos0/env/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PDF holds the configuration for the PDF generator.
|
// PDF holds the configuration for the PDF generator.
|
||||||
type PDF struct {
|
type PDF struct {
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname" env:"HOSTNAME"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gitea holds the configuration for the Gitea client.
|
// Gitea holds the configuration for the Gitea client.
|
||||||
type Gitea struct {
|
type Gitea struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url" env:"URL"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token" env:"TOKEN"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config holds the configuration for the entire application.
|
// Config holds the configuration for the entire application.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Email email.Config `json:"email"`
|
Email email.Config `json:"email" envPrefix:"EMAIL_"`
|
||||||
PDF PDF `json:"pdf"`
|
PDF PDF `json:"pdf" envPrefix:"PDF_"`
|
||||||
Gitea Gitea `json:"gitea"`
|
Gitea Gitea `json:"gitea" envPrefix:"GITEA_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads the configuration from a JSON file.
|
// Load loads the configuration from a JSON file and environment variables.
|
||||||
func Load(path string) (*Config, error) {
|
func Load(path string) (*Config, error) {
|
||||||
|
cfg := &Config{}
|
||||||
|
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
defer file.Close()
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
if err := decoder.Decode(cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
cfg := &Config{}
|
if err := env.Parse(cfg); err != nil {
|
||||||
decoder := json.NewDecoder(file)
|
|
||||||
if err := decoder.Decode(cfg); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
SMTP SMTPConfig
|
SMTP SMTPConfig `envPrefix:"SMTP_"`
|
||||||
From string
|
From string `env:"FROM"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SMTPConfig struct {
|
type SMTPConfig struct {
|
||||||
Host string
|
Host string `env:"HOST"`
|
||||||
Port string
|
Port string `env:"PORT"`
|
||||||
User string
|
User string `env:"USER"`
|
||||||
Password string
|
Password string `env:"PASSWORD"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
|||||||
22
main.go
22
main.go
@@ -1,22 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.schreifuchs.ch/lou-taylor/accounting/internal/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// var cfg invoice.Config
|
|
||||||
// file, err := os.Open("config.json")
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// defer file.Close()
|
|
||||||
// decoder := json.NewDecoder(file)
|
|
||||||
// err = decoder.Decode(&cfg)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// invoice.Generate(cfg)
|
|
||||||
api.Start(":8080")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user