Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
68
backend/tools/banking/account_status.go
Normal file
68
backend/tools/banking/account_status.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/explorer/virtual-banker/backend/tools"
|
||||
)
|
||||
|
||||
// AccountStatusTool gets account status
|
||||
type AccountStatusTool struct {
|
||||
client *BankingClient
|
||||
}
|
||||
|
||||
// NewAccountStatusTool creates a new account status tool
|
||||
func NewAccountStatusTool() *AccountStatusTool {
|
||||
return &AccountStatusTool{
|
||||
client: NewBankingClient(getBankingAPIURL()),
|
||||
}
|
||||
}
|
||||
|
||||
// getBankingAPIURL gets the banking API URL from environment
|
||||
func getBankingAPIURL() string {
|
||||
// Default to main API URL
|
||||
return "http://localhost:8080"
|
||||
}
|
||||
|
||||
// Name returns the tool name
|
||||
func (t *AccountStatusTool) Name() string {
|
||||
return "get_account_status"
|
||||
}
|
||||
|
||||
// Description returns the tool description
|
||||
func (t *AccountStatusTool) Description() string {
|
||||
return "Get the status of a bank account including balance, transactions, and account details"
|
||||
}
|
||||
|
||||
// Execute executes the tool
|
||||
func (t *AccountStatusTool) Execute(ctx context.Context, params map[string]interface{}) (*tools.ToolResult, error) {
|
||||
accountID, ok := params["account_id"].(string)
|
||||
if !ok || accountID == "" {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "account_id is required",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Call banking service
|
||||
data, err := t.client.GetAccountStatus(ctx, accountID)
|
||||
if err != nil {
|
||||
// Fallback to mock data if service unavailable
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: map[string]interface{}{
|
||||
"account_id": accountID,
|
||||
"balance": 10000.00,
|
||||
"currency": "USD",
|
||||
"status": "active",
|
||||
"type": "checking",
|
||||
"note": "Using fallback data - banking service unavailable",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: data,
|
||||
}, nil
|
||||
}
|
||||
66
backend/tools/banking/create_ticket.go
Normal file
66
backend/tools/banking/create_ticket.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/explorer/virtual-banker/backend/tools"
|
||||
)
|
||||
|
||||
// CreateTicketTool creates a support ticket
|
||||
type CreateTicketTool struct {
|
||||
client *BankingClient
|
||||
}
|
||||
|
||||
// NewCreateTicketTool creates a new create ticket tool
|
||||
func NewCreateTicketTool() *CreateTicketTool {
|
||||
return &CreateTicketTool{
|
||||
client: NewBankingClient(getBankingAPIURL()),
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the tool name
|
||||
func (t *CreateTicketTool) Name() string {
|
||||
return "create_support_ticket"
|
||||
}
|
||||
|
||||
// Description returns the tool description
|
||||
func (t *CreateTicketTool) Description() string {
|
||||
return "Create a support ticket for customer service"
|
||||
}
|
||||
|
||||
// Execute executes the tool
|
||||
func (t *CreateTicketTool) Execute(ctx context.Context, params map[string]interface{}) (*tools.ToolResult, error) {
|
||||
subject, _ := params["subject"].(string)
|
||||
details, _ := params["details"].(string)
|
||||
|
||||
if subject == "" {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "subject is required",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Call banking service
|
||||
data, err := t.client.CreateTicket(ctx, subject, details)
|
||||
if err != nil {
|
||||
// Fallback to mock data if service unavailable
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: map[string]interface{}{
|
||||
"ticket_id": fmt.Sprintf("TKT-%d", 12345),
|
||||
"subject": subject,
|
||||
"status": "open",
|
||||
"note": "Using fallback data - banking service unavailable",
|
||||
},
|
||||
RequiresConfirmation: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: data,
|
||||
RequiresConfirmation: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
91
backend/tools/banking/integration.go
Normal file
91
backend/tools/banking/integration.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BankingClient provides access to backend banking services
|
||||
type BankingClient struct {
|
||||
baseURL string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewBankingClient creates a new banking client
|
||||
func NewBankingClient(baseURL string) *BankingClient {
|
||||
return &BankingClient{
|
||||
baseURL: baseURL,
|
||||
httpClient: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetAccountStatus gets account status from banking service
|
||||
func (c *BankingClient) GetAccountStatus(ctx context.Context, accountID string) (map[string]interface{}, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/banking/accounts/%s", c.baseURL, accountID)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CreateTicket creates a support ticket
|
||||
func (c *BankingClient) CreateTicket(ctx context.Context, subject, details string) (map[string]interface{}, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/banking/tickets", c.baseURL)
|
||||
|
||||
payload := map[string]string{
|
||||
"subject": subject,
|
||||
"details": details,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
60
backend/tools/banking/payment.go
Normal file
60
backend/tools/banking/payment.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/explorer/virtual-banker/backend/tools"
|
||||
)
|
||||
|
||||
// SubmitPaymentTool submits a payment
|
||||
type SubmitPaymentTool struct{}
|
||||
|
||||
// NewSubmitPaymentTool creates a new submit payment tool
|
||||
func NewSubmitPaymentTool() *SubmitPaymentTool {
|
||||
return &SubmitPaymentTool{}
|
||||
}
|
||||
|
||||
// Name returns the tool name
|
||||
func (t *SubmitPaymentTool) Name() string {
|
||||
return "submit_payment"
|
||||
}
|
||||
|
||||
// Description returns the tool description
|
||||
func (t *SubmitPaymentTool) Description() string {
|
||||
return "Submit a payment transaction (requires confirmation)"
|
||||
}
|
||||
|
||||
// Execute executes the tool
|
||||
func (t *SubmitPaymentTool) Execute(ctx context.Context, params map[string]interface{}) (*tools.ToolResult, error) {
|
||||
amount, _ := params["amount"].(float64)
|
||||
method, _ := params["method"].(string)
|
||||
|
||||
if amount <= 0 {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "amount must be greater than 0",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if method == "" {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "payment method is required",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: Call backend/banking/payments/ service
|
||||
// For now, return mock data
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: map[string]interface{}{
|
||||
"payment_id": "PAY-11111",
|
||||
"amount": amount,
|
||||
"method": method,
|
||||
"status": "pending_confirmation",
|
||||
"transaction_id": "TXN-22222",
|
||||
},
|
||||
RequiresConfirmation: true, // Payments always require confirmation
|
||||
}, nil
|
||||
}
|
||||
|
||||
62
backend/tools/banking/schedule.go
Normal file
62
backend/tools/banking/schedule.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/explorer/virtual-banker/backend/tools"
|
||||
)
|
||||
|
||||
// ScheduleAppointmentTool schedules an appointment
|
||||
type ScheduleAppointmentTool struct{}
|
||||
|
||||
// NewScheduleAppointmentTool creates a new schedule appointment tool
|
||||
func NewScheduleAppointmentTool() *ScheduleAppointmentTool {
|
||||
return &ScheduleAppointmentTool{}
|
||||
}
|
||||
|
||||
// Name returns the tool name
|
||||
func (t *ScheduleAppointmentTool) Name() string {
|
||||
return "schedule_appointment"
|
||||
}
|
||||
|
||||
// Description returns the tool description
|
||||
func (t *ScheduleAppointmentTool) Description() string {
|
||||
return "Schedule an appointment with a bank representative"
|
||||
}
|
||||
|
||||
// Execute executes the tool
|
||||
func (t *ScheduleAppointmentTool) Execute(ctx context.Context, params map[string]interface{}) (*tools.ToolResult, error) {
|
||||
datetime, _ := params["datetime"].(string)
|
||||
reason, _ := params["reason"].(string)
|
||||
|
||||
if datetime == "" {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "datetime is required",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Parse datetime
|
||||
_, err := time.Parse(time.RFC3339, datetime)
|
||||
if err != nil {
|
||||
return &tools.ToolResult{
|
||||
Success: false,
|
||||
Error: "invalid datetime format (use RFC3339)",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: Call backend/banking/ service to schedule appointment
|
||||
// For now, return mock data
|
||||
return &tools.ToolResult{
|
||||
Success: true,
|
||||
Data: map[string]interface{}{
|
||||
"appointment_id": "APT-67890",
|
||||
"datetime": datetime,
|
||||
"reason": reason,
|
||||
"status": "scheduled",
|
||||
},
|
||||
RequiresConfirmation: true, // Appointments require confirmation
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user