First off, thanks for taking the time to contribute!
I'm Leonardo the founder of Foliofox. All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. The community looks forward to your contributions.
And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation:
- Star the project
- Share it on Reddit/X
- Refer this project in your project's readme
- Mention it to friends/colleagues or at your local meetup
If you need help, feel free to reach out to @unav4ila8le.
- Local Development
- Types
- Linting & Formatting
- Commit Message Convention
- Pull Request Guidelines
- Reporting Bugs
- Suggesting Enhancements
- Legal Notice
You can build and run Foliofox locally using either Docker or a local Node.js setup.
- Your own Supabase project (Project URL, anon/publishable key, service_role/secret key, database password)
- Supabase CLI 2.5+ (
supabase --version; you can also run it vianpx supabaseif you prefer not to install globally)
For Docker setup:
- Docker Desktop
For traditional Node.js setup:
- Node.js 22+
- npm 11+
Optional:
- Vercel account (for one-click deploy and scheduled cron jobs)
git clone https://github.com/unav4ila8le/foliofox.git
cd foliofoxCreate a .env.local file in the project root:
# Required
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your_supabase_publishable_key
SUPABASE_SECRET_KEY=your_supabase_secret_key
# Optional (used to authorize cron invocations)
CRON_SECRET=generate_a_strong_random_string
# Optional (used for AI features)
AI_PROVIDER=openai
AI_PROVIDER_API_KEY=your_provider_api_key
AI_CHAT_MODEL_ID=gpt-5-mini
AI_EXTRACTION_MODEL_ID=gpt-5-mini
# Optional (used for domain valuations)
REPLICATE_API_TOKEN=your_replicate_api_token
# Optional (used for PostHog)
NEXT_PUBLIC_POSTHOG_KEY=<ph_project_api_key>
NEXT_PUBLIC_POSTHOG_HOST=https://<us | eu>.i.posthog.comsupabase login # once per machine
supabase link --project-ref <your-project-ref>
supabase db push --linked # applies tracked migrations (baseline + new ones)- You can safely re-run
supabase db push --linkedwhenever you need to resync with the repo; it only applies migrations that have not yet been recorded in your project. - The tracked migrations also include the reference data required for signup and basic usage.
- If prompted, use the Database Password from Supabase (Settings → Database).
docker compose up --buildVisit http://localhost:3000
- Run in detached mode:
docker compose up -d - Rebuild after changes:
docker compose up --build - Stop:
docker compose down
For faster development, we suggest using the traditional local setup:
git clone https://github.com/unav4ila8le/foliofox.git
cd foliofox
npm installCreate a .env.local file in the project root, same as Docker setup above.
Same as Docker apply database migrations.
npm run devVisit http://localhost:3000
supabase start # boots the Supabase stack in Docker
supabase migration up --local # applies the tracked migrations to the local DB- Update your
.env.localwith the new local credentials by runningsupabase status -o envand mapping the output to the environment variables:API_URL→NEXT_PUBLIC_SUPABASE_URLPUBLISHABLE_KEY→NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSECRET_KEY→SUPABASE_SECRET_KEY
- The CLI prints the local connection string (
postgresql://postgres:postgres@localhost:54322/postgresby default). - Reset the local database with
supabase db reset --local(it will replay all migrations and seed data). - You can regenerate types with
supabase gen types typescript --local > types/database.types.ts. - You can also run
supabase db push --localif you prefer the same command as remote projects. - Stop the stack with
supabase stopwhen you are done.
Test User for Local Development:
When running locally, a test user is automatically seeded on db reset or db push --local:
- Email:
test@example.com - Password:
Password123
-
Generate a migration shell:
supabase migration new add_feature_name
-
Edit the generated SQL file in
supabase/migrations/. -
Test locally:
supabase migration up --local
-
Apply remotely:
supabase db push --linked
-
Commit the migration file along with any related code changes.
- If you update reference tables (currencies, position categories), edit the
*_seed_reference_data.sqlmigration or add a new seed migration so contributors stay in sync.
If you use your own Supabase project, regenerate types/database.types.ts:
supabase login
supabase link --project-ref <your-project-ref>
# Option A: use the provided script
npm run types:supabase:local
# Option B: ad-hoc generation
supabase gen types typescript --project-id <your-project-ref> > types/database.types.ts- Import the repo into Vercel.
- Set the same environment variables (Project Settings → Environment Variables).
vercel.jsonincludes daily cron jobs at 22:00 UTC for quotes and FX updates.- Cron endpoints expect
Authorization: Bearer <CRON_SECRET>.
If headers can’t be configured in your environment, trigger manually:
# Exchange rates
curl "http://localhost:3000/api/cron/fetch-exchange-rates" \
-H "authorization: Bearer $CRON_SECRET"
# Quotes
curl "http://localhost:3000/api/cron/fetch-quotes" \
-H "authorization: Bearer $CRON_SECRET"N/A
We use strict TypeScript for type safety. Some rules to follow:
- Never use
anytype. Implicit or explicit. - Prefer
unknownoverany. Refine the type. - Always type your function parameters and return values explicitly; do not rely on implicit any or inference.
- Do not use
astype assertions. The only exception isas const.
Our linter will catch most styling issues that may exist in your code.
- Check lint status:
npm run lint - Check formatting:
npm run format
Use Conventional Commits: type(scope): summary
- Allowed types:
feat,fix,docs,refactor,test,chore,build,ci,perf - Scope: folder or domain, e.g.
server/positions,app/dashboard,ai
Examples:
feat(positions): add cost basis override to new position form
fix(exchange-rates): handle missing base currency fallback
docs(contributing): document commit conventions and pr checklist
- Keep PRs small and focused; one change per PR.
- Target the
mainbranch for all PRs. - Title should follow Conventional Commits if possible.
- Link related issues, if any: Closes #123.
- Describe what/why; include screenshots for UI changes.
- Tests if applicable; no lint/type errors; run locally.
- Follow project rules (RSC-first, TypeScript strict, server actions in server/, import order, naming).
- Avoid breaking changes; if unavoidable, document migration in the PR.
- For features, note performance, accessibility, and data model impacts.
First search existing issues. If nothing matches, open a new issue.
- Ensure you’re on the latest version of
main. - Provide clear expected vs actual behavior.
- Include steps to reproduce (ideally a minimal example and screenshots/screen recodings if they apply). If there are no reproduction steps or no obvious way to reproduce the issue, I will ask you for those steps and mark the issue as
needs repro. Bugs with theneeds-reprotag will not be addressed until they are reproduced. - Add environment details (OS, Node, package manager).
- Security issues: report a vulnerability (do not post security issues publicly).
- Search existing issues.
- Explain current vs desired behavior and why it helps most users.
- Include alternatives considered and, if helpful, screenshots or references.
By contributing to Foliofox, you agree that your contributions will be licensed under its MIT license.