feat(v1.5.1): renomeação OpenSheets → OpenMonetis + multi-domínio

Renomeia o projeto em ~40 arquivos (package.json, manifests, layouts,
componentes, server actions, emails, Docker, docs, landing page).
Adiciona suporte a multi-domínio via PUBLIC_DOMAIN onde o domínio
público serve apenas a landing page sem botões de auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-16 17:16:50 +00:00
parent 98dd0f11e1
commit a1347aed28
40 changed files with 284 additions and 1368 deletions

View File

@@ -1,17 +1,17 @@
# ============================================ # ============================================
# OPENSHEETS - Variáveis de Ambiente # OPENMONETIS - Variáveis de Ambiente
# ============================================ # ============================================
# === Database === # === Database ===
# PostgreSQL local (Docker): use host "db" # PostgreSQL local (Docker): use host "db"
# PostgreSQL local (sem Docker): use host "localhost" # PostgreSQL local (sem Docker): use host "localhost"
# PostgreSQL remoto: use URL completa do provider # PostgreSQL remoto: use URL completa do provider
DATABASE_URL=postgresql://opensheets:opensheets_dev_password@db:5432/opensheets_db DATABASE_URL=postgresql://openmonetis:openmonetis_dev_password@db:5432/openmonetis_db
# Credenciais do PostgreSQL (apenas para Docker local) - Alterar # Credenciais do PostgreSQL (apenas para Docker local) - Alterar
POSTGRES_USER=opensheets POSTGRES_USER=openmonetis
POSTGRES_PASSWORD=opensheets_dev_password POSTGRES_PASSWORD=openmonetis_dev_password
POSTGRES_DB=opensheets_db POSTGRES_DB=openmonetis_db
# === Better Auth === # === Better Auth ===
# Gere com: openssl rand -base64 32 # Gere com: openssl rand -base64 32
@@ -32,6 +32,11 @@ RESEND_FROM_EMAIL=noreply@example.com
GOOGLE_CLIENT_ID= GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET= GOOGLE_CLIENT_SECRET=
# === Multi-Domínio (Opcional) ===
# Domínio público que serve apenas a landing page (apenas hostname, com ou sem protocolo/porta).
# Se não definido, todas as rotas ficam acessíveis.
# PUBLIC_DOMAIN=openmonetis.com
# === AI Providers (Opcional) === # === AI Providers (Opcional) ===
ANTHROPIC_API_KEY= ANTHROPIC_API_KEY=
OPENAI_API_KEY= OPENAI_API_KEY=

View File

@@ -1,8 +1,8 @@
# AI Coding Assistant Instructions for Opensheets # AI Coding Assistant Instructions for OpenMonetis
## Project Overview ## Project Overview
Opensheets is a self-hosted personal finance management application built with Next.js 16, TypeScript, PostgreSQL, and Drizzle ORM. It provides manual transaction tracking, account management, budgeting, and financial insights with a Portuguese interface. OpenMonetis is a self-hosted personal finance management application built with Next.js 16, TypeScript, PostgreSQL, and Drizzle ORM. It provides manual transaction tracking, account management, budgeting, and financial insights with a Portuguese interface.
## Architecture ## Architecture

View File

@@ -12,7 +12,7 @@ on:
workflow_dispatch: workflow_dispatch:
env: env:
DOCKER_IMAGE_NAME: opensheets DOCKER_IMAGE_NAME: openmonetis
jobs: jobs:
build-and-push: build-and-push:

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
# ============================================ # ============================================
# OPENSHEETS - .gitignore # OPENMONETIS - .gitignore
# ============================================ # ============================================
# === Dependencies === # === Dependencies ===

View File

@@ -5,6 +5,20 @@ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/), O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/). e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
## [1.5.1] - 2026-02-16
### Alterado
- Projeto renomeado de **OpenSheets** para **OpenMonetis** em todo o codebase (~40 arquivos): package.json, manifests, layouts, componentes, server actions, emails, Docker, docs e landing page
- URLs do repositório atualizados de `opensheets-app` para `openmonetis`
- Docker image renomeada para `felipegcoutinho/openmonetis`
- Logo textual atualizado (`logo_text.png`)
### Adicionado
- Suporte a multi-domínio via `PUBLIC_DOMAIN`: domínio público serve apenas a landing page (sem botões de login/cadastro, rotas do app bloqueadas pelo middleware)
- Variável de ambiente `PUBLIC_DOMAIN` no `.env.example` com documentação
## [1.5.0] - 2026-02-15 ## [1.5.0] - 2026-02-15
### Adicionado ### Adicionado

