[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-95892":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":9,"totalLinesOfCode":9,"stars":12,"forks":13,"watchers":14,"openIssues":14,"contributorsCount":9,"subscribersCount":14,"size":14,"stars1d":14,"stars7d":14,"stars30d":14,"stars90d":14,"forks30d":14,"starsTrendScore":14,"compositeScore":15,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":16,"hasPages":16,"topics":9,"createdAt":9,"pushedAt":9,"updatedAt":18,"readmeContent":19,"aiSummary":20,"trendingCount":14,"starSnapshotCount":14,"syncStatus":21,"lastSyncTime":9,"discoverSource":22},95892,"picsou-finance","Zoeille\u002Fpicsou-finance","Zoeille","Self-hosted personal finance dashboard Track bank accounts, brokerage, crypto, and net worth — all in one place.",null,"https:\u002F\u002Fgithub.com\u002FZoeille\u002Fpicsou-finance","Java",503,48,0,9.07,false,"main","2026-09-21 02:04:28","\u003Cdiv align=\"center\">\n\n# Picsou\n\n**Self-hosted personal finance dashboard**\n\nTrack bank accounts, brokerage, crypto, and net worth — all in one place.\n\n[![License: Apache 2.0 + Commons Clause](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-Apache%202.0%20%2B%20Commons%20Clause-blue.svg)](LICENSE)\n\n[Getting started](#getting-started) · [Features](#features) · [Development](#development) · [Security](SECURITY.md)\n\n\u003C\u002Fdiv>\n\n---\n\n## Disclaimer\n\n> **Picsou is designed for personal, local use.**\n>\n> It stores sensitive financial data (balances, transactions, bank session tokens). It supports multi-member families, optional TOTP 2FA, and audit logging of setup\u002Fadmin actions, but it has **not** undergone a professional security audit.\n>\n> **Do not expose it on the public internet.** Use it on your local machine or home network behind a firewall. If you choose to expose it, you do so at your own risk.\n\n---\n\n## Features\n\n- **Account aggregation** — Bank accounts (LEP, PEA, Livret, current), brokerage, crypto wallets, on-chain addresses, debts\u002Floans\n- **Bank sync** — Enable Banking (PSD2\u002FOAuth, 2000+ EU banks).\n- **BoursoBank** — Current accounts, livrets and the PEA\u002FCTO with its cash and positions, via a local read-only sidecar. Reaches the securities account PSD2 cannot.\n- **Brokerage sync** — Trade Republic via WebSocket or CSV import, and Bourse Direct PEA\u002FCTO positions via a local read-only sidecar\n- **Employee savings** — Amundi Épargne Salariale plans (PEE\u002FPEG, PERCO, PER) and their FCPE lines, via a local read-only sidecar\n- **Crypto** — Binance and Meria exchange sync, on-chain BTC\u002FETH\u002FSOL address tracking\n- **Live prices** — CoinGecko (crypto), Yahoo Finance (stocks\u002FETFs)\n- **Real estate** — Automatic monthly valuation of French property from open data (DGFiP transactions via Cerema, IGN geocoding, INSEE price index). No API key, no subscription. Ownership shares between family members, mortgages linked to the property they finance, and gross\u002Fnet property equity.\n- **Security insight** — Per-holding asset-type detection and ETF composition (top holdings, country & sector breakdowns) in the holding detail modal\n- **Net worth tracking** — Historical snapshots, stacked area charts, per-account breakdown\n- **Savings goals** — Targets with deadlines, progress tracking across accounts\n- **Multi-member family** — One admin manages multiple profiles (children, spouse). Per-resource sharing (`NONE` \u002F `ALL` \u002F `MANUAL`), optional activation links to upgrade a managed profile to a full login.\n- **2FA + Remember Me** — Opt-in TOTP per user, 10 single-use recovery codes, 90-day \"Remember Me\" cookie with rotating tokens, \"Trust this device\" to skip TOTP, per-session revocation from settings.\n- **GDPR data export** — Self-service ZIP export (JSON + per-entity CSV) gated by re-authentication, rate-limited to 5\u002Fhour.\n- **Finary import** — CSV import or direct API sync\n- **i18n** — English and French\n- **Dark mode** — System\u002Flight\u002Fdark with flash-free theme switching\n\n## Architecture\n\n```\n┌──────────────────┐     ┌───────────────────────┐     ┌────────────┐\n│  React Frontend  │────▶│  Spring Boot Backend   │────▶│ PostgreSQL │\n│   (Vite\u002FBun)     │◀────│     (Tomcat :8080)     │     │  (:5432)   │\n└──────────────────┘     └───────────┬────────────┘     └────────────┘\n                                     │\n                      ┌──────────────┼──────────────┬──────────────┐\n                      ▼              ▼               ▼              ▼\n               Enable Banking   CoinGecko      Yahoo Finance   Trade Republic\n               (PSD2\u002FOAuth)     (crypto)       (stocks\u002FETF)    (WebSocket)\n```\n\n- **Ports & Adapters** — `BankConnectorPort`, `PriceProviderPort`, `TradeRepublicPort`, `BoursoPort`, etc. Swap providers without touching business logic.\n- **Two-tier identity** — `AppUser` (auth) → `FamilyMember` (domain). Every entity is scoped by `member_id`; admins can act on behalf of a managed profile via `?memberId=X`.\n- **Flyway** — Versioned database migrations\n- **JWT auth** — HttpOnly cookies, SameSite=Lax (Safari iOS compatibility), refresh token rotation\n- **2FA (TOTP)** — Opt-in, with hashed recovery codes and trusted-device cookies\n- **AES-256-GCM** — Mandatory encryption for API secrets at rest (Binance, TOTP secrets, bank session tokens)\n- **Rate limiting** — Bucket4j on login, MFA challenge, sync endpoints, and data export\n\n## Tech stack\n\n| Layer | Technology |\n|-------|-----------|\n| Backend | Java 21, Spring Boot 3.4, Maven |\n| Frontend | React 19, TypeScript 5.9, Vite 7, Tailwind v4, Bun |\n| Database | PostgreSQL 16, Flyway |\n| Runtime | Docker (Nginx + Spring Boot + supervisor) |\n\n## Getting started\n\n### Prerequisites\n\n- [Docker](https:\u002F\u002Fdocs.docker.com\u002Fget-docker\u002F) & Docker Compose v2\n- (Optional) An [Enable Banking](https:\u002F\u002Fenablebanking.com\u002F) account for bank sync\n\n### 1. Clone\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002FZoeille\u002Fpicsou-finance.git\ncd picsou-finance\n```\n\n### 2. Run (zero-config)\n\nPicsou publishes pre-built, multi-arch (amd64\u002Farm64) images to the GitHub Container Registry, so there is nothing to compile:\n\n| Image | Package |\n|-------|---------|\n| `ghcr.io\u002Fzoeille\u002Fpicsou-finance` | [picsou-finance](https:\u002F\u002Fgithub.com\u002Fusers\u002FZoeille\u002Fpackages\u002Fcontainer\u002Fpackage\u002Fpicsou-finance) — app (frontend + backend) |\n| `ghcr.io\u002Fzoeille\u002Fpicsou-finance\u002Ftr-auth` | [picsou-finance\u002Ftr-auth](https:\u002F\u002Fgithub.com\u002Fusers\u002FZoeille\u002Fpackages\u002Fcontainer\u002Fpackage\u002Fpicsou-finance%2Ftr-auth) — Trade Republic auth sidecar |\n| `ghcr.io\u002Fzoeille\u002Fpicsou-finance\u002Fbourse-direct-auth` | Bourse Direct login\u002F2FA sidecar |\n| `ghcr.io\u002Fzoeille\u002Fpicsou-finance\u002Famundi-auth` | Amundi Épargne Salariale login\u002F2FA sidecar |\n| `ghcr.io\u002Fzoeille\u002Fpicsou-finance\u002Fbourso-auth` | BoursoBank login\u002F2FA sidecar |\n\n```bash\ndocker compose -f docker\u002Fdocker-compose.yml pull    # fetch the published images from GHCR\ndocker compose -f docker\u002Fdocker-compose.yml up -d\n```\n\n> The compose file pins `:latest`. To follow the bleeding edge instead, override with `:nightly` (built on every `main` push), or pin a release such as `:1.0.0`.\n>\n> Building from source instead of pulling? Run `docker compose -f docker\u002Fdocker-compose.yml up --build` — the `build:` sections are kept for contributors.\n\nOn first launch the entrypoint auto-generates `JWT_SECRET`, `CRYPTO_ENCRYPTION_KEY`, and `POSTGRES_PASSWORD` (persisted to the `picsou_data` volume under `\u002Fdata\u002F.secrets\u002F`).\n\n> [!IMPORTANT]\n> **Planning to sync bank accounts? Set up HTTPS now, before opening the wizard — jump to\n> [step 3](#3-https-decide-before-the-first-launch).**\n> Enable Banking refuses plain-HTTP callback URLs, and the wizard permanently stores values derived\n> from the address you open it on. Run it over HTTP and you will have to correct three settings by\n> hand afterwards; run it over HTTPS and they are all derived correctly with nothing to type.\n\nOtherwise, open http:\u002F\u002Flocalhost:8080 — the **setup wizard** walks you through admin credentials, CORS, and (optionally) Enable Banking.\n\n### 3. HTTPS (decide before the first launch)\n\n**Required for bank sync.** Enable Banking rejects plain-HTTP callback URLs for PRODUCTION\napplications, and PRODUCTION is the only mode that lists real banks — so an HTTP-only install can\nnever complete a bank connection. Everything else in Picsou works fine over HTTP.\n\nThe stack ships an optional [Caddy](https:\u002F\u002Fcaddyserver.com\u002F) TLS terminator, **off by default** so\nit cannot collide with an ingress proxy you already run.\n\n#### 3a. Choose a hostname\n\nCaddy picks the certificate strategy from `PICSOU_DOMAIN` alone — there is no issuer to configure:\n\n| `PICSOU_DOMAIN` | Certificate | What you must do |\n|---|---|---|\n| A real domain (`picsou.example.com`) resolving to this host, `:80`+`:443` reachable | Let's Encrypt, publicly trusted | **Nothing.** Issued and renewed automatically |\n| A LAN IP (`192.168.1.50`) or a `.local` \u002F `.internal` name | Caddy's built-in CA | Install its root once per device (3c) |\n| `picsou.localhost` (the default) | Caddy's built-in CA | Resolves **only on the Docker host** — fine for a smoke test, useless from a phone |\n\nA real domain is worth the effort: it is the only option with no per-device step. It does not need\nto be publicly reachable for day-to-day use — only during certificate issuance.\n\n#### 3b. Start the stack with TLS\n\nThis replaces the `up -d` from step 2 — it starts the same services plus the proxy, so on a fresh\ninstall run this instead:\n\n```bash\n# Start from the commented reference file if you don't have a .env yet\n[ -f docker\u002F.env ] || cp docker\u002F.env.example docker\u002F.env\n\n# printf's leading \\n guards against a .env that lacks a trailing newline —\n# plain `echo >>` would concatenate onto the last line and corrupt both values.\nprintf '\\nPICSOU_DOMAIN=picsou.example.com\\n' >> docker\u002F.env\n\ndocker compose -f docker\u002Fdocker-compose.yml --profile tls pull\ndocker compose -f docker\u002Fdocker-compose.yml --profile tls up -d\n```\n\n> [!IMPORTANT]\n> **The `pull` is not optional on an existing install.** Compose will not re-fetch `:latest` if the\n> image already exists locally, so you would keep an older build that sends HSTS unconditionally —\n> which, combined with the internal-CA certificate from 3c, is precisely the lockout this setup\n> exists to avoid. Building from source? Use `up -d --build` instead.\n\nNote that plain HTTP stays published on `:8080` at this point. That is deliberate — it is your way\nback in if the certificate is not trusted yet. Close it in 3d, once HTTPS is confirmed working.\n\nVerify before going further:\n\n```bash\ncurl -sk -o \u002Fdev\u002Fnull -w 'https=%{http_code}\\n' https:\u002F\u002Fpicsou.example.com\u002F\ncurl -s  -o \u002Fdev\u002Fnull -w 'http=%{http_code} -> %{redirect_url}\\n' http:\u002F\u002Fpicsou.example.com\u002F\n```\n\nExpect `https=200` and an `http=308` redirect. **Now** open `https:\u002F\u002Fpicsou.example.com` and run the\nsetup wizard. It reads your browser's origin, so the callback URL, allowed origins, and secure-cookie\nflag all land on the HTTPS values with nothing to type.\n\nFinally, register `https:\u002F\u002Fpicsou.example.com\u002Fsync\u002Fcallback` in the Enable Banking portal — it must\nmatch byte-for-byte, or auth initiation fails with `REDIRECT_URI_NOT_ALLOWED`.\n\n#### 3c. No domain? Trust the internal CA\n\nCertificate trust cannot be established remotely — each device must be told once that your CA is\nlegitimate. Export the root:\n\n```bash\ndocker compose -f docker\u002Fdocker-compose.yml cp \\\n  proxy:\u002Fdata\u002Fcaddy\u002Fpki\u002Fauthorities\u002Flocal\u002Froot.crt .\u002Fpicsou-root-ca.crt\n```\n\nInstall it per device: Keychain Access (macOS), Settings → Security → Encryption & credentials\n(Android), `update-ca-certificates` (Linux), certmgr.msc (Windows). Firefox keeps its own store —\nSettings → Privacy & Security → Certificates.\n\nOnly *your* devices need this. Enable Banking never fetches the callback URL; the redirect happens\nentirely inside the user's browser, so an internal CA is perfectly sufficient for bank sync.\n\n#### 3d. Hardening, once HTTPS works\n\nTwo steps, once HTTPS works from every device you use.\n\n**Close the plain-HTTP port.** Until now `:8080` has served the whole app in cleartext to the LAN,\ncredentials included. Add the overlay file to remove that publish — the container still listens on\n8080 inside the Docker network, which is how Caddy reaches it:\n\n```bash\ndocker compose -f docker\u002Fdocker-compose.yml \\\n               -f docker\u002Fdocker-compose.no-http.yml \\\n               --profile tls up -d\n```\n\nKeep passing both `-f` flags from then on, or the publish comes back. (Requires Compose v2.24+ for\n`!reset`; on older versions comment out the `ports:` block in `docker\u002Fdocker-compose.yml` instead.)\n\n**Enable HSTS** — **only with a publicly-trusted\n(Let's Encrypt) certificate**:\n\n```bash\nprintf '\\nHSTS_ENABLED=true\\n' >> docker\u002F.env\ndocker compose -f docker\u002Fdocker-compose.yml \\\n               -f docker\u002Fdocker-compose.no-http.yml \\\n               --profile tls up -d --force-recreate app\n```\n\nBoth `-f` flags again — dropping the overlay here would re-publish the `:8080` port you just closed,\nand `--force-recreate` would make it happen immediately.\n\n`HSTS_ENABLED` sends `Strict-Transport-Security`, telling browsers to refuse plain HTTP for this\nhost for a year. It is off by default, so **if you run a public HTTPS deployment you should turn it\non** — otherwise nothing stops a browser being downgraded to the `:8080` port if it is exposed.\n\n`--force-recreate app` is needed because this value reaches the container only through `env_file`,\nwhich does not always change the rendered service config — a plain `up -d` can report the container\nas up-to-date and leave the old setting in place. Verify it took effect:\n\n```bash\ncurl -sI https:\u002F\u002Fpicsou.example.com\u002F | grep -i strict-transport\n```\n\nExactly one `Strict-Transport-Security` line when enabled, none when disabled.\n\nIn this image nginx is the only emitter the browser ever sees: it adds the header to every response\nincluding proxied ones, and strips the backend's copy on `\u002Fapi` and `\u002Factuator`\n(`proxy_hide_header`) so it is never sent twice. The backend has its own gate on the same variable,\nwhich is what the split-stack deployment relies on — to check that one, ask the backend directly,\nbypassing nginx:\n\n```bash\ndocker compose -f docker\u002Fdocker-compose.yml exec app \\\n  curl -sI -H 'X-Forwarded-Proto: https' http:\u002F\u002F127.0.0.1:9090\u002Factuator\u002Fhealth \\\n  | grep -i strict-transport\n```\n\n> [!WARNING]\n> Never set `HSTS_ENABLED=true` with an internal-CA or mkcert certificate. The browser remembers the\n> policy and then refuses to offer the \"proceed anyway\" bypass for a certificate it does not trust,\n> locking you out with no in-app recovery — only clearing HSTS state in browser internals\n> (`chrome:\u002F\u002Fnet-internals\u002F#hsts`) gets you back. It is off by default for this reason.\n\n#### 3e. Already running your own reverse proxy?\n\nSkip the profile entirely and point Traefik \u002F Nginx Proxy Manager \u002F a Cloudflare Tunnel at the app\ncontainer's `:8080`. Your proxy **must** forward `X-Forwarded-Proto: https` (all of the above do by\ndefault). Picsou honors that header to know it is served over HTTPS; without it the backend treats\nsame-origin HTTPS requests as cross-origin and login \u002F the wizard's **Origins** step fail with\n**403**. For a same-origin deployment leave `ALLOWED_ORIGINS` blank and let the wizard handle it,\nand keep `SECURE_COOKIES=true`.\n\n#### 3f. Adding HTTPS to an install that is already set up\n\nIf the wizard already ran over HTTP, three values are stored in the **database**, which takes\nprecedence over `.env` — editing environment variables will not change them.\n\nStart TLS as in 3b. Do **not** add the `no-http` overlay from 3d yet — you want plain HTTP on\n`:8080` to stay reachable as a fallback until HTTPS is confirmed from the machines you actually use:\n\n```bash\n[ -f docker\u002F.env ] || cp docker\u002F.env.example docker\u002F.env\nprintf '\\nPICSOU_DOMAIN=picsou.example.com\\n' >> docker\u002F.env\ndocker compose -f docker\u002Fdocker-compose.yml --profile tls pull\ndocker compose -f docker\u002Fdocker-compose.yml --profile tls up -d\n```\n\nThen log in over HTTPS and fix the three settings in the UI:\n\n| Setting | Where | New value |\n|---|---|---|\n| Redirect URI | Admin → Integrations → Enable Banking | `https:\u002F\u002F\u003Cdomain>\u002Fsync\u002Fcallback` |\n| Allowed origins | Admin → Security | add `https:\u002F\u002F\u003Cdomain>` |\n| Secure cookies | Admin → Security | `true` — **set this last**, after confirming HTTPS login works |\n\nFor allowed origins there is a shortcut: set `ALLOWED_ORIGINS` in `docker\u002F.env`, restart, then press\n**Reload from environment** in Admin → Security. That is the one place where env is allowed to\noverwrite the stored value. It covers CORS only — the redirect URI and cookie flag still have to be\nedited directly.\n\nThen update the redirect URI in the Enable Banking portal to match. Once HTTPS works from every\ndevice you care about, close the HTTP door with the `no-http` overlay from 3d.\n\nYou may not need the origins change at all: Caddy forwards `X-Forwarded-Host`\u002F`-Proto`, so the\nbackend should recognise the request as same-origin and skip CORS entirely. Only add the origin if\nyou actually hit a **403**.\n\n> [!WARNING]\n> **Once Secure cookies is `true`, plain HTTP is no longer a usable fallback.** Auth cookies are\n> issued with the `Secure` flag, which browsers discard over HTTP — login returns 200 and then\n> bounces straight back to the login screen with no error. If TLS later breaks (expired certificate,\n> lost `caddy_data` volume, DNS change) and you need to get back in over HTTP, clear the flag\n> directly in the database and restart:\n>\n> ```bash\n> docker compose -f docker\u002Fdocker-compose.yml exec db \\\n>   psql -U picsou -d picsou -c \\\n>   \"update app_setting set value='false' where setting_key='app.secure-cookies';\"\n> docker compose -f docker\u002Fdocker-compose.yml restart app\n> ```\n\n### 4. Advanced configuration (optional)\n\nIf you prefer to seed everything up front (CI, external secret managers, etc.):\n\n```bash\ncp docker\u002F.env.example docker\u002F.env\n```\n\n| Variable | When to set | Description |\n|----------|-------------|-------------|\n| `POSTGRES_PASSWORD` | Override auto-gen | Strong random password |\n| `JWT_SECRET` | Override auto-gen | `openssl rand -base64 48` |\n| `CRYPTO_ENCRYPTION_KEY` | Override auto-gen | `openssl rand -base64 32` |\n| `APP_USERNAME` \u002F `APP_PASSWORD_HASH` | Skip wizard | `htpasswd -bnBC 12 \"\" YOUR_PASSWORD \\| tr -d ':\\r\\n'` |\n| `ALLOWED_ORIGINS` | Non-localhost | e.g. `https:\u002F\u002Fpicsou.example.com` — leave blank for a same-origin deployment |\n| `SECURE_COOKIES` | Plain HTTP | `false` if no TLS in front; keep `true` behind HTTPS |\n| `ENABLEBANKING_*` | Skip wizard | From your [Enable Banking dashboard](https:\u002F\u002Fenablebanking.com\u002F). The redirect URI must be `https:\u002F\u002F` |\n| `BOURSO_AUTH_URL` | Custom sidecar | Defaults to `http:\u002F\u002Fbourso-auth:8001` |\n| `BOURSE_DIRECT_AUTH_URL` | Custom sidecar | Defaults to `http:\u002F\u002Fbourse-direct-auth:8001` |\n| `PICSOU_DOMAIN` | TLS profile | Hostname Caddy serves — see [step 3](#3-https-decide-before-the-first-launch) |\n| `HSTS_ENABLED` | Trusted cert | `true` only with a publicly-trusted certificate |\n\n> **Note:** The bcrypt hash contains `$` characters. In `.env`, write it as-is without quotes. Never export it in a shell without single quotes: `export APP_PASSWORD_HASH='$2a$12$...'`.\n\n> **Settings the wizard already stored win over `.env`.** `ENABLEBANKING_REDIRECT_URI`,\n> `ALLOWED_ORIGINS`, and `SECURE_COOKIES` resolve **database-first**, so once setup has completed,\n> changing them here has no effect — use the Admin page instead (see [3f](#3f-adding-https-to-an-install-that-is-already-set-up)).\n\n### 5. Enable Banking key setup (optional)\n\n```bash\nmkdir -p docker\u002Fsecrets\nopenssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out docker\u002Fsecrets\u002Fenablebanking.pem\nopenssl rsa -pubout -in docker\u002Fsecrets\u002Fenablebanking.pem -out enablebanking_public.pem\n```\n\nUpload `enablebanking_public.pem` to your Enable Banking dashboard.\n\n## Development\n\n### Backend\n\n```bash\ncd backend\nJAVA_HOME=$(\u002Fusr\u002Flibexec\u002Fjava_home -v 21) mvn spring-boot:run -Dspring-boot.run.profiles=dev   # Requires PostgreSQL on :5432\nJAVA_HOME=$(\u002Fusr\u002Flibexec\u002Fjava_home -v 21) mvn test                                              # Run tests\n```\n\nBackend Maven runs enforce Java 21 during `validate`; set `JAVA_HOME` to a JDK 21 installation before running backend commands locally.\n\n### Frontend\n\n```bash\ncd frontend\nbun install        # Install dependencies\nbun run dev        # HTTPS dev server on https:\u002F\u002Flocalhost:5173 (proxies \u002Fapi\u002F* → localhost:8080)\nbun run build      # TypeScript check + Vite build\nbunx vitest run    # Unit tests\n```\n\n#### 🔒 HTTPS in Development (Hybrid Mode)\n\nTo comply with the strict security requirements of certain banking integrations, the Vite development server is configured to run over **HTTPS**. The project utilizes a hybrid approach to make setup seamless for all environments:\n\n* **Premium Mode (Recommended for your host machine):** Install `mkcert` on your system, then generate your local certificates at the root of the `frontend\u002F` directory:\n  ```bash\n  mkdir -p .local\u002Fcerts\n  mkcert -cert-file .local\u002Fcerts\u002Fpicsou-local-cert.pem -key-file .local\u002Fcerts\u002Fpicsou-local-key.pem localhost 127.0.0.1 ::1\n  ```\n  *Benefit: You will get a natively trusted green padlock in your browser with zero security warnings.*\n\n* **Fallback Mode (Zero-Config \u002F Dev Container):** If the `.pem` files are not detected inside `.local\u002Fcerts\u002F`, the `@vitejs\u002Fplugin-basic-ssl` plugin will automatically take over.\n  *Note: The development server will still start over HTTPS, but you will need to bypass your browser's security warning on first access. Automation can instead opt in to ignoring the self-signed certificate.*\n\n## Contributing\n\nContributions are welcome — bug fixes, features, translations, or documentation.\n\n1. Fork the repository\n2. Create a feature branch (`feat\u002Fxxx`, `fix\u002Fxxx`)\n3. Write conventional commits\n4. Open a pull request against `main`\n\nPlease read the relevant [feature docs](docs\u002Ffeatures\u002F) and [conventions](docs\u002Fconventions\u002F) before touching existing code.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for the vulnerability reporting policy.\n\n## License\n\n[Apache 2.0 + Commons Clause](LICENSE) — free for personal use and managed hosting. Commercial SaaS use is prohibited without permission.\n","Picsou 是一款自托管的个人财务仪表盘，用于集中管理银行账户、证券经纪账户、加密货币钱包及净资产。它支持欧盟PSD2\u002FOAuth银行同步（覆盖2000+银行）、本地只读侧车程序接入法国特色金融产品（如PEA、Livret、Amundi员工储蓄计划）、多交易所与区块链地址跟踪、法国房地产自动估值、多成员家庭权限管理及GDPR合规数据导出。基于Java开发，强调本地部署安全边界，适用于注重隐私、需整合多源法国家庭财务数据的个人或家庭用户。",2,"trending"]