rentease/main.go
Ruidy 8384d85e3e
feat(stripe): add Stripe payment sync and webhook support
Introduce Stripe integration for automatic payment ingestion and refund
tracking. Adds new fields to the payment model for Stripe IDs and
status,
Stripe client driver, sync service, cron job, manual API endpoint, and
public webhook handler for real-time updates. Includes tests and
documentation. Manual cash entry remains supported.
2025-10-03 21:39:59 +02:00

126 lines
3.4 KiB
Go

package main
import (
"context"
"fmt"
"log/slog"
"os"
"os/signal"
"github.com/getsentry/sentry-go"
"github.com/rjNemo/rentease/assets"
"github.com/rjNemo/rentease/internal/config"
"github.com/rjNemo/rentease/internal/driver/database"
"github.com/rjNemo/rentease/internal/driver/logger"
"github.com/rjNemo/rentease/internal/driver/parser"
"github.com/rjNemo/rentease/internal/driver/pdf"
stripeclient "github.com/rjNemo/rentease/internal/driver/stripe"
bookingRepo "github.com/rjNemo/rentease/internal/repository/booking"
"github.com/rjNemo/rentease/internal/server"
"github.com/rjNemo/rentease/internal/service/auth"
"github.com/rjNemo/rentease/internal/service/booking"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
baseLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: true}))
appConfig, err := config.New(ctx)
if err != nil {
baseLogger.Error("configuration error", slog.Any("error", err))
}
appLogger := logger.New(appConfig.LogLevel)
slog.SetDefault(appLogger)
if err := run(ctx, appConfig, appLogger); err != nil {
appLogger.Error("server exited", slog.Any("error", err))
os.Exit(1)
}
}
func run(ctx context.Context, appConfig *config.Config, appLogger *slog.Logger) error {
// init sentry
if err := sentry.Init(sentry.ClientOptions{
Dsn: appConfig.SentryDsn,
EnableTracing: true,
TracesSampleRate: 1.0,
}); err != nil {
return fmt.Errorf("error initializing sentry %w", err)
}
// init database
db, err := database.New(appConfig.DatabaseURL)
if err != nil {
return fmt.Errorf("error connecting to the database %w", err)
}
if err = database.Migrate(db, &booking.Booking{}, &booking.Item{}, &booking.Payment{}); err != nil {
return fmt.Errorf("error migrating the database %w", err)
}
bookingStore := bookingRepo.NewPgStore(db)
// build pdf client
pc, err := pdf.NewPdfClient()
if err != nil {
return fmt.Errorf("error starting pdf client %w", err)
}
parsingClient := parser.NewBookingAgentParser()
var stripeClient booking.StripeClient
if appConfig.StripeSecretKey != "" {
opts := []stripeclient.Option{}
if appConfig.StripeConnectAccount != "" {
opts = append(opts, stripeclient.WithAccount(appConfig.StripeConnectAccount))
}
client, err := stripeclient.New(appConfig.StripeSecretKey, opts...)
if err != nil {
return fmt.Errorf("error creating stripe client: %w", err)
}
stripeClient = client
}
bookingService, err := booking.NewService(appLogger, bookingStore, parsingClient, pc, stripeClient)
if err != nil {
return fmt.Errorf("error creating booking service: %w", err)
}
// build authentication service
as, err := auth.NewService(
appConfig.SessionSecret,
appConfig.Admin,
appConfig.AdminSecret,
appConfig.APIKey,
)
if err != nil {
return fmt.Errorf("error starting auth service %w", err)
}
port := appConfig.Port
origins := appConfig.Origins
srv, err := server.New(
bookingService,
as,
config.NewHost(), // TODO: move to the database at some point
server.WithPort(port),
server.WithFileSystem(assets.Static),
server.WithDebug(appConfig.Debug),
server.WithSecretKey(appConfig.SecretKey),
server.WithOrigins(origins),
server.WithStripeWebhookSecret(appConfig.StripeWebhookSecret),
)
if err != nil {
return fmt.Errorf("error starting server %w", err)
}
srv.Start(ctx)
return nil
}