├── .dockerignore
├── .editorconfig
├── .env.example
├── .env.release
├── .env.testing
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── config.yml
├── images
│ ├── any-bank.png
│ ├── cashflow.png
│ ├── global.png
│ ├── header.png
│ ├── preview.png
│ ├── private-sync.png
│ ├── self-host.png
│ └── tagging.png
└── workflows
│ ├── action_app-publish-edge.yml
│ ├── action_app-publish-release.yml
│ ├── action_marketing-site-preview.yml
│ ├── action_marketing-site-publish.yml
│ ├── scheduled-task_update-sponsors.yml
│ ├── service_deploy-static-site.yml
│ ├── service_docker-build-and-publish.yml
│ ├── service_install-and-build-node.yml
│ └── service_install-and-test-php.yml
├── .gitignore
├── .gitpod.Dockerfile
├── .gitpod.yml
├── .infrastructure
├── conf
│ └── traefik
│ │ ├── dev
│ │ ├── certificates
│ │ │ ├── local-dev-key.pem
│ │ │ └── local-dev.pem
│ │ ├── traefik-certs.yml
│ │ └── traefik.yml
│ │ └── prod
│ │ └── traefik.yml
└── volume_data
│ └── .gitignore
├── CONTRIBUTING.md
├── Dockerfile.node
├── Dockerfile.php
├── LICENSE
├── Modules
├── Initialize
│ ├── app
│ │ ├── Actions
│ │ │ ├── CreateAccounts.php
│ │ │ ├── CreateTransactions.php
│ │ │ └── CreateUser.php
│ │ ├── Console
│ │ │ ├── InitializeDemo.php
│ │ │ └── InitializeFresh.php
│ │ ├── Data
│ │ │ └── merchants.json
│ │ └── Providers
│ │ │ ├── .gitkeep
│ │ │ ├── EventServiceProvider.php
│ │ │ └── InitializeServiceProvider.php
│ ├── composer.json
│ ├── config
│ │ ├── .gitkeep
│ │ └── config.php
│ ├── database
│ │ ├── factories
│ │ │ └── .gitkeep
│ │ ├── migrations
│ │ │ └── .gitkeep
│ │ └── seeders
│ │ │ ├── .gitkeep
│ │ │ └── InitializeDatabaseSeeder.php
│ ├── module.json
│ └── tests
│ │ ├── Feature
│ │ └── .gitkeep
│ │ └── Unit
│ │ └── .gitkeep
└── Transaction
│ ├── app
│ ├── Data
│ │ └── TransactionData.php
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── .gitkeep
│ │ │ ├── Api
│ │ │ │ └── TransactionController.php
│ │ │ ├── ImportController.php
│ │ │ └── TransactionController.php
│ │ └── Requests
│ │ │ ├── StoreTransactionRequest.php
│ │ │ └── UpdateTransactionRequest.php
│ ├── Models
│ │ └── Transaction.php
│ ├── Providers
│ │ ├── .gitkeep
│ │ ├── EventServiceProvider.php
│ │ ├── RouteServiceProvider.php
│ │ └── TransactionServiceProvider.php
│ └── Services
│ │ ├── ImportTransactions.php
│ │ ├── IndexTransactions.php
│ │ ├── StoreTransaction.php
│ │ └── UpdateTransaction.php
│ ├── composer.json
│ ├── config
│ ├── .gitkeep
│ └── config.php
│ ├── database
│ ├── factories
│ │ └── .gitkeep
│ ├── migrations
│ │ ├── .gitkeep
│ │ ├── 2024_02_03_175535_added_transactions.php
│ │ └── 2024_06_03_224410_renamed_description_to_notes_transactions.php
│ └── seeders
│ │ ├── .gitkeep
│ │ └── TransactionsDatabaseSeeder.php
│ ├── module.json
│ ├── routes
│ ├── .gitkeep
│ ├── api.php
│ └── web.php
│ └── tests
│ ├── Feature
│ └── .gitkeep
│ └── Unit
│ └── .gitkeep
├── README.md
├── SECURITY.md
├── app
├── Console
│ ├── Commands
│ │ ├── SeedCategories.php
│ │ └── SetUpInstitutions.php
│ └── Kernel.php
├── Data
│ ├── CashAccountData.php
│ ├── CreditCardData.php
│ ├── LoanData.php
│ └── Rules
│ │ └── StoreRuleData.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── AccountController.php
│ │ ├── Auth
│ │ │ ├── AuthenticatedSessionController.php
│ │ │ ├── ConfirmablePasswordController.php
│ │ │ ├── EmailVerificationNotificationController.php
│ │ │ ├── EmailVerificationPromptController.php
│ │ │ ├── NewPasswordController.php
│ │ │ ├── PasswordController.php
│ │ │ ├── PasswordResetLinkController.php
│ │ │ ├── RegisteredUserController.php
│ │ │ └── VerifyEmailController.php
│ │ ├── BudgetController.php
│ │ ├── CashAccountController.php
│ │ ├── CashFlowController.php
│ │ ├── CategoryController.php
│ │ ├── Controller.php
│ │ ├── CreditCardController.php
│ │ ├── DashboardController.php
│ │ ├── GoalsController.php
│ │ ├── InstitutionController.php
│ │ ├── LoanController.php
│ │ ├── PortfolioController.php
│ │ ├── ProfileController.php
│ │ ├── RulesController.php
│ │ └── SettingsController.php
│ ├── Kernel.php
│ ├── Middleware
│ │ ├── Authenticate.php
│ │ ├── EncryptCookies.php
│ │ ├── HandleInertiaRequests.php
│ │ ├── PreventRequestsDuringMaintenance.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── TrimStrings.php
│ │ ├── TrustHosts.php
│ │ ├── TrustProxies.php
│ │ ├── ValidateSignature.php
│ │ └── VerifyCsrfToken.php
│ └── Requests
│ │ ├── Accounts
│ │ └── StoreAccountRequest.php
│ │ ├── Auth
│ │ └── LoginRequest.php
│ │ ├── Categories
│ │ ├── StoreCategoryRequest.php
│ │ └── UpdateCategoryRequest.php
│ │ ├── Institutions
│ │ ├── StoreInstitutionRequest.php
│ │ └── UpdateInstitutionRequest.php
│ │ ├── Portfolio
│ │ └── UpdatePortfolioRequest.php
│ │ ├── ProfileUpdateRequest.php
│ │ └── Rules
│ │ └── StoreRuleRequest.php
├── Listeners
│ └── Registered
│ │ └── SeedDefaultCategories.php
├── Models
│ ├── CashAccount.php
│ ├── Category.php
│ ├── CreditCard.php
│ ├── Group.php
│ ├── Institution.php
│ ├── Loan.php
│ ├── Rule.php
│ └── User.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
└── Services
│ ├── Accounts
│ └── StoreAccount.php
│ ├── CashAccounts
│ ├── IndexCashAccounts.php
│ └── StoreCashAccount.php
│ ├── Categories
│ ├── DeleteCategory.php
│ ├── IndexCategories.php
│ ├── SeedUserCategories.php
│ ├── StoreCategory.php
│ └── UpdateCategory.php
│ ├── CreditCards
│ ├── IndexCreditCards.php
│ ├── StoreCreditCard.php
│ └── UpdateCreditCard.php
│ ├── Groups
│ └── IndexGroups.php
│ ├── Institutions
│ ├── DeleteInstitution.php
│ ├── IndexInstitutions.php
│ ├── SeedInstitutions.php
│ ├── StoreInstitution.php
│ └── UpdateInstitution.php
│ ├── Loans
│ ├── IndexLoans.php
│ └── StoreLoanAccount.php
│ ├── Portfolio
│ └── UpdatePortfolio.php
│ └── Rules
│ └── StoreRule.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── broadcasting.php
├── cache.php
├── cors.php
├── database.php
├── filesystems.php
├── financial-freedom.php
├── hashing.php
├── logging.php
├── mail.php
├── modules.php
├── queue.php
├── sanctum.php
├── services.php
├── session.php
└── view.php
├── database
├── .gitignore
├── factories
│ └── UserFactory.php
├── migrations
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2014_10_12_100000_create_password_reset_tokens_table.php
│ ├── 2019_08_19_000000_create_failed_jobs_table.php
│ ├── 2019_12_14_000001_create_personal_access_tokens_table.php
│ ├── 2024_01_13_180043_added_default_currency_to_users.php
│ ├── 2024_01_13_184932_added_groups.php
│ ├── 2024_01_13_184933_added_categories.php
│ ├── 2024_01_19_213458_added_institutions.php
│ ├── 2024_01_20_190002_added_cash_accounts.php
│ ├── 2024_01_20_190547_added_credit_cards.php
│ ├── 2024_01_20_190818_added_loans.php
│ ├── 2024_04_24_030908_added_import_map_to_credit_cards.php
│ ├── 2024_04_24_030948_added_import_map_to_loans.php
│ ├── 2024_04_24_031010_added_import_map_to_cash_accounts.php
│ └── 2024_05_15_212852_added_rules.php
└── seeders
│ └── DatabaseSeeder.php
├── docker-compose.ci.yml
├── docker-compose.dev.yml
├── docker-compose.gitpod.yml
├── docker-compose.prod.yml
├── docker-compose.yml
├── docs
├── .env.example
├── .gitignore
├── .npmrc
├── .nvmrc
├── README.md
├── assets
│ └── css
│ │ ├── animations.css
│ │ ├── docsearch.css
│ │ ├── hamburger.css
│ │ └── tailwind.css
├── components
│ ├── Docs
│ │ ├── Anchor.vue
│ │ ├── Eyebrow.vue
│ │ ├── Footer.vue
│ │ ├── Header.vue
│ │ ├── Logo.vue
│ │ ├── ModeToggle.vue
│ │ ├── Navigation.vue
│ │ ├── NavigationGroup.vue
│ │ ├── PageLink.vue
│ │ ├── Search.vue
│ │ ├── SmallPrint.vue
│ │ ├── Tag.vue
│ │ └── TopLevelNavItem.vue
│ ├── DocumentDrivenNotFound.vue
│ ├── Global
│ │ ├── MobileMenu.vue
│ │ └── ServerSideUp.vue
│ ├── Icons
│ │ ├── Anchor.vue
│ │ ├── Arrow.vue
│ │ ├── ChatBubbleIcon.vue
│ │ ├── Check.vue
│ │ ├── CheckIcon.vue
│ │ ├── ClipboardIcon.vue
│ │ ├── EnvelopeIcon.vue
│ │ ├── Moon.vue
│ │ ├── Resource.vue
│ │ ├── Search.vue
│ │ ├── Social
│ │ │ ├── Discord.vue
│ │ │ ├── GitHub.vue
│ │ │ └── Twitter.vue
│ │ ├── Sun.vue
│ │ ├── UserIcon.vue
│ │ └── UsersIcon.vue
│ └── content
│ │ ├── About.vue
│ │ ├── AppButton.vue
│ │ ├── AppHeading2.vue
│ │ ├── AppHeading3.vue
│ │ ├── AppHeading4.vue
│ │ ├── AppLink.vue
│ │ ├── Code
│ │ ├── ClipboardIcon.vue
│ │ ├── CopyButton.vue
│ │ └── PanelHeader.vue
│ │ ├── CodeGroup.vue
│ │ ├── CodePanel.vue
│ │ ├── Column.vue
│ │ ├── GridPattern.vue
│ │ ├── Guide.vue
│ │ ├── Guides.vue
│ │ ├── HeroPattern.vue
│ │ ├── InfoIcon.vue
│ │ ├── LandingDecentralized.vue
│ │ ├── LandingHero.vue
│ │ ├── LandingScreenshot.vue
│ │ ├── LandingSignup.vue
│ │ ├── LandingStack.vue
│ │ ├── LeadP.vue
│ │ ├── MarketingFollowAlong.vue
│ │ ├── MarketingFooter.vue
│ │ ├── MarketingHeader.vue
│ │ ├── NotProse.vue
│ │ ├── Note.vue
│ │ ├── Properties.vue
│ │ ├── Property.vue
│ │ ├── Resources.vue
│ │ ├── Resources
│ │ ├── Pattern.vue
│ │ ├── Resource.vue
│ │ └── ResourceIcon.vue
│ │ └── Row.vue
├── composables
│ ├── states.ts
│ └── useBreakpoints.ts
├── content
│ ├── docs
│ │ ├── 1.index.md
│ │ ├── 1.installation
│ │ │ └── 2.install-on-synology.md
│ │ └── 6.community
│ │ │ └── 1.contributing.md
│ └── index.md
├── layouts
│ ├── docs.vue
│ └── marketing.vue
├── nuxt.config.ts
├── package.json
├── public
│ └── images
│ │ ├── docs
│ │ └── install-synology
│ │ │ ├── container-manager.png
│ │ │ ├── create-folder.png
│ │ │ ├── create-project-completed.png
│ │ │ └── create-project.png
│ │ ├── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── mstile-150x150.png
│ │ ├── safari-pinned-tab.svg
│ │ └── site.webmanifest
│ │ ├── icons
│ │ ├── bank.svg
│ │ ├── heart.svg
│ │ ├── search-icon.svg
│ │ ├── server.svg
│ │ └── zap.svg
│ │ ├── logos
│ │ ├── amplitude.svg
│ │ ├── docker.svg
│ │ ├── financial-freedom-white-logo.svg
│ │ ├── github-white.svg
│ │ ├── laravel.svg
│ │ ├── mariadb.svg
│ │ ├── meilisearch.svg
│ │ ├── redis.svg
│ │ ├── server-side-up-footer.svg
│ │ ├── server-side-up-logo-horizontal.svg
│ │ ├── spin-logo.svg
│ │ ├── tailwindcss.svg
│ │ └── x-logo.svg
│ │ ├── social-image.png
│ │ └── ui
│ │ ├── app-screenshot.png
│ │ ├── background-pattern.svg
│ │ ├── credit-cards.png
│ │ ├── dan.png
│ │ ├── full-screen-mockup.png
│ │ ├── jay.png
│ │ └── light-accent.png
├── server
│ └── routes
│ │ └── sitemap.xml.ts
├── tailwind.config.js
├── tsconfig.json
├── typography.js
└── yarn.lock
├── jsconfig.json
├── modules_statuses.json
├── package.json
├── phpunit.xml
├── postcss.config.js
├── public
├── .htaccess
├── favicon.ico
├── img
│ └── ui
│ │ └── institution-placeholder.png
├── index.php
└── robots.txt
├── resources
├── css
│ ├── animations.css
│ └── app.css
├── js
│ ├── Components
│ │ ├── ApplicationLogo.vue
│ │ ├── Checkbox.vue
│ │ ├── DangerButton.vue
│ │ ├── Dropdown.vue
│ │ ├── DropdownLink.vue
│ │ ├── Icons
│ │ │ ├── BankIcon.vue
│ │ │ ├── BankModalIcon.vue
│ │ │ ├── BudgetPlanIcon.vue
│ │ │ ├── CashFlowIcon.vue
│ │ │ ├── CoinsIcon.vue
│ │ │ ├── DashboardIcon.vue
│ │ │ ├── FolderIcon.vue
│ │ │ ├── FolderModalIcon.vue
│ │ │ ├── GoalsIcon.vue
│ │ │ ├── LeftArrowIcon.vue
│ │ │ ├── ModalCloseIcon.vue
│ │ │ ├── RightArrowIcon.vue
│ │ │ ├── SettingsIcon.vue
│ │ │ ├── SuccessNotificationIcon.vue
│ │ │ ├── SwitchIcon.vue
│ │ │ ├── TransactionsIcon.vue
│ │ │ ├── TrashModalIcon.vue
│ │ │ └── UploadIcon.vue
│ │ ├── InputError.vue
│ │ ├── InputLabel.vue
│ │ ├── Modal.vue
│ │ ├── NavLink.vue
│ │ ├── Notification.vue
│ │ ├── PrefixTextInput.vue
│ │ ├── PrimaryButton.vue
│ │ ├── ResponsiveNavLink.vue
│ │ ├── SecondaryButton.vue
│ │ ├── SlideOut.vue
│ │ ├── SuffixTextInput.vue
│ │ └── TextInput.vue
│ ├── Composables
│ │ ├── useCategoryColor.js
│ │ ├── useDisplay.js
│ │ ├── useFormatters.js
│ │ └── useImportTransactions.js
│ ├── Layouts
│ │ ├── AuthenticatedLayout.vue
│ │ └── GuestLayout.vue
│ ├── Pages
│ │ ├── Accounts
│ │ │ ├── Index.vue
│ │ │ └── Partials
│ │ │ │ ├── AccountSummary.vue
│ │ │ │ ├── AddAccountModal.vue
│ │ │ │ ├── CashAccountsTable.vue
│ │ │ │ ├── CreditCardsTable.vue
│ │ │ │ ├── EmptyState.vue
│ │ │ │ ├── LoansTable.vue
│ │ │ │ └── NetWorth.vue
│ │ ├── Auth
│ │ │ ├── ConfirmPassword.vue
│ │ │ ├── ForgotPassword.vue
│ │ │ ├── Login.vue
│ │ │ ├── Register.vue
│ │ │ ├── ResetPassword.vue
│ │ │ └── VerifyEmail.vue
│ │ ├── Cash
│ │ │ └── Show.vue
│ │ ├── CreditCards
│ │ │ └── Show.vue
│ │ ├── Dashboard
│ │ │ └── Index.vue
│ │ ├── Demo
│ │ │ └── Index.vue
│ │ ├── Loans
│ │ │ └── Show.vue
│ │ ├── Profile
│ │ │ ├── Edit.vue
│ │ │ └── Partials
│ │ │ │ ├── DeleteUserForm.vue
│ │ │ │ ├── UpdatePasswordForm.vue
│ │ │ │ └── UpdateProfileInformationForm.vue
│ │ ├── Settings
│ │ │ ├── Categories
│ │ │ │ ├── Index.vue
│ │ │ │ └── Partials
│ │ │ │ │ ├── AddCategoryModal.vue
│ │ │ │ │ ├── CategoriesTable.vue
│ │ │ │ │ ├── DeleteCategoryModal.vue
│ │ │ │ │ ├── EditCategoryModal.vue
│ │ │ │ │ └── GroupTable.vue
│ │ │ ├── Index.vue
│ │ │ ├── Institutions
│ │ │ │ ├── Index.vue
│ │ │ │ └── Partials
│ │ │ │ │ ├── AddInstitutionModal.vue
│ │ │ │ │ ├── DeleteInstitutionModal.vue
│ │ │ │ │ ├── EditInstitutionModal.vue
│ │ │ │ │ └── InstitutionTable.vue
│ │ │ └── Partials
│ │ │ │ └── Navigation.vue
│ │ ├── Transactions
│ │ │ ├── Import
│ │ │ │ ├── Index.vue
│ │ │ │ └── Partials
│ │ │ │ │ ├── AddRuleSlideout.vue
│ │ │ │ │ ├── CheckDuplicateModal.vue
│ │ │ │ │ ├── FloatingActions.vue
│ │ │ │ │ ├── ImportRow.vue
│ │ │ │ │ ├── ImportStep.vue
│ │ │ │ │ ├── ImportTable.vue
│ │ │ │ │ ├── MapFields.vue
│ │ │ │ │ ├── SelectAccount.vue
│ │ │ │ │ └── UploadFile.vue
│ │ │ ├── Index.vue
│ │ │ ├── Partials
│ │ │ │ ├── AddTransactionModal.vue
│ │ │ │ ├── Filters.vue
│ │ │ │ └── TransactionsTable.vue
│ │ │ └── Show.vue
│ │ └── Welcome.vue
│ ├── app.js
│ └── bootstrap.js
└── views
│ └── app.blade.php
├── routes
├── api.php
├── auth.php
├── channels.php
├── console.php
└── web.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ ├── .gitignore
│ │ └── data
│ │ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tailwind.config.js
├── tests
├── CreatesApplication.php
├── Feature
│ ├── Auth
│ │ ├── AuthenticationTest.php
│ │ ├── EmailVerificationTest.php
│ │ ├── PasswordConfirmationTest.php
│ │ ├── PasswordResetTest.php
│ │ ├── PasswordUpdateTest.php
│ │ └── RegistrationTest.php
│ ├── ExampleTest.php
│ └── ProfileTest.php
├── TestCase.php
└── Unit
│ └── ExampleTest.php
├── vite-module-loader.js
├── vite.config.js
└── yarn.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | .vault-password
2 | .github
3 | .git
4 | .infrastructure
5 | Dockerfile
6 | docker-*.yml
7 | .gitlab-ci.yml
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.{yml,yaml}]
15 | indent_size = 2
16 |
17 | [docker-compose.yml]
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | ############################################
2 | # Application Settings: Ensure these are correct.
3 | ############################################
4 |
5 | # App Settings
6 | APP_NAME="Financial Freedom"
7 | APP_ENV=local
8 | APP_URL="https://financialfreedom.dev.test"
9 | APP_DEBUG=true
10 | APP_KEY=base64:1234567890abcdefghijklmnopqrstuvwxyz # Run `php artisan key:generate`
11 | VITE_APP_NAME="Financial Freedom"
12 |
13 | # Database Settings
14 | DB_CONNECTION=sqlite
15 | DB_DATABASE=/var/www/html/.infrastructure/volume_data/database.sqlite
16 |
17 | # Mail Settings
18 | MAIL_MAILER=smtp
19 | MAIL_HOST=mailpit
20 | MAIL_PORT=1025
21 | MAIL_USERNAME=null
22 | MAIL_PASSWORD=null
23 | MAIL_ENCRYPTION=null
24 | MAIL_FROM_ADDRESS=noreply@financialfreedom.dev.test
25 | MAIL_FROM_NAME="${APP_NAME}"
26 |
27 | # serversideup/php settings
28 | SSL_MODE=full
29 | AUTORUN_ENABLED=true
30 | AUTORUN_LARAVEL_EVENT_CACHE=false
31 | AUTORUN_LARAVEL_ROUTE_CACHE=false
32 | AUTORUN_LARAVEL_STORAGE_LINK=false
33 | AUTORUN_LARAVEL_VIEW_CACHE=false
34 |
35 | # Financial Freedom Settings
36 | FINANCIAL_FREEDOM_ALLOW_REGISTRATION=false
37 |
38 | ############################################
39 | # Development Settings (don't change these)
40 | ############################################
41 | LOG_CHANNEL=stack
42 |
43 | BROADCAST_DRIVER=log
44 | CACHE_DRIVER=file
45 | QUEUE_CONNECTION=sync
46 | SESSION_LIFETIME=120
47 |
48 | SESSION_DRIVER=cookie
--------------------------------------------------------------------------------
/.env.release:
--------------------------------------------------------------------------------
1 | ############################################
2 | # Application Settings: Ensure these are correct.
3 | ############################################
4 |
5 | # App Settings
6 | APP_NAME="Financial Freedom"
7 | APP_ENV=production
8 |
9 | APP_DEBUG=false # Change to "true" for development
10 |
11 | # Database Settings
12 | DB_CONNECTION=sqlite
13 | DB_DATABASE=/var/www/html/.infrastructure/volume_data/database.sqlite
14 |
15 | # Financial Freedom Settings
16 | FINANCIAL_FREEDOM_ALLOW_REGISTRATION=false
17 |
18 | ############################################
19 | # Development Settings (don't change these)
20 | ############################################
21 | LOG_CHANNEL=stack
22 |
23 | BROADCAST_DRIVER=log
24 | CACHE_DRIVER=file
25 | QUEUE_CONNECTION=sync
26 | SESSION_LIFETIME=120
27 |
28 | SESSION_DRIVER=cookie
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Coming Soon! 😃
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: serversideup
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41B Bug Report"
3 | about: "You found a bug in the code \U0001F914"
4 | title: ''
5 | labels: "Bug: Needs Confirmation 🧐"
6 |
7 | ---
8 |
9 | ## Issue description
10 |
11 |
12 | ## Environment
13 |
14 |
15 | - What's My Browser Support link: {{ paste your support link here }}
16 |
17 | ## Steps to reproduce the issue
18 |
19 | 1.
20 | 2.
21 | 3.
22 |
23 | ## What is expected?
24 |
25 |
26 | ## Link to where issue can be reproduced
27 |
28 |
29 | ## Additional details / screenshots
30 |
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: ❓ Support Question
4 | url: https://github.com/serversideup/financial-freedom/discussions
5 | about: Get friendly support from the community on our forum.
6 |
7 | - name: ✨ Request a feature
8 | url: https://github.com/serversideup/financial-freedom/discussions/63
9 | about: Learn how to request a new feature.
10 |
11 | - name: 🤵 Get Professional Support & Customizations
12 | url: https://serversideup.net/professional-support
13 | about: Skip the line and get priority support directly from the creators of Financial Freedom.
--------------------------------------------------------------------------------
/.github/images/any-bank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/any-bank.png
--------------------------------------------------------------------------------
/.github/images/cashflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/cashflow.png
--------------------------------------------------------------------------------
/.github/images/global.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/global.png
--------------------------------------------------------------------------------
/.github/images/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/header.png
--------------------------------------------------------------------------------
/.github/images/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/preview.png
--------------------------------------------------------------------------------
/.github/images/private-sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/private-sync.png
--------------------------------------------------------------------------------
/.github/images/self-host.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/self-host.png
--------------------------------------------------------------------------------
/.github/images/tagging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/.github/images/tagging.png
--------------------------------------------------------------------------------
/.github/workflows/action_app-publish-edge.yml:
--------------------------------------------------------------------------------
1 | name: Docker Publish (Edge Image)
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - 'docs/**'
9 | schedule:
10 | - cron: '0 8 * * 1'
11 |
12 | jobs:
13 | build-edge:
14 | uses: ./.github/workflows/service_docker-build-and-publish.yml
15 | with:
16 | docker-tags: "serversideup/financial-freedom:edge"
17 | dockerfile: "./Dockerfile.php"
18 | secrets: inherit
19 |
20 | update_container_readme:
21 | runs-on: ubuntu-22.04
22 | name: Push README to Docker Hub
23 | steps:
24 | - name: git checkout
25 | uses: actions/checkout@v4
26 | with:
27 | ref: main
28 |
29 | - name: push README to Dockerhub
30 | uses: peter-evans/dockerhub-description@v4
31 | with:
32 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
33 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
34 | repository: serversideup/financial-freedom
35 | short-description: "🔥🔥🔥 An open source alternative to Mint, YNAB, and more. Stay on budget and build wealth."
--------------------------------------------------------------------------------
/.github/workflows/action_app-publish-release.yml:
--------------------------------------------------------------------------------
1 | name: Docker Publish (Release)
2 | on:
3 | workflow_dispatch:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | release:
9 | uses: ./.github/workflows/service_docker-build-and-publish.yml
10 | with:
11 | docker-tags: "serversideup/financial-freedom:latest,serversideup/financial-freedom:${{ github.ref_name }}"
12 | dockerfile: "./Dockerfile.php"
13 | secrets: inherit
--------------------------------------------------------------------------------
/.github/workflows/action_marketing-site-preview.yml:
--------------------------------------------------------------------------------
1 | name: Site Deployment - Preview 👨🔬
2 |
3 | on:
4 | pull_request:
5 | types: [opened, synchronize, reopened]
6 | paths:
7 | - docs/**
8 |
9 | jobs:
10 | publish-preview-site:
11 | uses: ./.github/workflows/service_deploy-static-site.yml
12 | secrets: inherit
13 | with:
14 | environment-name: 'site-financial-freedom (Preview)'
--------------------------------------------------------------------------------
/.github/workflows/action_marketing-site-publish.yml:
--------------------------------------------------------------------------------
1 | name: Site Deployment - Production 🚀
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths:
7 | - docs/**
8 |
9 | jobs:
10 | publish-production-site:
11 | secrets: inherit
12 | uses: ./.github/workflows/service_deploy-static-site.yml
13 | with:
14 | environment-name: 'site-financial-freedom (Production)'
--------------------------------------------------------------------------------
/.github/workflows/scheduled-task_update-sponsors.yml:
--------------------------------------------------------------------------------
1 | name: Generate Sponsors README
2 | on:
3 | workflow_dispatch:
4 | schedule:
5 | - cron: 30 15 * * 0-6
6 | jobs:
7 | deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout 🛎️
11 | uses: actions/checkout@v3
12 |
13 | - name: Generate Sponsors 💖
14 | uses: JamesIves/github-sponsors-readme-action@v1
15 | with:
16 | organization: true
17 | maximum: 500
18 | fallback: '

'
19 | token: ${{ secrets.SPONSORS_README_ACTION_PERSONAL_ACCESS_TOKEN }}
20 | marker: 'supporters'
21 | template: '
'
22 | file: 'README.md'
23 |
24 | - name: Deploy to GitHub Pages 🚀
25 | uses: JamesIves/github-pages-deploy-action@v4
26 | with:
27 | branch: main
28 | folder: '.'
--------------------------------------------------------------------------------
/.github/workflows/service_deploy-static-site.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_call:
3 | inputs:
4 | environment-name:
5 | required: true
6 | type: string
7 |
8 | jobs:
9 | deploy-static-site:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: read
13 | deployments: write
14 | environment:
15 | name: ${{ inputs.environment-name }}
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Set env file
20 | run: |
21 | if [[ -z "$BASE_64_SECRET" ]]; then
22 | echo '🚨🚨🚨 ENV File not set 🚨🚨🚨' 1>&2
23 | exit 1
24 | fi
25 | echo $BASE_64_SECRET | base64 -d > .env
26 | working-directory: ./docs
27 | env:
28 | BASE_64_SECRET: ${{ secrets.ENV_FILE_BASE64 }}
29 |
30 | - run: |
31 | yarn install --frozen-lockfile
32 | yarn build
33 | npx nuxi generate
34 | working-directory: ./docs
35 |
36 | - name: Publish to Cloudflare Pages
37 | uses: cloudflare/pages-action@v1
38 | with:
39 | apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
40 | accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
41 | projectName: site-financial-freedom
42 | directory: docs/.output/public
43 | branch: ${{ github.head_ref || github.ref_name }}
44 | gitHubToken: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /public/storage
4 | /public/build
5 | /public/css/app.css
6 | /public/js/app.js
7 | /public/js/bug-snatch.js
8 | /public/js/bug-snatch.js.map
9 | /storage/*.key
10 | /vendor
11 | .env
12 | .env.backup
13 | .phpunit.result.cache
14 | .nova
15 | Homestead.json
16 | Homestead.yaml
17 | npm-debug.log
18 | yarn-error.log
19 | report.xml
20 |
21 | # Ignore the _volumes folder, except certain Traefik configs
22 | /_volumes/*
23 | !/_volumes/traefik
24 | .vault-password
25 |
--------------------------------------------------------------------------------
/.gitpod.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM gitpod/workspace-base:latest
2 |
3 | ENV SPIN_ENV="dev,gitpod"
4 |
5 | RUN echo 'export PATH="$HOME/.spin/bin:$PATH"' >> ~/.bashrc && \
6 | touch /home/gitpod/.bash_profile && \
7 | chown gitpod:gitpod /home/gitpod/.bash_profile
--------------------------------------------------------------------------------
/.infrastructure/conf/traefik/dev/traefik-certs.yml:
--------------------------------------------------------------------------------
1 | tls:
2 | stores:
3 | default:
4 | defaultCertificate:
5 | certFile: /certificates/local-dev.pem
6 | keyFile: /certificates/local-dev-key.pem
7 | certificates:
8 | - certFile: /certificates/local-dev.pem
9 | keyFile: /certificates/local-dev-key.pem
10 | stores:
11 | - default
--------------------------------------------------------------------------------
/.infrastructure/conf/traefik/dev/traefik.yml:
--------------------------------------------------------------------------------
1 | # Allow self-signed certificates
2 | serversTransport:
3 | insecureSkipVerify: true
4 |
5 | providers:
6 | docker:
7 | exposedByDefault: false
8 | file:
9 | filename: /traefik-certs.yml
10 | watch: true
11 | entryPoints:
12 | web:
13 | address: ":80"
14 | http:
15 | redirections:
16 | entrypoint:
17 | to: websecure
18 | scheme: https
19 |
20 | websecure:
21 | address: ":443"
22 |
23 | vite:
24 | address: ":5173"
25 |
26 | accessLog: {}
27 | log:
28 | level: ERROR
29 |
30 | api:
31 | dashboard: true
32 | insecure: true
--------------------------------------------------------------------------------
/.infrastructure/volume_data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # View our contributing guidelines
2 | 👉 https://serversideup.net/open-source/financial-freedom/docs/community/contributing
--------------------------------------------------------------------------------
/Dockerfile.node:
--------------------------------------------------------------------------------
1 | FROM node:20 as base
2 |
3 | ### Development
4 | FROM base as development
5 | ARG USER_ID
6 |
7 | RUN usermod -u $USER_ID node
8 |
9 | USER node
--------------------------------------------------------------------------------
/Modules/Initialize/app/Actions/CreateUser.php:
--------------------------------------------------------------------------------
1 | $name,
14 | 'email' => $email,
15 | 'password' => Hash::make($password),
16 | ]);
17 | }
18 | }
--------------------------------------------------------------------------------
/Modules/Initialize/app/Providers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/app/Providers/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | >
13 | */
14 | protected $listen = [];
15 |
16 | /**
17 | * Indicates if events should be discovered.
18 | *
19 | * @var bool
20 | */
21 | protected static $shouldDiscoverEvents = true;
22 |
23 | /**
24 | * Configure the proper event listeners for email verification.
25 | *
26 | * @return void
27 | */
28 | protected function configureEmailVerification(): void
29 | {
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Modules/Initialize/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "financial-freedom/initialize",
3 | "description": "",
4 | "authors": [
5 | {
6 | "name": "Dan Pastori",
7 | "email": "dan@serversideup.net"
8 | }
9 | ],
10 | "extra": {
11 | "laravel": {
12 | "providers": [],
13 | "aliases": {
14 |
15 | }
16 | }
17 | },
18 | "autoload": {
19 | "psr-4": {
20 | "Modules\\Initialize\\": "app/",
21 | "Modules\\Initialize\\Database\\Factories\\": "database/factories/",
22 | "Modules\\Initialize\\Database\\Seeders\\": "database/seeders/"
23 | }
24 | },
25 | "autoload-dev": {
26 | "psr-4": {
27 | "Modules\\Initialize\\Tests\\": "tests/"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Modules/Initialize/config/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/config/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/config/config.php:
--------------------------------------------------------------------------------
1 | 'Initialize',
5 | ];
6 |
--------------------------------------------------------------------------------
/Modules/Initialize/database/factories/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/database/factories/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/database/migrations/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/database/migrations/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/database/seeders/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/database/seeders/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/database/seeders/InitializeDatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call([]);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Modules/Initialize/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Initialize",
3 | "alias": "initialize",
4 | "description": "",
5 | "keywords": [],
6 | "priority": 0,
7 | "providers": [
8 | "Modules\\Initialize\\Providers\\InitializeServiceProvider"
9 | ],
10 | "files": []
11 | }
12 |
--------------------------------------------------------------------------------
/Modules/Initialize/tests/Feature/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/tests/Feature/.gitkeep
--------------------------------------------------------------------------------
/Modules/Initialize/tests/Unit/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Initialize/tests/Unit/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/app/Http/Controllers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/app/Http/Controllers/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/app/Http/Controllers/Api/TransactionController.php:
--------------------------------------------------------------------------------
1 | execute( $request, false );
16 |
17 | return response()->json( $transactions );
18 | }
19 | }
--------------------------------------------------------------------------------
/Modules/Transaction/app/Http/Controllers/ImportController.php:
--------------------------------------------------------------------------------
1 | 'transactions',
22 | 'groups' => fn () => ( new IndexGroups() )->index( $request ),
23 | 'cashAccounts' => fn() => ( new IndexCashAccounts() )->index(),
24 | 'creditCards' => fn() => ( new IndexCreditCards() )->index(),
25 | 'loans' => fn() => ( new IndexLoans() )->index(),
26 | ]);
27 | }
28 |
29 | public function store( Request $request ): RedirectResponse
30 | {
31 | ( new ImportTransactions() )
32 | ->execute(
33 | $request->get('account'),
34 | $request->get('transactions')
35 | );
36 |
37 | return redirect('/transactions');
38 | }
39 | }
--------------------------------------------------------------------------------
/Modules/Transaction/app/Http/Requests/StoreTransactionRequest.php:
--------------------------------------------------------------------------------
1 | 'required',
16 | 'merchant' => 'required',
17 | 'date' => 'required',
18 | 'amount' => 'required',
19 | 'direction' => 'required|in:credit,debit,transfer,payment',
20 | 'category' => 'required',
21 | ];
22 | }
23 |
24 | /**
25 | * Determine if the user is authorized to make this request.
26 | */
27 | public function authorize(): bool
28 | {
29 | return true;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Modules/Transaction/app/Http/Requests/UpdateTransactionRequest.php:
--------------------------------------------------------------------------------
1 | morphTo();
32 | }
33 |
34 | public function category()
35 | {
36 | return $this->belongsTo(Category::class);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Modules/Transaction/app/Providers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/app/Providers/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | >
13 | */
14 | protected $listen = [];
15 |
16 | /**
17 | * Indicates if events should be discovered.
18 | *
19 | * @var bool
20 | */
21 | protected static $shouldDiscoverEvents = true;
22 |
23 | /**
24 | * Configure the proper event listeners for email verification.
25 | *
26 | * @return void
27 | */
28 | protected function configureEmailVerification(): void
29 | {
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Modules/Transaction/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
26 |
27 | $this->mapWebRoutes();
28 | }
29 |
30 | /**
31 | * Define the "web" routes for the application.
32 | *
33 | * These routes all receive session state, CSRF protection, etc.
34 | */
35 | protected function mapWebRoutes(): void
36 | {
37 | Route::middleware('web')->group(module_path('Transaction', '/routes/web.php'));
38 | }
39 |
40 | /**
41 | * Define the "api" routes for the application.
42 | *
43 | * These routes are typically stateless.
44 | */
45 | protected function mapApiRoutes(): void
46 | {
47 | Route::middleware('api')->prefix('api')->name('api.')->group(module_path('Transaction', '/routes/api.php'));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Modules/Transaction/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nwidart/transaction",
3 | "description": "",
4 | "authors": [
5 | {
6 | "name": "Nicolas Widart",
7 | "email": "n.widart@gmail.com"
8 | }
9 | ],
10 | "extra": {
11 | "laravel": {
12 | "providers": [],
13 | "aliases": {
14 |
15 | }
16 | }
17 | },
18 | "autoload": {
19 | "psr-4": {
20 | "Modules\\Transaction\\": "app/",
21 | "Modules\\Transaction\\Database\\Factories\\": "database/factories/",
22 | "Modules\\Transaction\\Database\\Seeders\\": "database/seeders/"
23 | }
24 | },
25 | "autoload-dev": {
26 | "psr-4": {
27 | "Modules\\Transaction\\Tests\\": "tests/"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Modules/Transaction/config/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/config/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/config/config.php:
--------------------------------------------------------------------------------
1 | 'Transaction',
5 | ];
6 |
--------------------------------------------------------------------------------
/Modules/Transaction/database/factories/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/database/factories/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/database/migrations/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/database/migrations/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/database/migrations/2024_06_03_224410_renamed_description_to_notes_transactions.php:
--------------------------------------------------------------------------------
1 | renameColumn('description', 'notes');
16 | });
17 | }
18 |
19 | /**
20 | * Reverse the migrations.
21 | */
22 | public function down(): void
23 | {
24 | Schema::table('transactions', function (Blueprint $table) {
25 | $table->renameColumn('notes', 'description');
26 | });
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/Modules/Transaction/database/seeders/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/database/seeders/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/database/seeders/TransactionsDatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call([]);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Modules/Transaction/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Transaction",
3 | "alias": "transaction",
4 | "description": "",
5 | "keywords": [],
6 | "priority": 0,
7 | "providers": [
8 | "Modules\\Transaction\\Providers\\TransactionServiceProvider"
9 | ],
10 | "files": []
11 | }
12 |
--------------------------------------------------------------------------------
/Modules/Transaction/routes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/routes/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/routes/api.php:
--------------------------------------------------------------------------------
1 | 'transactions'], function () {
18 | Route::get('/', [TransactionController::class, 'index'])
19 | ->name('transaction.index');
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/Modules/Transaction/tests/Feature/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/tests/Feature/.gitkeep
--------------------------------------------------------------------------------
/Modules/Transaction/tests/Unit/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/Modules/Transaction/tests/Unit/.gitkeep
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Reporting a Security Vulnerability
2 | If you find a security vulnerability, please let us know as soon as possible.
3 |
4 | [View Our Responsible Disclosure Policy →](https://www.notion.so/Responsible-Disclosure-Policy-421a6a3be1714d388ebbadba7eebbdc8)
--------------------------------------------------------------------------------
/app/Console/Commands/SeedCategories.php:
--------------------------------------------------------------------------------
1 | seed( $user );
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Console/Commands/SetUpInstitutions.php:
--------------------------------------------------------------------------------
1 | seedUnitedStates();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')->hourly();
16 | }
17 |
18 | /**
19 | * Register the commands for the application.
20 | */
21 | protected function commands(): void
22 | {
23 | $this->load(__DIR__.'/Commands');
24 |
25 | require base_path('routes/console.php');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Data/CashAccountData.php:
--------------------------------------------------------------------------------
1 | user()->id,
26 | institutionId: $request->input('institution_id'),
27 | type: $request->input('type'),
28 | name: $request->input('name'),
29 | description: $request->input('description'),
30 | balance: $request->input('balance'),
31 | interestRate: $request->input('interest_rate') ? $request->input('interest_rate') : 0.00,
32 | );
33 | }
34 | }
--------------------------------------------------------------------------------
/app/Data/CreditCardData.php:
--------------------------------------------------------------------------------
1 | user()->id,
27 | institutionId: $request->input('institution_id'),
28 | brand: $request->input('brand'),
29 | name: $request->input('name'),
30 | description: $request->input('description'),
31 | interestRate: $request->input('interest_rate') ? $request->input('interest_rate') : 0.00,
32 | creditLimit: $request->input('credit_limit'),
33 | balance: $request->input('balance'),
34 | );
35 | }
36 | }
--------------------------------------------------------------------------------
/app/Data/Rules/StoreRuleData.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | protected $dontFlash = [
16 | 'current_password',
17 | 'password',
18 | 'password_confirmation',
19 | ];
20 |
21 | /**
22 | * Register the exception handling callbacks for the application.
23 | */
24 | public function register(): void
25 | {
26 | $this->reportable(function (Throwable $e) {
27 | //
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ConfirmablePasswordController.php:
--------------------------------------------------------------------------------
1 | validate([
30 | 'email' => $request->user()->email,
31 | 'password' => $request->password,
32 | ])) {
33 | throw ValidationException::withMessages([
34 | 'password' => __('auth.password'),
35 | ]);
36 | }
37 |
38 | $request->session()->put('auth.password_confirmed_at', time());
39 |
40 | return redirect()->intended(RouteServiceProvider::HOME);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/EmailVerificationNotificationController.php:
--------------------------------------------------------------------------------
1 | user()->hasVerifiedEmail()) {
18 | return redirect()->intended(RouteServiceProvider::HOME);
19 | }
20 |
21 | $request->user()->sendEmailVerificationNotification();
22 |
23 | return back()->with('status', 'verification-link-sent');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/EmailVerificationPromptController.php:
--------------------------------------------------------------------------------
1 | user()->hasVerifiedEmail()
20 | ? redirect()->intended(RouteServiceProvider::HOME)
21 | : Inertia::render('Auth/VerifyEmail', ['status' => session('status')]);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/PasswordController.php:
--------------------------------------------------------------------------------
1 | validate([
19 | 'current_password' => ['required', 'current_password'],
20 | 'password' => ['required', Password::defaults(), 'confirmed'],
21 | ]);
22 |
23 | $request->user()->update([
24 | 'password' => Hash::make($validated['password']),
25 | ]);
26 |
27 | return back();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/VerifyEmailController.php:
--------------------------------------------------------------------------------
1 | user()->hasVerifiedEmail()) {
19 | return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
20 | }
21 |
22 | if ($request->user()->markEmailAsVerified()) {
23 | event(new Verified($request->user()));
24 | }
25 |
26 | return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Http/Controllers/BudgetController.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/app/Http/Controllers/BudgetController.php
--------------------------------------------------------------------------------
/app/Http/Controllers/CashAccountController.php:
--------------------------------------------------------------------------------
1 | back();
17 | }
18 |
19 | // public function destroy( Account $account ): RedirectResponse
20 | // {
21 | // ( new DeleteAccount() )->delete( $account );
22 | // return redirect()->back();
23 | // }
24 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/CashFlowController.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/app/Http/Controllers/CashFlowController.php
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | 'accounts',
18 | 'creditCard' => $creditCard,
19 | ]);
20 | }
21 |
22 | public function update( Request $request, CreditCard $creditCard ): RedirectResponse
23 | {
24 | ( new UpdateCreditCard( $request, $creditCard ) )->update();
25 | return redirect()->back();
26 | }
27 |
28 | // public function destroy( Account $account ): RedirectResponse
29 | // {
30 | // ( new DeleteAccount() )->delete( $account );
31 | // return redirect()->back();
32 | // }
33 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/DashboardController.php:
--------------------------------------------------------------------------------
1 | 'dashboard'
18 | ] );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Controllers/GoalsController.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/app/Http/Controllers/GoalsController.php
--------------------------------------------------------------------------------
/app/Http/Controllers/LoanController.php:
--------------------------------------------------------------------------------
1 | back();
17 | }
18 |
19 | // public function destroy( Account $account ): RedirectResponse
20 | // {
21 | // ( new DeleteAccount() )->delete( $account );
22 | // return redirect()->back();
23 | // }
24 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/PortfolioController.php:
--------------------------------------------------------------------------------
1 | update( $request );
16 | return redirect()->back();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Controllers/RulesController.php:
--------------------------------------------------------------------------------
1 | execute( $request->toDto() );
17 |
18 | return redirect()->back();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Controllers/SettingsController.php:
--------------------------------------------------------------------------------
1 | 'settings',
16 | 'subGroup' => 'portfolio'
17 | ] );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson() ? null : route('login');
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Middleware/HandleInertiaRequests.php:
--------------------------------------------------------------------------------
1 |
29 | */
30 | public function share(Request $request): array
31 | {
32 | return [
33 | ...parent::share($request),
34 | 'auth' => [
35 | 'user' => $request->user(),
36 | ],
37 | ];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Middleware/PreventRequestsDuringMaintenance.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
24 | return redirect(RouteServiceProvider::HOME);
25 | }
26 | }
27 |
28 | return $next($request);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | 'current_password',
16 | 'password',
17 | 'password_confirmation',
18 | ];
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrustHosts.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | public function hosts(): array
15 | {
16 | return [
17 | $this->allSubdomainsOfApplicationUrl(),
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrustProxies.php:
--------------------------------------------------------------------------------
1 | |string|null
14 | */
15 | protected $proxies;
16 |
17 | /**
18 | * The headers that should be used to detect proxies.
19 | *
20 | * @var int
21 | */
22 | protected $headers =
23 | Request::HEADER_X_FORWARDED_FOR |
24 | Request::HEADER_X_FORWARDED_HOST |
25 | Request::HEADER_X_FORWARDED_PORT |
26 | Request::HEADER_X_FORWARDED_PROTO |
27 | Request::HEADER_X_FORWARDED_AWS_ELB;
28 | }
29 |
--------------------------------------------------------------------------------
/app/Http/Middleware/ValidateSignature.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | // 'fbclid',
16 | // 'utm_campaign',
17 | // 'utm_content',
18 | // 'utm_medium',
19 | // 'utm_source',
20 | // 'utm_term',
21 | ];
22 | }
23 |
--------------------------------------------------------------------------------
/app/Http/Middleware/VerifyCsrfToken.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Requests/Accounts/StoreAccountRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'account_type' => 'required|string',
18 | 'name' => 'required|string',
19 | 'institution_id' => 'required|exists:institutions,id',
20 | 'description' => 'nullable|string',
21 | 'type' => 'nullable|required_unless:account_type,credit-card|string',
22 | 'balance' => 'nullable|numeric',
23 | 'remaining_balance' => 'nullable|required_if:account_type,loan|numeric',
24 | 'original_balance' => 'nullable|required_if:account_type,loan|numeric',
25 | 'payment_amount' => 'nullable|required_if:account_type,loan|numeric',
26 | 'interest_rate' => 'nullable|numeric',
27 | 'date_opened' => 'nullable|date',
28 | 'credit_limit' => 'nullable|numeric',
29 | 'brand' => 'nullable|required_if:account_type,credit-card|string',
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Requests/Categories/StoreCategoryRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'name' => 'required|string',
18 | 'color' => 'required|string',
19 | 'group_id' => 'required|numeric'
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Http/Requests/Categories/UpdateCategoryRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'name' => 'sometimes|string',
18 | 'color' => 'sometimes|string',
19 | 'group_id' => 'sometimes|numeric'
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Http/Requests/Institutions/StoreInstitutionRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'name' => 'required|string'
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Institutions/UpdateInstitutionRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'name' => 'required|string'
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Portfolio/UpdatePortfolioRequest.php:
--------------------------------------------------------------------------------
1 | |string>
13 | */
14 | public function rules(): array
15 | {
16 | return [
17 | 'name' => ['required', 'string'],
18 | 'default_currency' => ['required', 'string'],
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/ProfileUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | public function rules(): array
17 | {
18 | return [
19 | 'name' => ['required', 'string', 'max:255'],
20 | 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($this->user()->id)],
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Http/Requests/Rules/StoreRuleRequest.php:
--------------------------------------------------------------------------------
1 | |string>
22 | */
23 | public function rules(): array
24 | {
25 | return [
26 | 'search_string' => 'required|string',
27 | 'replace_string' => 'required|string',
28 | ];
29 | }
30 |
31 | /**
32 | * Build and return a DTO.
33 | *
34 | * @return StoreRuleData
35 | */
36 | public function toDto(): StoreRuleData
37 | {
38 | return new StoreRuleData(
39 | account: $this->account,
40 | searchString: $this->search_string,
41 | replaceString: $this->replace_string,
42 | category: $this->category,
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/Listeners/Registered/SeedDefaultCategories.php:
--------------------------------------------------------------------------------
1 | user;
25 |
26 | ( new SeedUserCategories() )->seed( $user );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Models/CashAccount.php:
--------------------------------------------------------------------------------
1 | 'object'
29 | ];
30 |
31 | public function user()
32 | {
33 | return $this->hasOne('App\Models\User', 'id', 'user_id');
34 | }
35 |
36 | public function institution()
37 | {
38 | return $this->hasOne('App\Models\Institution', 'id', 'institution_id');
39 | }
40 |
41 | public function rules()
42 | {
43 | return $this->morphMany(Rule::class, 'accountable');
44 | }
45 |
46 | public function getTypeAttribute()
47 | {
48 | return 'cash-account';
49 | }
50 | }
--------------------------------------------------------------------------------
/app/Models/Category.php:
--------------------------------------------------------------------------------
1 | hasOne('App\Models\Group', 'id', 'group_id');
24 | }
25 | }
--------------------------------------------------------------------------------
/app/Models/CreditCard.php:
--------------------------------------------------------------------------------
1 | 'object'
29 | ];
30 |
31 | public function user()
32 | {
33 | return $this->hasOne(User::class, 'id', 'user_id');
34 | }
35 |
36 | public function institution()
37 | {
38 | return $this->hasOne(Institution::class, 'id', 'institution_id');
39 | }
40 |
41 | public function rules()
42 | {
43 | return $this->morphMany(Rule::class, 'accountable');
44 | }
45 |
46 | public function getTypeAttribute()
47 | {
48 | return 'credit-card';
49 | }
50 | }
--------------------------------------------------------------------------------
/app/Models/Group.php:
--------------------------------------------------------------------------------
1 | hasMany('App\Models\Category', 'group_id', 'id');
23 | }
24 | }
--------------------------------------------------------------------------------
/app/Models/Institution.php:
--------------------------------------------------------------------------------
1 | 'object'
31 | ];
32 |
33 | public function user()
34 | {
35 | return $this->hasOne('App\Models\User', 'id', 'user_id');
36 | }
37 |
38 | public function institution()
39 | {
40 | return $this->hasOne('App\Models\Institution', 'id', 'institution_id');
41 | }
42 |
43 | public function rules()
44 | {
45 | return $this->morphMany(Rule::class, 'accountable');
46 | }
47 |
48 | public function getTypeAttribute()
49 | {
50 | return 'loan';
51 | }
52 | }
--------------------------------------------------------------------------------
/app/Models/Rule.php:
--------------------------------------------------------------------------------
1 | morphTo();
23 | }
24 |
25 | public function category()
26 | {
27 | return $this->belongsTo(Category::class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | protected $policies = [
16 | //
17 | ];
18 |
19 | /**
20 | * Register any authentication / authorization services.
21 | */
22 | public function boot(): void
23 | {
24 | //
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | >
17 | */
18 | protected $listen = [
19 | Registered::class => [
20 | SendEmailVerificationNotification::class,
21 | SeedDefaultCategories::class,
22 | ],
23 | ];
24 |
25 | /**
26 | * Register any events for your application.
27 | */
28 | public function boot(): void
29 | {
30 | //
31 | }
32 |
33 | /**
34 | * Determine if events and listeners should be automatically discovered.
35 | */
36 | public function shouldDiscoverEvents(): bool
37 | {
38 | return false;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | by($request->user()?->id ?: $request->ip());
29 | });
30 |
31 | $this->routes(function () {
32 | Route::middleware('api')
33 | ->prefix('api')
34 | ->group(base_path('routes/api.php'));
35 |
36 | Route::middleware('web')
37 | ->group(base_path('routes/web.php'));
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Services/Accounts/StoreAccount.php:
--------------------------------------------------------------------------------
1 | get('account_type') ){
17 | case 'cash':
18 | $cashAccount = CashAccountData::fromCreateRequest( $request );
19 | ( new StoreCashAccount() )->store( $cashAccount );
20 | break;
21 | case 'loan':
22 | $loanAccount = LoanData::fromCreateRequest( $request );
23 | ( new StoreLoanAccount() )->store( $loanAccount );
24 | break;
25 | case 'credit-card':
26 | $creditCard = CreditCardData::fromCreateRequest( $request );
27 | ( new StoreCreditCard() )->store( $creditCard );
28 | break;
29 | }
30 |
31 | }
32 | }
--------------------------------------------------------------------------------
/app/Services/CashAccounts/IndexCashAccounts.php:
--------------------------------------------------------------------------------
1 | with('rules')
13 | ->where('user_id', auth()->id())
14 | ->orderBy('name', 'ASC')
15 | ->get();
16 |
17 | return $cashAccounts;
18 | }
19 | }
--------------------------------------------------------------------------------
/app/Services/CashAccounts/StoreCashAccount.php:
--------------------------------------------------------------------------------
1 | $cashAccountData->userId,
14 | 'institution_id' => $cashAccountData->institutionId,
15 | 'type' => $cashAccountData->type,
16 | 'name' => $cashAccountData->name,
17 | 'description' => $cashAccountData->description,
18 | 'balance' => $cashAccountData->balance,
19 | 'interest_rate' => $cashAccountData->interestRate,
20 | ]);
21 | }
22 | }
--------------------------------------------------------------------------------
/app/Services/Categories/DeleteCategory.php:
--------------------------------------------------------------------------------
1 | delete();
10 | }
11 | }
--------------------------------------------------------------------------------
/app/Services/Categories/IndexCategories.php:
--------------------------------------------------------------------------------
1 | request = $request;
18 | $this->query = Category::query();
19 |
20 | $this->applySearch();
21 | $this->applyOrder();
22 |
23 | if( $this->paginate ){
24 | $categories = $this->query->paginate( $this->take );
25 | }else{
26 | $categories = $this->query->get();
27 | }
28 |
29 | return $categories;
30 | }
31 |
32 | private function applySearch()
33 | {
34 | if( $this->request->has('term') ){
35 | $this->query->where( 'name', 'LIKE', "%{$this->term}%" );
36 | }
37 | }
38 |
39 | private function applyOrder()
40 | {
41 | $this->query->orderBy(
42 | $this->request->input('orderBy', 'name'),
43 | $this->request->input('orderDirection', 'asc')
44 | );
45 | }
46 | }
--------------------------------------------------------------------------------
/app/Services/Categories/StoreCategory.php:
--------------------------------------------------------------------------------
1 | $request->user()->id,
13 | 'group_id' => $request->input('group_id'),
14 | 'name' => $request->input('name'),
15 | 'color' => $request->input('color'),
16 | ]);
17 |
18 | return $category;
19 | }
20 | }
--------------------------------------------------------------------------------
/app/Services/Categories/UpdateCategory.php:
--------------------------------------------------------------------------------
1 | update( $request->validated() );
10 | }
11 | }
--------------------------------------------------------------------------------
/app/Services/CreditCards/IndexCreditCards.php:
--------------------------------------------------------------------------------
1 | with('rules')
13 | ->where('user_id', auth()->id())
14 | ->orderBy('name', 'ASC')
15 | ->get();
16 |
17 | return $creditCards;
18 | }
19 | }
--------------------------------------------------------------------------------
/app/Services/CreditCards/StoreCreditCard.php:
--------------------------------------------------------------------------------
1 | $creditCardData->userId,
14 | 'institution_id' => $creditCardData->institutionId,
15 | 'name' => $creditCardData->name,
16 | 'brand' => $creditCardData->brand,
17 | 'description' => $creditCardData->description,
18 | 'interest_rate' => $creditCardData->interestRate,
19 | 'credit_limit' => $creditCardData->creditLimit,
20 | 'balance' => $creditCardData->balance,
21 | ]);
22 | }
23 | }
--------------------------------------------------------------------------------
/app/Services/CreditCards/UpdateCreditCard.php:
--------------------------------------------------------------------------------
1 | request = $request;
13 | $this->creditCard = $creditCard;
14 | }
15 |
16 | public function update()
17 | {
18 | if( $this->request->has('import_map') ){
19 | $this->creditCard->import_map = $this->request->get('import_map');
20 | }
21 |
22 | $this->creditCard->save();
23 | }
24 | }
--------------------------------------------------------------------------------
/app/Services/Groups/IndexGroups.php:
--------------------------------------------------------------------------------
1 | get();
14 |
15 | return $groups;
16 | }
17 | }
--------------------------------------------------------------------------------
/app/Services/Institutions/DeleteInstitution.php:
--------------------------------------------------------------------------------
1 | delete();
10 | }
11 | }
--------------------------------------------------------------------------------
/app/Services/Institutions/IndexInstitutions.php:
--------------------------------------------------------------------------------
1 | request = $request;
17 | $this->query = Institution::query();
18 |
19 | $this->applyOrder();
20 |
21 | if( $this->paginate ){
22 | $institutions = $this->query->paginate( $this->take );
23 | }else{
24 | $institutions = $this->query->get();
25 | }
26 |
27 | return $institutions;
28 | }
29 |
30 | private function applyOrder()
31 | {
32 | $this->query->orderBy(
33 | $this->request->input('orderBy', 'name'),
34 | $this->request->input('orderDirection', 'asc')
35 | );
36 | }
37 | }
--------------------------------------------------------------------------------
/app/Services/Institutions/StoreInstitution.php:
--------------------------------------------------------------------------------
1 | $request->input('name'),
13 | 'url' => $request->input('url', ''),
14 | ]);
15 |
16 | return $institution;
17 | }
18 | }
--------------------------------------------------------------------------------
/app/Services/Institutions/UpdateInstitution.php:
--------------------------------------------------------------------------------
1 | update([
12 | 'name' => $request->input('name'),
13 | 'url' => $request->input('url', ''),
14 | ]);
15 |
16 | return $institution;
17 | }
18 | }
--------------------------------------------------------------------------------
/app/Services/Loans/IndexLoans.php:
--------------------------------------------------------------------------------
1 | with('rules')
13 | ->where('user_id', auth()->id())
14 | ->orderBy('name', 'ASC')
15 | ->get();
16 |
17 | return $loans;
18 | }
19 | }
--------------------------------------------------------------------------------
/app/Services/Loans/StoreLoanAccount.php:
--------------------------------------------------------------------------------
1 | $loanData->userId,
14 | 'institution_id' => $loanData->institutionId,
15 | 'name' => $loanData->name,
16 | 'type' => $loanData->type,
17 | 'description' => $loanData->description,
18 | 'opened_at' => $loanData->dateOpened,
19 | 'interest_rate' => $loanData->interestRate,
20 | 'remaining_balance' => $loanData->remainingBalance,
21 | 'original_balance' => $loanData->originalBalance,
22 | 'payment_amount' => $loanData->paymentAmount
23 | ]);
24 | }
25 | }
--------------------------------------------------------------------------------
/app/Services/Portfolio/UpdatePortfolio.php:
--------------------------------------------------------------------------------
1 | user()->update( $request->validated() );
12 | }
13 | }
--------------------------------------------------------------------------------
/app/Services/Rules/StoreRule.php:
--------------------------------------------------------------------------------
1 | findAccount( $data->account );
16 |
17 | Rule::create([
18 | 'accountable_id' => $account->id,
19 | 'accountable_type' => get_class( $account ),
20 | 'search_string' => $data->searchString,
21 | 'replace_string' => $data->replaceString,
22 | 'category_id' => $data->category['id'],
23 | ]);
24 | }
25 |
26 | private function findAccount( $account )
27 | {
28 | switch( $account['type'] ){
29 | case 'cash-account':
30 | return CashAccount::find( $account['id'] );
31 | break;
32 | case 'credit-card':
33 | return CreditCard::find( $account['id'] );
34 | break;
35 | case 'loan':
36 | return Loan::find( $account['id'] );
37 | break;
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/config/cors.php:
--------------------------------------------------------------------------------
1 | ['api/*', 'sanctum/csrf-cookie'],
19 |
20 | 'allowed_methods' => ['*'],
21 |
22 | 'allowed_origins' => ['*'],
23 |
24 | 'allowed_origins_patterns' => [],
25 |
26 | 'allowed_headers' => ['*'],
27 |
28 | 'exposed_headers' => [],
29 |
30 | 'max_age' => 0,
31 |
32 | 'supports_credentials' => false,
33 |
34 | ];
35 |
--------------------------------------------------------------------------------
/config/financial-freedom.php:
--------------------------------------------------------------------------------
1 | env('FINANCIAL_FREEDOM_ALLOW_REGISTRATION', false),
17 | ];
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
21 | 'scheme' => 'https',
22 | ],
23 |
24 | 'postmark' => [
25 | 'token' => env('POSTMARK_TOKEN'),
26 | ],
27 |
28 | 'ses' => [
29 | 'key' => env('AWS_ACCESS_KEY_ID'),
30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
32 | ],
33 |
34 | ];
35 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => env(
32 | 'VIEW_COMPILED_PATH',
33 | realpath(storage_path('framework/views'))
34 | ),
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite*
2 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | class UserFactory extends Factory
13 | {
14 | /**
15 | * The current password being used by the factory.
16 | */
17 | protected static ?string $password;
18 |
19 | /**
20 | * Define the model's default state.
21 | *
22 | * @return array
23 | */
24 | public function definition(): array
25 | {
26 | return [
27 | 'name' => fake()->name(),
28 | 'email' => fake()->unique()->safeEmail(),
29 | 'email_verified_at' => now(),
30 | 'password' => static::$password ??= Hash::make('password'),
31 | 'remember_token' => Str::random(10),
32 | ];
33 | }
34 |
35 | /**
36 | * Indicate that the model's email address should be unverified.
37 | */
38 | public function unverified(): static
39 | {
40 | return $this->state(fn (array $attributes) => [
41 | 'email_verified_at' => null,
42 | ]);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | id();
16 | $table->string('name');
17 | $table->string('email')->unique();
18 | $table->timestamp('email_verified_at')->nullable();
19 | $table->string('password');
20 | $table->rememberToken();
21 | $table->timestamps();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | */
28 | public function down(): void
29 | {
30 | Schema::dropIfExists('users');
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php:
--------------------------------------------------------------------------------
1 | string('email')->primary();
16 | $table->string('token');
17 | $table->timestamp('created_at')->nullable();
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | */
24 | public function down(): void
25 | {
26 | Schema::dropIfExists('password_reset_tokens');
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/database/migrations/2019_08_19_000000_create_failed_jobs_table.php:
--------------------------------------------------------------------------------
1 | id();
16 | $table->string('uuid')->unique();
17 | $table->text('connection');
18 | $table->text('queue');
19 | $table->longText('payload');
20 | $table->longText('exception');
21 | $table->timestamp('failed_at')->useCurrent();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | */
28 | public function down(): void
29 | {
30 | Schema::dropIfExists('failed_jobs');
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php:
--------------------------------------------------------------------------------
1 | id();
16 | $table->morphs('tokenable');
17 | $table->string('name');
18 | $table->string('token', 64)->unique();
19 | $table->text('abilities')->nullable();
20 | $table->timestamp('last_used_at')->nullable();
21 | $table->timestamp('expires_at')->nullable();
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | */
29 | public function down(): void
30 | {
31 | Schema::dropIfExists('personal_access_tokens');
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_13_180043_added_default_currency_to_users.php:
--------------------------------------------------------------------------------
1 | string('default_currency')->default('USD')->after('remember_token');
16 | });
17 | }
18 |
19 | /**
20 | * Reverse the migrations.
21 | */
22 | public function down(): void
23 | {
24 | Schema::table('users', function (Blueprint $table) {
25 | //
26 | });
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_13_184932_added_groups.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->bigInteger('user_id')->unsigned();
17 | $table->foreign('user_id')->references('id')->on('users');
18 | $table->string('name');
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | */
26 | public function down(): void
27 | {
28 | Schema::dropIfExists('groups');
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_13_184933_added_categories.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id')->unsigned();
16 | $table->bigInteger('user_id')->unsigned();
17 | $table->foreign('user_id')->references('id')->on('users');
18 | $table->bigInteger('group_id')->unsigned();
19 | $table->foreign('group_id')->references('id')->on('groups');
20 | $table->string('name');
21 | $table->string('color');
22 | $table->timestamps();
23 | });
24 |
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | */
30 | public function down(): void
31 | {
32 | Schema::dropIfExists('categories');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_19_213458_added_institutions.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->string('name');
17 | $table->string('url')->nullable();
18 | $table->text('logo')->nullable();
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | */
26 | public function down(): void
27 | {
28 | Schema::drop('institutions');
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_20_190002_added_cash_accounts.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->bigInteger('user_id')->unsigned();
17 | $table->foreign('user_id')->references('id')->on('users');
18 | $table->bigInteger('institution_id')->unsigned();
19 | $table->foreign('institution_id')->references('id')->on('institutions');
20 | $table->string('type');
21 | $table->string('name');
22 | $table->string('description')->nullable();
23 | $table->string('account_number')->nullable();
24 | $table->decimal('balance', 10, 3)->default(0);
25 | $table->decimal('interest_rate', 5, 3)->default(0);
26 | $table->timestamps();
27 | $table->softDeletes();
28 | });
29 | }
30 |
31 | /**
32 | * Reverse the migrations.
33 | */
34 | public function down(): void
35 | {
36 | Schema::drop('cash_accounts');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/database/migrations/2024_01_20_190547_added_credit_cards.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->bigInteger('user_id')->unsigned();
17 | $table->foreign('user_id')->references('id')->on('users');
18 | $table->bigInteger('institution_id')->unsigned();
19 | $table->foreign('institution_id')->references('id')->on('institutions');
20 | $table->string('brand')->nullable();
21 | $table->string('name');
22 | $table->string('description')->nullable();
23 | $table->decimal('interest_rate', 5, 3)->default(0);
24 | $table->decimal('credit_limit', 10, 3)->default(0);
25 | $table->decimal('balance', 10, 3)->default(0);
26 | $table->timestamps();
27 | $table->softDeletes();
28 | });
29 | }
30 |
31 | /**
32 | * Reverse the migrations.
33 | */
34 | public function down(): void
35 | {
36 | Schema::drop('credit_cards');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/database/migrations/2024_04_24_030908_added_import_map_to_credit_cards.php:
--------------------------------------------------------------------------------
1 | json('import_map')->nullable()->after('balance');
16 | });
17 | }
18 |
19 | /**
20 | * Reverse the migrations.
21 | */
22 | public function down(): void
23 | {
24 | Schema::table('credit_cards', function (Blueprint $table) {
25 | //
26 | });
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/database/migrations/2024_04_24_030948_added_import_map_to_loans.php:
--------------------------------------------------------------------------------
1 | json('import_map')->nullable()->after('payment_amount');
16 | });
17 | }
18 |
19 | /**
20 | * Reverse the migrations.
21 | */
22 | public function down(): void
23 | {
24 | Schema::table('loans', function (Blueprint $table) {
25 | //
26 | });
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/database/migrations/2024_04_24_031010_added_import_map_to_cash_accounts.php:
--------------------------------------------------------------------------------
1 | json('import_map')->nullable()->after('interest_rate');
16 | });
17 | }
18 |
19 | /**
20 | * Reverse the migrations.
21 | */
22 | public function down(): void
23 | {
24 | Schema::table('cash_accounts', function (Blueprint $table) {
25 | //
26 | });
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/database/migrations/2024_05_15_212852_added_rules.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->bigInteger('accountable_id')->unsigned();
17 | $table->string('accountable_type');
18 | $table->string('search_string');
19 | $table->string('replace_string');
20 | $table->bigInteger('category_id')->unsigned()->nullable();
21 | $table->foreign('category_id')->references('id')->on('categories');
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | */
29 | public function down(): void
30 | {
31 | Schema::dropIfExists('rules');
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/database/seeders/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | // \App\Models\User::factory()->create([
18 | // 'name' => 'Test User',
19 | // 'email' => 'test@example.com',
20 | // ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/docker-compose.ci.yml:
--------------------------------------------------------------------------------
1 | services:
2 | php:
3 | build:
4 | context: .
5 | dockerfile: Dockerfile.php
6 | target: ci
7 | networks:
8 | - ci
9 | volumes:
10 | - .:/var/www/html/
11 | working_dir: /var/www/html/
12 |
13 | node:
14 | build:
15 | context: .
16 | dockerfile: Dockerfile.node
17 | target: base
18 | networks:
19 | - ci
20 | volumes:
21 | - .:/usr/src/app/:cached
22 | working_dir: /usr/src/app/
23 |
24 | mailpit:
25 | image: axllent/mailpit
26 | networks:
27 | - ci
28 |
29 | networks:
30 | ci:
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | traefik:
4 | image: traefik:v3.0
5 |
6 | php:
7 | depends_on:
8 | - traefik
--------------------------------------------------------------------------------
/docs/.env.example:
--------------------------------------------------------------------------------
1 | NUXT_APP_BASE_URL=/open-source/financial-freedom
2 | TOP_LEVEL_DOMAIN=http://localhost:3000
3 | ALGOLIA_API_KEY=changeme
4 | ALGOLIA_APPLICATION_ID=changeme
5 | ALGOLIA_INDEX=changeme
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log*
3 | .nuxt
4 | .nitro
5 | .cache
6 | .output
7 | .env
8 | dist
9 |
--------------------------------------------------------------------------------
/docs/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/docs/.nvmrc:
--------------------------------------------------------------------------------
1 | v20
2 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Documentation & Static Site, generated with Nuxt Content
2 | This is a documentation site built on top of Nuxt Content (v3).
3 |
4 | # Docs location
5 | All docs are located in the [./content](./content/docs) folder if you're just looking for the docs in plain text.
6 |
7 | ## Setup
8 |
9 | Ensure you're in the right directory.
10 |
11 | ```bash
12 | cd docs/
13 | ```
14 |
15 | Copy over the environment variable example file.
16 |
17 | ```bash
18 | cp .env.example .env
19 | ```
20 |
21 | We use [NVM](https://github.com/nvm-sh/nvm) to manage our local Node version (Docker support coming soon after some JS libraries support it better). Ensure you have NVM installed and configured and use the following command to install the correct version of Node:
22 |
23 | ```bash
24 | nvm use
25 | ```
26 |
27 | Make sure to install the dependencies:
28 |
29 | ```bash
30 | yarn install
31 | ```
32 |
33 | ## Development Server
34 |
35 | Start the development server on http://localhost:3000
36 |
37 | ```bash
38 | yarn dev
39 | ```
40 |
41 | ## Production
42 |
43 | Build the application for production:
44 |
45 | ```bash
46 | yarn build
47 | ```
48 |
49 | Locally preview production build:
50 |
51 | ```bash
52 | yarn preview
53 | ```
54 |
55 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
--------------------------------------------------------------------------------
/docs/assets/css/docsearch.css:
--------------------------------------------------------------------------------
1 | button.DocSearch-Button{
2 | background: transparent;
3 | font-family: "Inter", sans-serif;
4 | border-radius: 4px;
5 | margin: 0px;
6 | }
7 |
8 | button.DocSearch-Button .DocSearch-Search-Icon{
9 | margin-right: 8px;
10 | width: 20px;
11 | height: 20px;
12 | stroke-width: 2;
13 | stroke-linecap: round;
14 | stroke-linejoin: round;
15 | color: #CBD5E1;
16 | }
17 |
18 | button.DocSearch-Button .DocSearch-Button-Placeholder{
19 | font-weight: bold;
20 | color: rgb(203, 213, 225);
21 | font-size: 0.875rem/* 14px */;
22 | line-height: 1.5rem/* 24px */;
23 | padding: 0px;
24 | display: none;
25 | }
26 |
27 | @media (min-width: 1024px) {
28 | button.DocSearch-Button .DocSearch-Button-Placeholder{
29 | display: block;
30 | }
31 | }
32 |
33 | @media (min-width: 1280px) {
34 | button.DocSearch-Button .DocSearch-Button-Placeholder{
35 | font-size: 1.125rem/* 18px */;
36 | line-height: 1.75rem/* 28px */;
37 | }
38 | }
39 |
40 | button.DocSearch-Button:hover,
41 | button.DocSearch-Button:active,
42 | button.DocSearch-Button:focus {
43 | background: rgb(17, 24, 39);
44 | box-shadow: none;
45 | }
46 |
47 | button.DocSearch-Button .DocSearch-Button-Keys{
48 | display: none;
49 | }
50 |
--------------------------------------------------------------------------------
/docs/assets/css/tailwind.css:
--------------------------------------------------------------------------------
1 | @import "animations.css";
2 | @import "hamburger.css";
3 | @import "docsearch.css";
4 | @import 'tailwindcss/base';
5 | @import 'tailwindcss/components';
6 | @import 'tailwindcss/utilities';
7 | ::-webkit-scrollbar {
8 | width: 0px;
9 | height: 0px;
10 | }
--------------------------------------------------------------------------------
/docs/components/Docs/Anchor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/components/Docs/Eyebrow.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ tag }}
4 |
5 | {{ label }}
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/components/Docs/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/components/Docs/ModeToggle.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/components/Docs/PageLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 | {{ label }}
7 |
8 |
13 | {{ page.title }}
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/components/Docs/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/components/Docs/SmallPrint.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | © Copyright {{ copyright }}. All rights reserved.
5 |
6 |
7 |
8 | Twitter
9 |
10 |
11 |
12 | GitHub
13 |
14 |
15 |
16 | Discord
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/components/Docs/TopLevelNavItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
--------------------------------------------------------------------------------
/docs/components/DocumentDrivenNotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/docs/components/Icons/Anchor.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/docs/components/Icons/Arrow.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/components/Icons/ChatBubbleIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/components/Icons/Check.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/docs/components/Icons/CheckIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/components/Icons/ClipboardIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/docs/components/Icons/EnvelopeIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/docs/components/Icons/Moon.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/components/Icons/Resource.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/docs/components/Icons/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/docs/components/Icons/Social/Discord.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/components/Icons/Social/GitHub.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/docs/components/Icons/Social/Twitter.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/components/Icons/Sun.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/docs/components/Icons/UserIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
--------------------------------------------------------------------------------
/docs/components/Icons/UsersIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/docs/components/content/AppHeading2.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/components/content/AppHeading3.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/components/content/AppHeading4.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/components/content/Code/ClipboardIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/docs/components/content/Code/PanelHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ tag }}
5 |
6 |
7 |
8 |
9 |
{{ label }}
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/components/content/CodePanel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ label }}
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/components/content/Column.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/components/content/GridPattern.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
35 |
36 |
40 |
--------------------------------------------------------------------------------
/docs/components/content/Guide.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ name }}
5 |
6 |
7 | {{ description }}
8 |
9 |
10 |
11 | Read More
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/components/content/Guides.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Guides
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/components/content/HeroPattern.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
31 |
--------------------------------------------------------------------------------
/docs/components/content/InfoIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/components/content/LandingScreenshot.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/components/content/LeadP.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/docs/components/content/NotProse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/docs/components/content/Note.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/docs/components/content/Properties.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/docs/components/content/Property.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - Name
5 | -
6 |
7 |
8 | - Type
9 |
10 | - Description
11 | -
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/components/content/Resources/ResourceIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/components/content/Row.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/docs/composables/states.ts:
--------------------------------------------------------------------------------
1 | export const usePreferredProgrammingLanguage = () => useState('programming-language', () => '')
--------------------------------------------------------------------------------
/docs/composables/useBreakpoints.ts:
--------------------------------------------------------------------------------
1 | const screens = {
2 | xs: 320,
3 | sm: 640,
4 | md: 768,
5 | lg: 1024,
6 | xl: 1280
7 | }
8 |
9 | const breakpoints = reactive({ w: 0, h: 0, is: 'xs' })
10 |
11 | const xs = (val: number) => val >= screens.xs && val < screens.sm
12 | const sm = (val: number) => val >= screens.sm && val < screens.md
13 | const md = (val: number) => val >= screens.md && val < screens.lg
14 | const lg = (val: number) => val >= screens.lg && val < screens.xl
15 | const xl = (val: number) => val >= screens.xl
16 |
17 | const getBreakpoint = (w: number) => {
18 | if (xs(w)) return 'xs'
19 | else if (sm(w)) return 'sm'
20 | else if (md(w)) return 'md'
21 | else if (lg(w)) return 'lg'
22 | else if (xl(w)) return 'xl'
23 | else return 'all'
24 | }
25 |
26 | const setBreakpoint = () => {
27 | breakpoints.w = window.innerWidth
28 | breakpoints.h = window.innerHeight
29 | breakpoints.is = getBreakpoint(window.innerWidth)
30 | }
31 |
32 | const useBreakpoint = () => {
33 | onMounted(() => {
34 | setBreakpoint()
35 | window.addEventListener('resize', () => {
36 | setBreakpoint()
37 | })
38 | })
39 |
40 | return {
41 | breakpoints
42 | }
43 | }
44 |
45 | export default useBreakpoint
--------------------------------------------------------------------------------
/docs/content/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: marketing
3 | ---
4 | ::landing-hero
5 | ::
6 |
7 | ::landing-screenshot
8 | ::
9 |
10 | ::landing-decentralized
11 | ::
12 |
13 | ::landing-stack
14 | ::
15 |
16 | ::landing-signup
17 | ::
18 |
19 | ::marketing-footer
20 | ::
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "build": "nuxt build",
5 | "dev": "nuxt dev",
6 | "generate": "nuxt generate",
7 | "preview": "nuxt preview",
8 | "postinstall": "nuxt prepare"
9 | },
10 | "devDependencies": {
11 | "@headlessui/vue": "^1.7.8",
12 | "@nuxt/content": "^2.9.0",
13 | "@nuxtjs/color-mode": "^3.3.0",
14 | "@nuxtjs/plausible": "^0.2.3",
15 | "@nuxtjs/tailwindcss": "^6.9.4",
16 | "@tailwindcss/typography": "^0.5.9",
17 | "@vueuse/core": "^10.6.1",
18 | "@vueuse/nuxt": "^10.6.1",
19 | "nuxt": "^3.8.1",
20 | "sitemap": "^7.1.1",
21 | "surge": "^0.23.1"
22 | },
23 | "dependencies": {
24 | "@docsearch/css": "^3.3.3",
25 | "@docsearch/js": "^3.3.3",
26 | "@nuxtjs/algolia": "^1.10.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docs/public/images/docs/install-synology/container-manager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/docs/install-synology/container-manager.png
--------------------------------------------------------------------------------
/docs/public/images/docs/install-synology/create-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/docs/install-synology/create-folder.png
--------------------------------------------------------------------------------
/docs/public/images/docs/install-synology/create-project-completed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/docs/install-synology/create-project-completed.png
--------------------------------------------------------------------------------
/docs/public/images/docs/install-synology/create-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/docs/install-synology/create-project.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/public/images/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/favicon.ico
--------------------------------------------------------------------------------
/docs/public/images/favicon/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/favicon/mstile-150x150.png
--------------------------------------------------------------------------------
/docs/public/images/favicon/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.14, written by Peter Selinger 2001-2017
9 |
10 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/public/images/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/docs/public/images/icons/heart.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/public/images/icons/search-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/public/images/logos/docker.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/public/images/logos/github-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/public/images/logos/tailwindcss.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/public/images/logos/x-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/public/images/social-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/social-image.png
--------------------------------------------------------------------------------
/docs/public/images/ui/app-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/app-screenshot.png
--------------------------------------------------------------------------------
/docs/public/images/ui/credit-cards.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/credit-cards.png
--------------------------------------------------------------------------------
/docs/public/images/ui/dan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/dan.png
--------------------------------------------------------------------------------
/docs/public/images/ui/full-screen-mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/full-screen-mockup.png
--------------------------------------------------------------------------------
/docs/public/images/ui/jay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/jay.png
--------------------------------------------------------------------------------
/docs/public/images/ui/light-accent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/docs/public/images/ui/light-accent.png
--------------------------------------------------------------------------------
/docs/server/routes/sitemap.xml.ts:
--------------------------------------------------------------------------------
1 | import { serverQueryContent } from '#content/server'
2 | import { SitemapStream, streamToPromise } from 'sitemap'
3 | export default defineEventHandler(async (event) => {
4 | // Fetch all documents
5 | const docs = await serverQueryContent(event).find()
6 | const sitemap = new SitemapStream({
7 | hostname: 'https://financialfreedom.app'
8 | })
9 |
10 | for (const doc of docs) {
11 | sitemap.write({
12 | url: doc._path,
13 | changefreq: 'monthly'
14 | })
15 | }
16 |
17 |
18 | sitemap.end()
19 | return streamToPromise(sitemap)
20 | })
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // https://nuxt.com/docs/guide/concepts/typescript
3 | "extends": "./.nuxt/tsconfig.json"
4 | }
5 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["resources/js/*"],
6 | "ziggy-js": ["./vendor/tightenco/ziggy"]
7 | }
8 | },
9 | "exclude": ["node_modules", "public"]
10 | }
11 |
--------------------------------------------------------------------------------
/modules_statuses.json:
--------------------------------------------------------------------------------
1 | {
2 | "Initialize": true,
3 | "Transaction": true
4 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "type": "module",
4 | "scripts": {
5 | "dev": "vite --host",
6 | "build": "vite build"
7 | },
8 | "devDependencies": {
9 | "@inertiajs/vue3": "^1.0.0",
10 | "@tailwindcss/forms": "^0.5.3",
11 | "@vitejs/plugin-basic-ssl": "^1.0.1",
12 | "@vitejs/plugin-vue": "^5.0.0",
13 | "autoprefixer": "^10.4.12",
14 | "axios": "^1.6.4",
15 | "laravel-vite-plugin": "^1.0.0",
16 | "postcss": "^8.4.31",
17 | "tailwindcss": "^3.2.1",
18 | "vite": "^5.0.0",
19 | "vue": "^3.4.0"
20 | },
21 | "dependencies": {
22 | "@headlessui/vue": "^1.7.17",
23 | "@heroicons/vue": "^2.1.1",
24 | "@vueuse/core": "^10.7.1",
25 | "chart.js": "^4.4.1",
26 | "moment": "^2.30.1",
27 | "momentum-modal": "^0.2.2",
28 | "papaparse": "^5.4.1",
29 | "vue-chartjs": "^5.3.0",
30 | "zxcvbn": "^4.4.2"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | tests/Unit
10 |
11 |
12 | tests/Feature
13 |
14 |
15 |
16 |
17 | app
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Send Requests To Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/ui/institution-placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serversideup/financial-freedom/1c21c06ae0cd2ca597e6b272721db84de4775b34/public/img/ui/institution-placeholder.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/resources/css/app.css:
--------------------------------------------------------------------------------
1 | @import "animations.css";
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Checkbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/resources/js/Components/DangerButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/resources/js/Components/Dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/resources/js/Components/DropdownLink.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/BudgetPlanIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/CashFlowIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/CoinsIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/DashboardIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/FolderIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/FolderModalIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/GoalsIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/LeftArrowIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/ModalCloseIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/RightArrowIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/SuccessNotificationIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/SwitchIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/TransactionsIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/TrashModalIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/js/Components/Icons/UploadIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/js/Components/InputError.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 | {{ message }}
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/resources/js/Components/InputLabel.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/resources/js/Components/NavLink.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/resources/js/Components/PrefixTextInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/resources/js/Components/PrimaryButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/resources/js/Components/ResponsiveNavLink.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/resources/js/Components/SecondaryButton.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/js/Components/SuffixTextInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/resources/js/Components/TextInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/resources/js/Composables/useCategoryColor.js:
--------------------------------------------------------------------------------
1 | const colors = {
2 | 'green': '#16B364',
3 | 'purple': '#7A5AF8',
4 | 'orange': '#EF6820',
5 | 'gray': '#737373',
6 | 'blue': '#2E90FA',
7 | 'pink': '#EE46BC',
8 | 'red': '#F63D68',
9 | };
10 |
11 | export const useCategoryColor = () => {
12 | const getCategoryColor = (categoryColor) => {
13 | return colors[categoryColor];
14 | }
15 |
16 | return {
17 | getCategoryColor,
18 | }
19 | }
--------------------------------------------------------------------------------
/resources/js/Composables/useDisplay.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue';
2 |
3 | const minimizeSidebar = ref(false);
4 |
5 | export const useDisplay = () => {
6 |
7 | return {
8 | minimizeSidebar
9 | }
10 | }
--------------------------------------------------------------------------------
/resources/js/Composables/useFormatters.js:
--------------------------------------------------------------------------------
1 | export const useFormatters = () => {
2 | const currency = new Intl.NumberFormat('en-US', {
3 | style: 'currency',
4 | currency: 'USD',
5 |
6 | // These options are needed to round to whole numbers if that's what you want.
7 | //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
8 | //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
9 | });
10 |
11 | const percentage = new Intl.NumberFormat('en-US', {
12 | style: 'percent',
13 | minimumFractionDigits: 1,
14 | maximumFractionDigits: 3
15 | });
16 |
17 | return {
18 | currency,
19 | percentage
20 | }
21 | }
--------------------------------------------------------------------------------
/resources/js/Layouts/GuestLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
--------------------------------------------------------------------------------
/resources/js/Pages/Accounts/Partials/AccountSummary.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Summary
5 |
6 |
7 |
8 |
9 | Assets
10 | {{ currency.format( assets ) }}
11 |
12 |
13 | Liabilities
14 | {{ currency.format( liabilities ) }}
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/resources/js/Pages/Accounts/Partials/NetWorth.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Net Worth
4 | {{ currency.format( netWorth ) }}
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/resources/js/Pages/Cash/Show.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/resources/js/Pages/Dashboard/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/resources/js/Pages/Loans/Show.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/resources/js/Pages/Settings/Partials/Navigation.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/js/app.js:
--------------------------------------------------------------------------------
1 | import './bootstrap';
2 | import '../css/app.css';
3 |
4 | import { createApp, h } from 'vue';
5 | import { createInertiaApp } from '@inertiajs/vue3';
6 | import { modal } from "momentum-modal"
7 | import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
8 | import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
9 |
10 | const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
11 |
12 | createInertiaApp({
13 | title: (title) => `${title} - ${appName}`,
14 | resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
15 | setup({ el, App, props, plugin }) {
16 | return createApp({ render: () => h(App, props) })
17 | .use(modal, {
18 | resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue")),
19 | })
20 | .use(plugin)
21 | .use(ZiggyVue)
22 | .mount(el);
23 | },
24 | progress: {
25 | color: '#4B5563',
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/resources/js/bootstrap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * We'll load the axios HTTP library which allows us to easily issue requests
3 | * to our Laravel back-end. This library automatically handles sending the
4 | * CSRF token as a header based on the value of the "XSRF" token cookie.
5 | */
6 |
7 | import axios from 'axios';
8 | window.axios = axios;
9 |
10 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
11 |
12 | /**
13 | * Echo exposes an expressive API for subscribing to channels and listening
14 | * for events that are broadcast by Laravel. Echo and event broadcasting
15 | * allows your team to easily build robust real-time web applications.
16 | */
17 |
18 | // import Echo from 'laravel-echo';
19 |
20 | // import Pusher from 'pusher-js';
21 | // window.Pusher = Pusher;
22 |
23 | // window.Echo = new Echo({
24 | // broadcaster: 'pusher',
25 | // key: import.meta.env.VITE_PUSHER_APP_KEY,
26 | // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
27 | // wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
28 | // wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
29 | // wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
30 | // forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
31 | // enabledTransports: ['ws', 'wss'],
32 | // });
33 |
--------------------------------------------------------------------------------
/resources/views/app.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ config('app.name', 'Laravel') }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | @routes
16 | @vite(['resources/js/app.js', "resources/js/Pages/{$page['component']}.vue"])
17 | @inertiaHead
18 |
19 |
20 | @inertia
21 |
22 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | get('/user', function (Request $request) {
18 | return $request->user();
19 | });
20 |
--------------------------------------------------------------------------------
/routes/channels.php:
--------------------------------------------------------------------------------
1 | id === (int) $id;
18 | });
19 |
--------------------------------------------------------------------------------
/routes/console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
19 | })->purpose('Display an inspiring quote');
20 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | compiled.php
2 | config.php
3 | down
4 | events.scanned.php
5 | maintenance.php
6 | routes.php
7 | routes.scanned.php
8 | schedule-*
9 | services.json
10 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !data/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/cache/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | import defaultTheme from 'tailwindcss/defaultTheme';
2 | import forms from '@tailwindcss/forms';
3 |
4 | /** @type {import('tailwindcss').Config} */
5 | export default {
6 | content: [
7 | './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
8 | './storage/framework/views/*.php',
9 | './resources/views/**/*.blade.php',
10 | './resources/js/**/*.vue',
11 | ],
12 |
13 | theme: {
14 | extend: {
15 | fontFamily: {
16 | sans: ['Inter', ...defaultTheme.fontFamily.sans],
17 | },
18 | },
19 | },
20 |
21 | plugins: [forms],
22 | };
23 |
--------------------------------------------------------------------------------
/tests/CreatesApplication.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
18 |
19 | return $app;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/Feature/Auth/PasswordConfirmationTest.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | $response = $this->actingAs($user)->get('/confirm-password');
18 |
19 | $response->assertStatus(200);
20 | }
21 |
22 | public function test_password_can_be_confirmed(): void
23 | {
24 | $user = User::factory()->create();
25 |
26 | $response = $this->actingAs($user)->post('/confirm-password', [
27 | 'password' => 'password',
28 | ]);
29 |
30 | $response->assertRedirect();
31 | $response->assertSessionHasNoErrors();
32 | }
33 |
34 | public function test_password_is_not_confirmed_with_invalid_password(): void
35 | {
36 | $user = User::factory()->create();
37 |
38 | $response = $this->actingAs($user)->post('/confirm-password', [
39 | 'password' => 'wrong-password',
40 | ]);
41 |
42 | $response->assertSessionHasErrors();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Feature/Auth/RegistrationTest.php:
--------------------------------------------------------------------------------
1 | get('/register');
16 |
17 | $response->assertStatus(200);
18 | }
19 |
20 | public function test_new_users_can_register(): void
21 | {
22 | $response = $this->post('/register', [
23 | 'name' => 'Test User',
24 | 'email' => 'test@example.com',
25 | 'password' => 'password',
26 | 'password_confirmation' => 'password',
27 | ]);
28 |
29 | $this->assertAuthenticated();
30 | $response->assertRedirect(RouteServiceProvider::HOME);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Feature/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
16 |
17 | $response->assertStatus(200);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig, loadEnv } from 'vite';
2 | import laravel from 'laravel-vite-plugin';
3 | import vue from '@vitejs/plugin-vue';
4 | import basicSsl from '@vitejs/plugin-basic-ssl'
5 |
6 | const env = loadEnv('', process.cwd());
7 |
8 | const host = env.VITE_HOST;
9 |
10 | export default defineConfig({
11 | plugins: [
12 | basicSsl(),
13 | laravel({
14 | input: 'resources/js/app.js',
15 | refresh: true,
16 | }),
17 | vue({
18 | template: {
19 | transformAssetUrls: {
20 | base: null,
21 | includeAbsolute: false,
22 | },
23 | },
24 | }),
25 | ],
26 | server: {
27 | host,
28 | hmr: {
29 | host,
30 | clientPort: 443
31 | },
32 | },
33 | });
--------------------------------------------------------------------------------