modified: .env

new file:   __debug_bin.exe
	modified:   bot.db
	modified:   db/db.go
	modified:   go.mod
	new file:   handlers/auth.go
	modified:   handlers/dashboard.go
	new file:   handlers/saas.go
	modified:   handlers/webhook.go
	modified:   main.go
	new file:   saas_bot.db
	modified:   services/openrouter.go
	new file:   services/types.go
	modified:   services/whatsapp.go
	new file:   static/style.css
	modified:   templates/dashboard.html
	new file:   templates/landing.html
	new file:   templates/login.html
	new file:   templates/register.html
	deleted:    types/types.go
This commit is contained in:
2026-03-02 00:38:05 -03:00
parent 9ff021879f
commit e256fcb073
20 changed files with 627 additions and 659 deletions

118
db/db.go
View File

@@ -2,6 +2,7 @@ package db
import (
"database/sql"
"log"
_ "modernc.org/sqlite"
)
@@ -10,64 +11,93 @@ var Conn *sql.DB
func Init() {
var err error
Conn, err = sql.Open("sqlite", "./bot.db")
Conn, err = sql.Open("sqlite", "./saas_bot.db")
if err != nil {
panic(err)
}
schema := `
CREATE TABLE IF NOT EXISTS clients (
id TEXT PRIMARY KEY,
name TEXT,
tier TEXT,
msg_count INTEGER DEFAULT 0
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE,
password_hash TEXT,
subscription_tier TEXT DEFAULT 'free',
stripe_customer_id TEXT
);
CREATE TABLE IF NOT EXISTS bot_configs (
user_id INTEGER PRIMARY KEY,
whatsapp_phone_id TEXT UNIQUE,
whatsapp_token TEXT,
bot_name TEXT DEFAULT 'My Assistant',
system_prompt TEXT DEFAULT 'You are a helpful assistant.',
availability_hours TEXT DEFAULT 'Mon-Fri 09:00-17:00',
FOREIGN KEY(user_id) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS appointments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
client_id TEXT,
user_id INTEGER,
customer_phone TEXT,
appointment_date TEXT,
status TEXT DEFAULT 'confirmed'
);
CREATE TABLE IF NOT EXISTS chats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT DEFAULT 'New Chat',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
appointment_time DATETIME,
status TEXT DEFAULT 'confirmed',
FOREIGN KEY(user_id) REFERENCES users(id)
);
`
_, err = Conn.Exec(schema)
if err != nil {
log.Fatal("Migration Error:", err)
}
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
chat_id INTEGER,
role TEXT, -- 'user' or 'assistant'
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(chat_id) REFERENCES chats(id)
);`
Conn.Exec(schema)
seedUser()
}
func SaveAppointment(phone string, date string) error {
_, err := Conn.Exec(
"INSERT INTO appointments (customer_phone, appointment_date, status) VALUES (?, ?, ?)",
phone, date, "confirmed",
)
// seedUser creates a default user so you can test the dashboard immediately
func seedUser() {
var count int
Conn.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
if count == 0 {
log.Println("🌱 Seeding default user (ID: 1)...")
_, _ = Conn.Exec("INSERT INTO users (email, subscription_tier) VALUES ('admin@sekibot.com', 'pro')")
// Insert default bot config for User 1
// NOTE: You must update these values in the Dashboard or DB to match your real Meta credentials!
_, _ = Conn.Exec(`INSERT INTO bot_configs (user_id, whatsapp_phone_id, whatsapp_token, bot_name)
VALUES (1, '986583417873961', 'EAATqIU03y9YBQ1DnscXkt0QQ8lfhWQbI8TT0wRNdB9ZAGLWEdPhN3761E0XBXBdzJiZA3uiPEugjhIS1TjrUZCu979aiiSYFvjbDjFRFYGVsGfqIZCB13H6AaviQHlBNksil9JlkefZAy4ZBFqZCkAcYGjGNtZBWHaXZCaMYTMmfn7rOAx4IUt6eHjfiVkXVquOoqDQY8oVOs5HAekLWNZBqsxm2w2J34AacAzsUwzem6kmsYcKs9CDQ9wIJBRw9FDaKkbV64waI1FdEI7ZALkZCKZBEWUFeA', 'Seki Bot')`)
}
}
// --- HELPERS ---
type BotContext struct {
UserID int
SystemPrompt string
Availability string
Token string
PhoneID string
}
func GetBotByPhoneID(phoneID string) (*BotContext, error) {
var b BotContext
err := Conn.QueryRow(`
SELECT user_id, system_prompt, availability_hours, whatsapp_token, whatsapp_phone_id
FROM bot_configs WHERE whatsapp_phone_id = ?`, phoneID).Scan(&b.UserID, &b.SystemPrompt, &b.Availability, &b.Token, &b.PhoneID)
if err != nil {
return nil, err
}
return &b, nil
}
// UpdateBotConfig saves settings from the dashboard
func UpdateBotConfig(userID int, name, prompt, avail string) error {
_, err := Conn.Exec(`
UPDATE bot_configs
SET bot_name=?, system_prompt=?, availability_hours=?
WHERE user_id=?`, name, prompt, avail, userID)
return err
}
// GetOrCreateChatByPhone finds a chat for this phone number or creates one
func GetOrCreateChatByPhone(phone string) int {
// 1. Check if we already have a chat for this phone
// (Note: You might want to add a 'phone' column to 'chats' table if you haven't yet.
// For now, I'll cheat and put the phone in the title if it's new)
var id int
err := Conn.QueryRow("SELECT id FROM chats WHERE title = ?", phone).Scan(&id)
if err == nil {
return id
}
// 2. If not found, create one
res, _ := Conn.Exec("INSERT INTO chats (title) VALUES (?)", phone)
newId, _ := res.LastInsertId()
return int(newId)
// SaveAppointment now requires a userID to know WHO the appointment is for
func SaveAppointment(userID int, phone, date string) error {
_, err := Conn.Exec("INSERT INTO appointments (user_id, customer_phone, appointment_time) VALUES (?, ?, ?)", userID, phone, date)
return err
}