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:
15
.env.example
15
.env.example
@@ -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=
|
||||||
|
|||||||
4
.github/copilot-instructions.md
vendored
4
.github/copilot-instructions.md
vendored
@@ -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
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
@@ -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
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
# ============================================
|
# ============================================
|
||||||
# OPENSHEETS - .gitignore
|
# OPENMONETIS - .gitignore
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
# === Dependencies ===
|
# === Dependencies ===
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -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
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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,7 +74,8 @@ 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 &&
|
||||||
|
(session?.user ? (
|
||||||
<Link prefetch href="/dashboard">
|
<Link prefetch href="/dashboard">
|
||||||
<Button variant="outline" size="sm">
|
<Button variant="outline" size="sm">
|
||||||
Dashboard
|
Dashboard
|
||||||
@@ -86,7 +95,7 @@ export default async function Page() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</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" />
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|
||||||
|
|||||||
@@ -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`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ export const insightsSalvos = pgTable(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ===================== OPENSHEETS COMPANION =====================
|
// ===================== OPENMONETIS COMPANION =====================
|
||||||
|
|
||||||
export const tokensApi = pgTable(
|
export const tokensApi = pgTable(
|
||||||
"tokens_api",
|
"tokens_api",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "opensheets",
|
"name": "openmonetis",
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
16
proxy.ts
16
proxy.ts
@@ -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 |
Reference in New Issue
Block a user