feat: implementar sistema de preferências do usuário e refatorar changelog

Adiciona sistema completo de preferências de usuário:
  - Cria tabela userPreferences no schema com campos disableMagnetlines, periodMonthsBefore e periodMonthsAfter
  - Implementa página de Ajustes com abas (Preferências, Alterar nome, Senha, E-mail, Deletar conta)
  - Adiciona componente PreferencesForm para configuração de magnetlines e períodos de exibição
  - Propaga periodPreferences para todos os componentes de lançamentos e calendário

  Refatora sistema de changelog:
  - Remove implementação anterior baseada em JSON estático
  - Adiciona nova página de changelog dinâmica em app/(dashboard)/changelog
  - Adiciona componente changelog-list.tsx
  - Remove arquivos obsoletos (changelog-notification, actions, data, utils, scripts)

  Adiciona controle de saldo inicial em contas:
  - Novo campo excludeInitialBalanceFromIncome em contas
  - Permite excluir saldo inicial do cálculo de receitas
  - Atualiza queries de lançamentos para respeitar esta configuração

  Melhorias adicionais:
  - Adiciona componente ui/accordion.tsx do shadcn/ui
  - Refatora formatPeriodLabel para displayPeriod centralizado
  - Propaga estabelecimentos para componentes de lançamentos
  - Remove variável DB_PROVIDER obsoleta do .env.example e documentação
  - Adiciona 6 migrações de banco de dados (0003-0008)
This commit is contained in:
Felipe Coutinho
2026-01-03 14:18:03 +00:00
parent 3eca48c71a
commit fd817683ca
87 changed files with 13582 additions and 1445 deletions

View File

@@ -100,6 +100,31 @@ export const verification = pgTable("verification", {
}),
});
export const userPreferences = pgTable("user_preferences", {
id: uuid("id")
.primaryKey()
.default(sql`gen_random_uuid()`),
userId: text("user_id")
.notNull()
.unique()
.references(() => user.id, { onDelete: "cascade" }),
disableMagnetlines: boolean("disable_magnetlines").notNull().default(false),
periodMonthsBefore: integer("period_months_before").notNull().default(3),
periodMonthsAfter: integer("period_months_after").notNull().default(3),
createdAt: timestamp("created_at", {
mode: "date",
withTimezone: true,
})
.notNull()
.default(sql`now()`),
updatedAt: timestamp("updated_at", {
mode: "date",
withTimezone: true,
})
.notNull()
.default(sql`now()`),
});
// ===================== PUBLIC TABLES =====================
export const contas = pgTable(
@@ -119,6 +144,9 @@ export const contas = pgTable(
excludeFromBalance: boolean("excluir_do_saldo")
.notNull()
.default(false),
excludeInitialBalanceFromIncome: boolean("excluir_saldo_inicial_receitas")
.notNull()
.default(false),
userId: text("user_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
@@ -359,30 +387,6 @@ export const anotacoes = pgTable("anotacoes", {
.references(() => user.id, { onDelete: "cascade" }),
});
export const userUpdateLog = pgTable(
"user_update_log",
{
id: uuid("id")
.primaryKey()
.default(sql`gen_random_uuid()`),
userId: text("user_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
updateId: text("update_id").notNull(), // commit hash
readAt: timestamp("read_at", {
mode: "date",
withTimezone: true,
})
.notNull()
.defaultNow(),
},
(table) => ({
userIdUpdateIdIdx: uniqueIndex("user_update_log_user_update_idx").on(
table.userId,
table.updateId
),
})
);
export const savedInsights = pgTable(
"saved_insights",
@@ -556,7 +560,6 @@ export const userRelations = relations(user, ({ many, one }) => ({
orcamentos: many(orcamentos),
pagadores: many(pagadores),
installmentAnticipations: many(installmentAnticipations),
updateLogs: many(userUpdateLog),
}));
export const accountRelations = relations(account, ({ one }) => ({
@@ -664,12 +667,6 @@ export const savedInsightsRelations = relations(savedInsights, ({ one }) => ({
}),
}));
export const userUpdateLogRelations = relations(userUpdateLog, ({ one }) => ({
user: one(user, {
fields: [userUpdateLog.userId],
references: [user.id],
}),
}));
export const lancamentosRelations = relations(lancamentos, ({ one }) => ({
user: one(user, {
@@ -725,6 +722,8 @@ export type NewUser = typeof user.$inferInsert;
export type Account = typeof account.$inferSelect;
export type Session = typeof session.$inferSelect;
export type Verification = typeof verification.$inferSelect;
export type UserPreferences = typeof userPreferences.$inferSelect;
export type NewUserPreferences = typeof userPreferences.$inferInsert;
export type Conta = typeof contas.$inferSelect;
export type Categoria = typeof categorias.$inferSelect;
export type Pagador = typeof pagadores.$inferSelect;
@@ -736,4 +735,3 @@ export type SavedInsight = typeof savedInsights.$inferSelect;
export type Lancamento = typeof lancamentos.$inferSelect;
export type InstallmentAnticipation =
typeof installmentAnticipations.$inferSelect;
export type UserUpdateLog = typeof userUpdateLog.$inferSelect;