1409
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ import { RiSettings2Line } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Ajustes | Opensheets", title: "Ajustes | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -53,7 +53,7 @@ export default async function Page() {
<div> <div>
<h2 className="text-lg font-bold mb-1">Preferências</h2> <h2 className="text-lg font-bold mb-1">Preferências</h2>
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-muted-foreground mb-4">
Personalize sua experiência no Opensheets ajustando as Personalize sua experiência no OpenMonetis ajustando as
configurações de acordo com suas necessidades. configurações de acordo com suas necessidades.
</p> </p>
</div> </div>
@@ -78,7 +78,7 @@ export default async function Page() {
<div> <div>
<h2 className="text-lg font-bold mb-1">Alterar nome</h2> <h2 className="text-lg font-bold mb-1">Alterar nome</h2>
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-muted-foreground mb-4">
Atualize como seu nome aparece no Opensheets. Esse nome pode Atualize como seu nome aparece no OpenMonetis. Esse nome pode
ser exibido em diferentes seções do app e em comunicações. ser exibido em diferentes seções do app e em comunicações.
</p> </p>
</div> </div>

View File

@@ -2,7 +2,7 @@ import { RiTodoLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Anotações | Opensheets", title: "Anotações | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiCalendarEventLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Calendário | Opensheets", title: "Calendário | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiBankCard2Line } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Cartões | Opensheets", title: "Cartões | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiPriceTag3Line } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Categorias | Opensheets", title: "Categorias | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiBankLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Contas | Opensheets", title: "Contas | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiSecurePaymentLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Análise de Parcelas | Opensheets", title: "Análise de Parcelas | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiSparklingLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Insights | Opensheets", title: "Insights | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -292,7 +292,7 @@ const resolveUserLabel = (user: {
if (user?.email && user.email.trim().length > 0) { if (user?.email && user.email.trim().length > 0) {
return user.email; return user.email;
} }
return "Opensheets"; return "OpenMonetis";
}; };
type InitialCandidate = { type InitialCandidate = {

View File

@@ -2,7 +2,7 @@ import { RiArrowLeftRightLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Lançamentos | Opensheets", title: "Lançamentos | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiFundsLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Anotações | Opensheets", title: "Orçamentos | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -388,7 +388,7 @@ const buildSummaryHtml = ({
<!-- Rodapé externo --> <!-- Rodapé externo -->
<p style="margin:16px 0 0 0;font-size:12.5px;color:#94a3b8;text-align:center;"> <p style="margin:16px 0 0 0;font-size:12.5px;color:#94a3b8;text-align:center;">
Este e-mail foi enviado automaticamente pelo <strong>Opensheets</strong>. Este e-mail foi enviado automaticamente pelo <strong>OpenMonetis</strong>.
</p> </p>
</div> </div>
@@ -419,7 +419,7 @@ export async function sendPagadorSummaryAction(
const resendApiKey = process.env.RESEND_API_KEY; const resendApiKey = process.env.RESEND_API_KEY;
const resendFrom = const resendFrom =
process.env.RESEND_FROM_EMAIL ?? "Opensheets <onboarding@resend.dev>"; process.env.RESEND_FROM_EMAIL ?? "OpenMonetis <onboarding@resend.dev>";
if (!resendApiKey) { if (!resendApiKey) {
return { return {

View File

@@ -2,7 +2,7 @@ import { RiGroupLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Pagadores | Opensheets", title: "Pagadores | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiInboxLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Pré-Lançamentos | Opensheets", title: "Pré-Lançamentos | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiFileChartLine } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Tendências | Opensheets", title: "Tendências | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiBankCard2Line } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Uso de Cartões | Opensheets", title: "Uso de Cartões | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -2,7 +2,7 @@ import { RiStore2Line } from "@remixicon/react";
import PageDescription from "@/components/page-description"; import PageDescription from "@/components/page-description";
export const metadata = { export const metadata = {
title: "Top Estabelecimentos | Opensheets", title: "Top Estabelecimentos | OpenMonetis",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -21,6 +21,7 @@ import {
RiTimeLine, RiTimeLine,
RiWalletLine, RiWalletLine,
} from "@remixicon/react"; } from "@remixicon/react";
import { headers } from "next/headers";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { AnimatedThemeToggler } from "@/components/animated-theme-toggler"; import { AnimatedThemeToggler } from "@/components/animated-theme-toggler";
@@ -32,6 +33,13 @@ import { getOptionalUserSession } from "@/lib/auth/server";
export default async function Page() { export default async function Page() {
const session = await getOptionalUserSession(); const session = await getOptionalUserSession();
const headersList = await headers();
const hostname = headersList.get("host")?.replace(/:\d+$/, "");
const publicDomain = process.env.PUBLIC_DOMAIN?.replace(
/^https?:\/\//,
"",
).replace(/:\d+$/, "");
const isPublicDomain = publicDomain && hostname === publicDomain;
return ( return (
<div className="flex min-h-screen flex-col"> <div className="flex min-h-screen flex-col">
@@ -66,27 +74,28 @@ export default async function Page() {
<nav className="flex items-center gap-2 md:gap-4"> <nav className="flex items-center gap-2 md:gap-4">
<AnimatedThemeToggler /> <AnimatedThemeToggler />
{session?.user ? ( {!isPublicDomain &&
<Link prefetch href="/dashboard"> (session?.user ? (
<Button variant="outline" size="sm"> <Link prefetch href="/dashboard">
Dashboard <Button variant="outline" size="sm">
</Button> Dashboard
</Link>
) : (
<>
<Link href="/login">
<Button variant="ghost" size="sm">
Entrar
</Button> </Button>
</Link> </Link>
<Link href="/signup"> ) : (
<Button size="sm" className="gap-2"> <>
Começar <Link href="/login">
<RiArrowRightSLine size={16} /> <Button variant="ghost" size="sm">
</Button> Entrar
</Link> </Button>
</> </Link>
)} <Link href="/signup">
<Button size="sm" className="gap-2">
Começar
<RiArrowRightSLine size={16} />
</Button>
</Link>
</>
))}
</nav> </nav>
</div> </div>
</header> </header>
@@ -124,7 +133,7 @@ export default async function Page() {
<div className="flex flex-col sm:flex-row gap-4 mt-4"> <div className="flex flex-col sm:flex-row gap-4 mt-4">
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app" href="https://github.com/felipegcoutinho/openmonetis"
target="_blank" target="_blank"
> >
<Button size="lg" className="gap-2 w-full sm:w-auto"> <Button size="lg" className="gap-2 w-full sm:w-auto">
@@ -133,7 +142,7 @@ export default async function Page() {
</Button> </Button>
</Link> </Link>
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app#readme" href="https://github.com/felipegcoutinho/openmonetis#readme"
target="_blank" target="_blank"
> >
<Button <Button
@@ -166,7 +175,7 @@ export default async function Page() {
<div className="mx-auto max-w-6xl"> <div className="mx-auto max-w-6xl">
<Image <Image
src="/dashboard-preview-light.png" src="/dashboard-preview-light.png"
alt="opensheets Dashboard Preview" alt="openmonetis Dashboard Preview"
width={1920} width={1920}
height={1080} height={1080}
className="w-full h-auto dark:hidden" className="w-full h-auto dark:hidden"
@@ -174,7 +183,7 @@ export default async function Page() {
/> />
<Image <Image
src="/dashboard-preview-dark.png" src="/dashboard-preview-dark.png"
alt="opensheets Dashboard Preview" alt="openmonetis Dashboard Preview"
width={1920} width={1920}
height={1080} height={1080}
className="w-full h-auto hidden dark:block" className="w-full h-auto hidden dark:block"
@@ -581,7 +590,7 @@ export default async function Page() {
</h3> </h3>
<code className="text-sm bg-muted px-2 py-1 rounded"> <code className="text-sm bg-muted px-2 py-1 rounded">
git clone git clone
https://github.com/felipegcoutinho/opensheets-app.git https://github.com/felipegcoutinho/openmonetis.git
</code> </code>
</div> </div>
</div> </div>
@@ -658,7 +667,7 @@ export default async function Page() {
<div className="mt-8 text-center"> <div className="mt-8 text-center">
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app#-início-rápido" href="https://github.com/felipegcoutinho/openmonetis#-início-rápido"
target="_blank" target="_blank"
className="text-sm text-primary hover:underline" className="text-sm text-primary hover:underline"
> >
@@ -678,7 +687,7 @@ export default async function Page() {
Para quem funciona? Para quem funciona?
</h2> </h2>
<p className="text-lg text-muted-foreground"> <p className="text-lg text-muted-foreground">
O opensheets funciona melhor se você: O openmonetis funciona melhor se você:
</p> </p>
</div> </div>
@@ -765,7 +774,7 @@ export default async function Page() {
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center"> <div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app" href="https://github.com/felipegcoutinho/openmonetis"
target="_blank" target="_blank"
> >
<Button size="lg" className="gap-2 w-full sm:w-auto"> <Button size="lg" className="gap-2 w-full sm:w-auto">
@@ -774,7 +783,7 @@ export default async function Page() {
</Button> </Button>
</Link> </Link>
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app#-início-rápido" href="https://github.com/felipegcoutinho/openmonetis#-início-rápido"
target="_blank" target="_blank"
> >
<Button <Button
@@ -808,7 +817,7 @@ export default async function Page() {
<ul className="space-y-3 text-sm text-muted-foreground"> <ul className="space-y-3 text-sm text-muted-foreground">
<li> <li>
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app" href="https://github.com/felipegcoutinho/openmonetis"
target="_blank" target="_blank"
className="hover:text-foreground transition-colors flex items-center gap-2" className="hover:text-foreground transition-colors flex items-center gap-2"
> >
@@ -818,7 +827,7 @@ export default async function Page() {
</li> </li>
<li> <li>
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app#readme" href="https://github.com/felipegcoutinho/openmonetis#readme"
target="_blank" target="_blank"
className="hover:text-foreground transition-colors" className="hover:text-foreground transition-colors"
> >
@@ -827,7 +836,7 @@ export default async function Page() {
</li> </li>
<li> <li>
<Link <Link
href="https://github.com/felipegcoutinho/opensheets-app/issues" href="https://github.com/felipegcoutinho/openmonetis/issues"
target="_blank" target="_blank"
className="hover:text-foreground transition-colors" className="hover:text-foreground transition-colors"
> >
@@ -850,8 +859,8 @@ export default async function Page() {
<div className="border-t mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted-foreground"> <div className="border-t mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted-foreground">
<p> <p>
© {new Date().getFullYear()} opensheets. Projeto open source sob © {new Date().getFullYear()} openmonetis. Projeto open source
licença MIT. sob licença MIT.
</p> </p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<RiShieldCheckLine size={16} className="text-primary" /> <RiShieldCheckLine size={16} className="text-primary" />

View File

@@ -4,7 +4,7 @@ import { db } from "@/lib/db";
const APP_VERSION = "1.0.0"; const APP_VERSION = "1.0.0";
/** /**
* Health check endpoint para Docker, monitoring e OpenSheets Companion * Health check endpoint para Docker, monitoring e OpenMonetis Companion
* GET /api/health * GET /api/health
* *
* Retorna status 200 se a aplicação está saudável * Retorna status 200 se a aplicação está saudável
@@ -20,7 +20,7 @@ export async function GET() {
return NextResponse.json( return NextResponse.json(
{ {
status: "ok", status: "ok",
name: "OpenSheets", name: "OpenMonetis",
version: APP_VERSION, version: APP_VERSION,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}, },
@@ -33,7 +33,7 @@ export async function GET() {
return NextResponse.json( return NextResponse.json(
{ {
status: "error", status: "error",
name: "OpenSheets", name: "OpenMonetis",
version: APP_VERSION, version: APP_VERSION,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
message: "Database connection failed", message: "Database connection failed",

View File

@@ -7,8 +7,9 @@ import { allFontVariables } from "@/public/fonts/font_index";
import "./globals.css"; import "./globals.css";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Opensheets", title: "OpenMonetis | Suas finanças, do seu jeito",
description: "Finanças pessoais descomplicadas.", description:
"Controle suas finanças pessoais de forma simples e transparente.",
}; };
export default function RootLayout({ export default function RootLayout({
@@ -19,7 +20,7 @@ export default function RootLayout({
return ( return (
<html lang="en" className={allFontVariables} suppressHydrationWarning> <html lang="en" className={allFontVariables} suppressHydrationWarning>
<head> <head>
<meta name="apple-mobile-web-app-title" content="Opensheets" /> <meta name="apple-mobile-web-app-title" content="OpenMonetis" />
</head> </head>
<body className="antialiased" suppressHydrationWarning> <body className="antialiased" suppressHydrationWarning>
<ThemeProvider attribute="class" defaultTheme="light"> <ThemeProvider attribute="class" defaultTheme="light">

View File

@@ -1,6 +1,6 @@
{ {
"name": "Opensheets", "name": "OpenMonetis",
"short_name": "Opensheets", "short_name": "OpenMonetis",
"icons": [ "icons": [
{ {
"src": "/web-app-manifest-192x192.png", "src": "/web-app-manifest-192x192.png",

View File

@@ -141,7 +141,7 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) {
<h3 className="font-medium">Dispositivos conectados</h3> <h3 className="font-medium">Dispositivos conectados</h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Gerencie os dispositivos que podem enviar notificações para o Gerencie os dispositivos que podem enviar notificações para o
OpenSheets. OpenMonetis.
</p> </p>
</div> </div>
<Dialog <Dialog
@@ -163,7 +163,7 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) {
<DialogHeader> <DialogHeader>
<DialogTitle>Criar Token de API</DialogTitle> <DialogTitle>Criar Token de API</DialogTitle>
<DialogDescription> <DialogDescription>
Crie um token para conectar o OpenSheets Companion no seu Crie um token para conectar o OpenMonetis Companion no seu
dispositivo Android. dispositivo Android.
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
@@ -204,7 +204,7 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) {
<DialogHeader> <DialogHeader>
<DialogTitle>Token Criado</DialogTitle> <DialogTitle>Token Criado</DialogTitle>
<DialogDescription> <DialogDescription>
Copie o token abaixo e cole no app OpenSheets Companion. Copie o token abaixo e cole no app OpenMonetis Companion.
Este token Este token
<strong> não será exibido novamente</strong>. <strong> não será exibido novamente</strong>.
</DialogDescription> </DialogDescription>

View File

@@ -39,7 +39,7 @@ const steps: {
<> <>
Baixe o APK no{" "} Baixe o APK no{" "}
<a <a
href="https://github.com/felipegcoutinho/opensheets-companion" href="https://github.com/felipegcoutinho/openmonetis-companion"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline-flex items-center gap-0.5 text-primary hover:underline" className="inline-flex items-center gap-0.5 text-primary hover:underline"
@@ -63,7 +63,7 @@ const steps: {
{ {
icon: RiShieldCheckLine, icon: RiShieldCheckLine,
title: "Pronto!", title: "Pronto!",
description: "Notificações serão enviadas ao OpenSheets.", description: "Notificações serão enviadas ao OpenMonetis.",
}, },
]; ];
@@ -74,7 +74,7 @@ export function CompanionTab({ tokens }: CompanionTabProps) {
{/* Header */} {/* Header */}
<div> <div>
<div className="flex items-center gap-2 mb-1"> <div className="flex items-center gap-2 mb-1">
<h2 className="text-lg font-bold">OpenSheets Companion</h2> <h2 className="text-lg font-bold">OpenMonetis Companion</h2>
<span className="inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-xs font-medium text-success dark:bg-success/10"> <span className="inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-xs font-medium text-success dark:bg-success/10">
<RiAndroidLine className="h-3 w-3" /> <RiAndroidLine className="h-3 w-3" />
Android Android

View File

@@ -108,7 +108,7 @@ export function LoginForm({ className, ...props }: DivProps) {
noValidate noValidate
> >
<FieldGroup className="gap-4"> <FieldGroup className="gap-4">
<AuthHeader title="Entrar no Opensheets" /> <AuthHeader title="Entrar no OpenMonetis" />
<AuthErrorAlert error={error} /> <AuthErrorAlert error={error} />

View File

@@ -25,7 +25,7 @@ import {
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const GITHUB_REPO_BASE = "https://github.com/felipegcoutinho/opensheets-app"; const GITHUB_REPO_BASE = "https://github.com/felipegcoutinho/openmonetis";
const GITHUB_DISCUSSIONS_BASE = `${GITHUB_REPO_BASE}/discussions/new`; const GITHUB_DISCUSSIONS_BASE = `${GITHUB_REPO_BASE}/discussions/new`;
const GITHUB_ISSUES_URL = `${GITHUB_REPO_BASE}/issues/new`; const GITHUB_ISSUES_URL = `${GITHUB_REPO_BASE}/issues/new`;
@@ -58,7 +58,7 @@ const feedbackCategories = [
id: "experience", id: "experience",
title: "Compartilhar Experiência", title: "Compartilhar Experiência",
icon: RiStarLine, icon: RiStarLine,
description: "Como o OpenSheets tem ajudado você?", description: "Como o OpenMonetis tem ajudado você?",
color: "text-purple-500 dark:text-purple-400", color: "text-purple-500 dark:text-purple-400",
url: `${GITHUB_DISCUSSIONS_BASE}?category=sua-experiencia`, url: `${GITHUB_DISCUSSIONS_BASE}?category=sua-experiencia`,
}, },

View File

@@ -17,7 +17,7 @@ export function Logo({
return ( return (
<Image <Image
src="/logo_small.png" src="/logo_small.png"
alt="Opensheets" alt="OpenMonetis"
width={32} width={32}
height={32} height={32}
className={cn("object-contain", className)} className={cn("object-contain", className)}
@@ -30,7 +30,7 @@ export function Logo({
<div className={cn("flex items-center gap-1.5 py-4", className)}> <div className={cn("flex items-center gap-1.5 py-4", className)}>
<Image <Image
src="/logo_small.png" src="/logo_small.png"
alt="Opensheets" alt="OpenMonetis"
width={28} width={28}
height={28} height={28}
className="object-contain" className="object-contain"
@@ -38,7 +38,7 @@ export function Logo({
/> />
<Image <Image
src="/logo_text.png" src="/logo_text.png"
alt="Opensheets" alt="OpenMonetis"
width={100} width={100}
height={32} height={32}
className="object-contain dark:invert" className="object-contain dark:invert"

View File

@@ -179,7 +179,7 @@ export function InboxPage({
<EmptyState <EmptyState
media={<RiInboxLine className="size-6 text-primary" />} media={<RiInboxLine className="size-6 text-primary" />}
title={message} title={message}
description="As notificações capturadas pelo app OpenSheets Companion aparecerão aqui. Saiba mais em Ajustes > Companion." description="As notificações capturadas pelo app OpenMonetis Companion aparecerão aqui. Saiba mais em Ajustes > Companion."
/> />
</Card> </Card>
); );

View File

@@ -404,7 +404,7 @@ export const insightsSalvos = pgTable(
}), }),
); );
// ===================== OPENSHEETS COMPANION ===================== // ===================== OPENMONETIS COMPANION =====================
export const tokensApi = pgTable( export const tokensApi = pgTable(
"tokens_api", "tokens_api",

View File

@@ -1,5 +1,5 @@
# Docker Compose para Next.js + PostgreSQL # Docker Compose para Next.js + PostgreSQL
name: opensheets name: openmonetis
# MODOS DE USO: # MODOS DE USO:
# 1. Banco LOCAL (PostgreSQL em container): # 1. Banco LOCAL (PostgreSQL em container):
@@ -22,13 +22,13 @@ services:
# ============================================ # ============================================
db: db:
image: postgres:18-alpine image: postgres:18-alpine
container_name: opensheets_postgres container_name: openmonetis_postgres
restart: unless-stopped restart: unless-stopped
environment: environment:
POSTGRES_USER: ${POSTGRES_USER:-opensheets} POSTGRES_USER: ${POSTGRES_USER:-openmonetis}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-opensheets_dev_password} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-openmonetis_dev_password}
POSTGRES_DB: ${POSTGRES_DB:-opensheets_db} POSTGRES_DB: ${POSTGRES_DB:-openmonetis_db}
# Configurações de performance # Configurações de performance
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C" POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
@@ -48,7 +48,7 @@ services:
test: test:
[ [
"CMD-SHELL", "CMD-SHELL",
"pg_isready -U ${POSTGRES_USER:-opensheets} -d ${POSTGRES_DB:-opensheets_db}", "pg_isready -U ${POSTGRES_USER:-openmonetis} -d ${POSTGRES_DB:-openmonetis_db}",
] ]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
@@ -56,7 +56,7 @@ services:
start_period: 10s start_period: 10s
networks: networks:
- opensheets_network - openmonetis_network
# Descomentar para ativar logs de queries (debug) # Descomentar para ativar logs de queries (debug)
# command: ["postgres", "-c", "log_statement=all"] # command: ["postgres", "-c", "log_statement=all"]
@@ -69,7 +69,7 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: opensheets_app container_name: openmonetis_app
restart: unless-stopped restart: unless-stopped
ports: ports:
@@ -112,7 +112,7 @@ services:
condition: service_healthy condition: service_healthy
networks: networks:
- opensheets_network - openmonetis_network
# Script de inicialização: roda migrations antes de iniciar o app # Script de inicialização: roda migrations antes de iniciar o app
# ATENÇÃO: Em produção, considere rodar migrations separadamente por segurança # ATENÇÃO: Em produção, considere rodar migrations separadamente por segurança
@@ -149,13 +149,13 @@ services:
# ============================================ # ============================================
volumes: volumes:
postgres_data: postgres_data:
name: opensheets_postgres_data name: openmonetis_postgres_data
driver: local driver: local
# ============================================ # ============================================
# Networks # Networks
# ============================================ # ============================================
networks: networks:
opensheets_network: openmonetis_network:
name: opensheets_network name: openmonetis_network
driver: bridge driver: bridge

View File

@@ -100,7 +100,7 @@ const buildHtmlBody = ({
</table> </table>
<p style="margin:0;font-size:12px;color:#94a3b8;"> <p style="margin:0;font-size:12px;color:#94a3b8;">
Enviado automaticamente por ${userLabel} via Opensheets. Enviado automaticamente por ${userLabel} via OpenMonetis.
</p> </p>
</div> </div>
`; `;
@@ -119,7 +119,7 @@ export async function sendPagadorAutoEmails({
const resendApiKey = process.env.RESEND_API_KEY; const resendApiKey = process.env.RESEND_API_KEY;
const resendFrom = const resendFrom =
process.env.RESEND_FROM_EMAIL ?? "Opensheets <onboarding@resend.dev>"; process.env.RESEND_FROM_EMAIL ?? "OpenMonetis <onboarding@resend.dev>";
if (!resendApiKey) { if (!resendApiKey) {
console.warn( console.warn(

View File

@@ -1,5 +1,5 @@
{ {
"name": "opensheets", "name": "openmonetis",
"version": "1.5.0", "version": "1.5.0",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -22,6 +22,21 @@ const PUBLIC_AUTH_ROUTES = ["/login", "/signup"];
export default async function proxy(request: NextRequest) { export default async function proxy(request: NextRequest) {
const { pathname } = request.nextUrl; const { pathname } = request.nextUrl;
// Multi-domain: block all routes except landing on public domain
// Normalize PUBLIC_DOMAIN: strip protocol and port if provided
const publicDomain = process.env.PUBLIC_DOMAIN?.replace(
/^https?:\/\//,
"",
).replace(/:\d+$/, "");
const hostname = request.headers.get("host")?.replace(/:\d+$/, "");
if (publicDomain && hostname === publicDomain) {
if (pathname !== "/") {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
}
// Validate actual session, not just cookie existence // Validate actual session, not just cookie existence
const session = await auth.api.getSession({ const session = await auth.api.getSession({
headers: request.headers, headers: request.headers,
@@ -49,6 +64,7 @@ export default async function proxy(request: NextRequest) {
export const config = { export const config = {
// Apply middleware to protected and auth routes // Apply middleware to protected and auth routes
matcher: [ matcher: [
"/",
"/ajustes/:path*", "/ajustes/:path*",
"/anotacoes/:path*", "/anotacoes/:path*",
"/calendario/:path*", "/calendario/:path*",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 26 KiB