feat(#22): gamificação RPG — XP, quests, conquistas, cosméticos e personagem SVG pixel art
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
@@ -20,8 +20,20 @@ var m003 string
|
||||
//go:embed sql/004_accounts.sql
|
||||
var m004 string
|
||||
|
||||
//go:embed sql/005_game_profile.sql
|
||||
var m005 string
|
||||
|
||||
//go:embed sql/006_quests.sql
|
||||
var m006 string
|
||||
|
||||
//go:embed sql/007_achievements.sql
|
||||
var m007 string
|
||||
|
||||
//go:embed sql/008_cosmetics.sql
|
||||
var m008 string
|
||||
|
||||
func Run(ctx context.Context, pool *pgxpool.Pool) error {
|
||||
migrations := []string{m001, m002, m003, m004}
|
||||
migrations := []string{m001, m002, m003, m004, m005, m006, m007, m008}
|
||||
for i, sql := range migrations {
|
||||
if _, err := pool.Exec(ctx, sql); err != nil {
|
||||
return fmt.Errorf("migration %03d: %w", i+1, err)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE IF NOT EXISTS player_profile (
|
||||
id SERIAL PRIMARY KEY,
|
||||
level INTEGER NOT NULL DEFAULT 1,
|
||||
xp INTEGER NOT NULL DEFAULT 0,
|
||||
xp_to_next INTEGER NOT NULL DEFAULT 100
|
||||
);
|
||||
INSERT INTO player_profile (level, xp, xp_to_next) VALUES (1, 0, 100)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS xp_events (
|
||||
id SERIAL PRIMARY KEY,
|
||||
event_type VARCHAR(50) NOT NULL,
|
||||
xp_earned INTEGER NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES (5) ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,32 @@
|
||||
CREATE TABLE IF NOT EXISTS quests (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
quest_type VARCHAR(20) NOT NULL CHECK (quest_type IN ('daily','weekly','monthly')),
|
||||
target_count INTEGER,
|
||||
target_pct NUMERIC(5,2),
|
||||
xp_reward INTEGER NOT NULL DEFAULT 50,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS player_quests (
|
||||
id SERIAL PRIMARY KEY,
|
||||
quest_id INTEGER NOT NULL REFERENCES quests(id) ON DELETE CASCADE,
|
||||
period VARCHAR(10) NOT NULL,
|
||||
current_count INTEGER NOT NULL DEFAULT 0,
|
||||
current_pct NUMERIC(5,2) NOT NULL DEFAULT 0,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
completed_at TIMESTAMP WITH TIME ZONE,
|
||||
claimed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
UNIQUE (quest_id, period)
|
||||
);
|
||||
|
||||
INSERT INTO quests (title, description, quest_type, target_count, target_pct, xp_reward) VALUES
|
||||
('Economista do Mês', 'Poupe ≥40% da receita este mês', 'monthly', NULL, 40, 200),
|
||||
('Capitão Organizado', 'Importe 1 extrato esta semana', 'weekly', 1, NULL, 50),
|
||||
('Categorizador Ativo', 'Categorize 5 transações hoje', 'daily', 5, NULL, 30),
|
||||
('Controlador Semanal', 'Registre ao menos 3 transações esta semana', 'weekly', 3, NULL, 40),
|
||||
('Mês Sem Surpresas', 'Cubra todas as recorrências do mês', 'monthly', NULL, NULL, 150)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES (6) ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,30 @@
|
||||
CREATE TABLE IF NOT EXISTS achievements (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
icon VARCHAR(10) NOT NULL DEFAULT '🏆',
|
||||
xp_reward INTEGER NOT NULL DEFAULT 100,
|
||||
unlock_condition VARCHAR(100) NOT NULL UNIQUE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS player_achievements (
|
||||
id SERIAL PRIMARY KEY,
|
||||
achievement_id INTEGER NOT NULL REFERENCES achievements(id) ON DELETE CASCADE UNIQUE,
|
||||
earned_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
INSERT INTO achievements (title, description, icon, xp_reward, unlock_condition) VALUES
|
||||
('Primeiro Passo', 'Registre sua primeira transação manual', '👣', 50, 'first_transaction'),
|
||||
('Explorador de Extratos', 'Importe seu primeiro extrato', '📄', 100, 'first_import'),
|
||||
('Meta Atingida!', 'Poupe 40% pela primeira vez', '🎯', 200, 'first_40pct'),
|
||||
('Tri-Campeão', 'Poupe 40% por 3 meses seguidos', '🥇', 500, 'three_months_40pct'),
|
||||
('Veleirista Econômico', 'Gaste menos de R$500 no Veleiro em um mês', '⛵', 150, 'veleiro_under_500'),
|
||||
('Nível 5', 'Alcance o nível 5', '⭐', 100, 'level_5'),
|
||||
('Nível 10', 'Alcance o nível 10', '🌟', 300, 'level_10'),
|
||||
('Mestre das Categorias', 'Categorize 100 transações', '🗂️', 200, 'categorize_100'),
|
||||
('Semana Perfeita', 'Importe extrato por 4 semanas seguidas', '📅', 250, 'four_weeks_import'),
|
||||
('Guardião da Saúde', 'Registre gasto com Saúde/Insulina em 3 meses', '💉', 300, 'health_3months'),
|
||||
('Mês Limpo', 'Todas as recorrências cobertas em um mês', '✨', 200, 'full_recurring_month')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES (7) ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS cosmetics (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL CHECK (type IN ('hat','outfit','accessory')),
|
||||
unlock_level INTEGER NOT NULL,
|
||||
css_data JSONB NOT NULL DEFAULT '{}'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS player_cosmetics (
|
||||
id SERIAL PRIMARY KEY,
|
||||
cosmetic_id INTEGER NOT NULL REFERENCES cosmetics(id) ON DELETE CASCADE UNIQUE,
|
||||
equipped BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
unlocked_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
INSERT INTO cosmetics (name, type, unlock_level, css_data) VALUES
|
||||
('Chapéu de Aventureiro', 'hat', 2, '{"color":"#8B4513","accent":"#d4a85a"}'),
|
||||
('Roupa de Marinheiro', 'outfit', 3, '{"primary":"#1e3a5f","accent":"#ffffff"}'),
|
||||
('Óculos de Sol', 'accessory', 4, '{"color":"#1a1a1a"}'),
|
||||
('Chapéu de Capitão', 'hat', 5, '{"color":"#1e293b","badge":"#ffd700"}'),
|
||||
('Roupa Dourada', 'outfit', 7, '{"primary":"#d4af37","accent":"#ffd700"}'),
|
||||
('Coroa de Campeão', 'hat', 10, '{"color":"#ffd700","gems":"#e11d48"}')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES (8) ON CONFLICT DO NOTHING;
|
||||
Reference in New Issue
Block a user