A minimalist ledger book application for financial tracking based on GitHub repos.
- 📊 Quarterly Organization - Track finances by quarters (Q1-Q4)
- 💰 Invoice Management - Record and monitor sent invoices with payment dates
- 🧾 Expense Tracking - Log business expenses with VAT (multiple), IRPF (15%), payment dates, and the attached document
- 💵 Cashflow View - Monitor bank balance and transaction flow over time with multi-bank support and category tagging
- 🔀 Linking View - Reconcile invoices or expenses with their cashflow entries side-by-side, with date-ordered rows
- 📥 Bank Imports - Import Revolut CSV files from the repository
import/folder into cashflow - 🌍 Bilingual Support - Switch between Spanish (ES) and English (EN)
- 🔗 GitHub Data Storage - Store and sync your financial data from GitHub repositories
Peris stores financial data in GitHub repositories as JSON files. This allows you to:
- Keep your data in version control with traceability
- Access from anywhere, GitHub is your backend
The app comes with sample data that's read from a public repository. This is perfect for exploring Peris without setting up your own data.
To use your own financial data:
-
Create a GitHub Repository
- Create a new repository (can be private)
- Optionally, organize your data in a folder (e.g.,
data/orfinancials/) so the same repo may contain multiple companies
-
Create JSON Data Files
- Create one folder per quarter:
2025.1Q/,2025.2Q/, etc. - Inside each quarter folder, create three JSON files:
invoices.json- List of invoices for that quarterexpenses.json- List of expenses for that quartercashflow.json- Bank transactions for that quarter
- Example structure:
peris-data/finances/2025.4Q/invoices.json - See sample
- Create one folder per quarter:
-
Create a Fine-Grained Personal Access Token
⚠️ SECURITY WARNING- Go to GitHub Settings → Developer Settings → Personal access tokens → Fine-grained tokens
- Click "Generate new token"
- Token settings:
- Expiration: Set an expiration date (recommended: 90 days or less)
- Resource owner: Select the repository owner
- Repository access: Select "Only select repositories" → Choose your Peris data repository
- Permissions: Select "Repository permissions" → Contents: either Read-only or Read and write if you want to commit changes
- Copy the token immediately (you'll only see it once!)
- Never commit tokens to version control
- Alternative: If you prefer, classic personal access tokens still work (select
reposcope) but it gives access to all your private repos
-
Add Your Repository to Peris
- Click the "Manage storages" button at the bottom of the sidebar
- Click "Add new storage"
- Fill in:
- Name: A name for your storage (e.g., "My Company 2025")
- Repository URL: Your GitHub repository URL with token and path
- Format:
https://[PAT@]github.com/owner/repo/path/to/quarters - Example:
https://ghp_xxxxxxxxxxxx@github.com/pablonete/peris-data/finances - The path should point to the folder containing your quarter folders (e.g.,
finances/where your2025.1Q/,2025.2Q/folders are)
- Format:
- Save to localStorage: Check to remember this connection on personal computers; uncheck on shared/public ones
- Click "Test connection" to verify access
- Click "Add" to save
-
Switch Between Storages
- Use the dropdown at the bottom of the sidebar to switch between storages
- All views will update to show data from the selected storage
-
Creating New Quarters
- Once you have a storage connected with write permissions, you can create new quarters directly with the "+" button next to "Quarters" in the sidebar
When you edit data in Peris, changes are kept in memory until you commit them
Your repository structure should look like:
finances/
├── peris.json
├── import/
│ ├── revolut-2026-01.csv
│ └── revolut-2026-01.peris-2026-03-07T16-10-31.772Z.log.txt
├── 2025.1Q/
│ ├── invoices.json
│ ├── expenses.json
│ └── cashflow.json
├── 2025.2Q/
│ ├── invoices.json
│ ├── expenses.json
│ └── cashflow.json
└── ...
peris.json - Optional global configuration at the root of the data path:
{
"categories": [
"tax",
"tax.vat",
"tax.labour-retention",
"payroll",
"internet",
"bank"
]
}invoices.json - Array of invoices:
[
{
"id": "inv-001",
"date": "2025-01-15",
"number": "001",
"client": "Client Name",
"concept": "Services",
"subtotal": 1000,
"vat": 210,
"total": 1210,
"paymentDate": "2025-02-01"
}
]expenses.json - Array of expenses:
[
{
"id": "exp-001",
"date": "2025-01-10",
"number": "001",
"vendor": "Vendor Name",
"concept": "Office supplies",
"vat": [{ "subtotal": 100, "rate": 21, "amount": 21 }],
"taxRetention": 15,
"paymentDate": "2025-01-15"
}
]cashflow.json - Array of transactions with metadata:
[
{
"date": "2025-01-15",
"concept": "Invoice received",
"bankName": "Unicaja",
"bankSequence": 1,
"income": 1210,
"balance": 6210,
"periodicity": "3mo",
"category": "tax.vat"
}
]import/ - Optional bank import workspace at the root of the data path:
- Place bank exports here before importing them from the Cashflow view
- Peris currently supports Revolut and Unicaja CSV files
- Each import writes a sibling
.log.txtfile describing per-row actions and the final summary
If your data repository contains expense PDFs, do not store them with Git LFS (Large File Storage). There are two reasons:
- Every checkout fetches all LFS objects. PDFs are rarely changed or deleted, so even when
clonecan be faster ignoring them, thecheckoutmust download every PDF in the repo, except those deleted or replaced which typically is a very small percentage — even in CI or Copilot agent sessions that only need the JSON data files. - GitHub LFS bandwidth budget is limited. Automated runs (GitHub Actions, Copilot agents) each trigger a full checkout, which rapidly exhausts the monthly LFS bandwidth quota. Once the budget is gone the repository can no longer be checked out until the quota resets or is increased.
Recommendation: commit PDF files directly to Git (no LFS). PDFs in a personal accounting repo are small in number and rarely re-downloaded by humans, so the standard Git object store is a better fit than LFS for this use case.
-
Token Storage: Your PAT is stored in browser
localStorage. This is suitable for:- Personal computers
- Private machines
- Development environments
- Not recommended: Public computers or shared machines
-
Token Restrictions: Always create tokens with minimum required permissions:
- Recommended: Use Fine-Grained Personal Access Tokens scoped to a single repository with read-only "Contents" permission
- Alternative: Classic PATs with
reposcope (read-only) also work but have broader permissions - Each storage should use a separate token if possible
- Regularly review and revoke unused tokens
- Set token expiration dates (90 days recommended)
-
Private Repositories: Create a private repository for sensitive financial data
-
No Backend: All operations are client-side via GitHub API. Peris never stores your data on external servers.
- Next.js 16 - React framework with App Router
- React 19 - UI library
- TypeScript - Type safety
- Tailwind CSS - Styling
- Radix UI - Accessible component primitives
- Recharts - Data visualization
- Vitest - Unit testing framework
- Storybook - Component development and documentation
- Node.js 20+
- pnpm
- Clone the repository:
git clone https://github.com/pablonete/peris.git
cd peris- Install dependencies:
pnpm install- Run the development server:
pnpm dev- Open http://localhost:3000 in your browser
- Use the sidebar to switch between quarters
- Once a quarter is selected, use the tabs at the top (Invoices, Expenses, Cashflow, Linking) to switch views
- In Cashflow, use Import to pick a bank export from the repository
import/folder and stage the resulting cashflow updates plus the generated log file - The active view is preserved when switching quarters
Switch between Spanish and English using the ES | EN toggle at the bottom of the sidebar.
- Welcome - Overview of all quarters with key financial metrics
- Invoices - Detailed list of sent invoices with totals and payment dates
- Expenses - Business expenses with VAT rates (multiple), IRPF tax withholding, payment dates, PDFs, and paid/pending status summary
- Cashflow - Month-by-month bank balance and transactions
- Linking - Side-by-side reconciliation of invoices or expenses with cashflow entries; rows sorted by date so unlinked items appear at their temporal position
pnpm dev # Start development server
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run ESLint
pnpm format # Format code with Prettier
pnpm test # Run tests in watch mode
pnpm test:run # Run tests once
pnpm test:ui # Run tests with UI
pnpm test:coverage # Run tests with coverage report
pnpm storybook # Start Storybook development server
pnpm build-storybook # Build Storybook to out/storybookperis/
├── app/ # Next.js app directory with routes
├── components/ # React components
│ └── ui/ # Radix UI component library
├── lib/ # Utilities, helpers, and business logic
├── public/ # Static assets
└── styles/ # Global styles
The app can be deployed to GitHub Pages:
- Enable GitHub Pages in repository settings (Source: GitHub Actions)
- Push to
mainbranch to trigger automatic deployment - Visit:
https://[username].github.io/peris - Storybook is available at:
https://[username].github.io/peris/storybook
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open source and available under the MIT License.
Started with v0 and then developed with Copilot on GitHub.