Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/guardrails.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
".ai-notes"
".agent"
)

for pattern in "${BLOCKED_FILES[@]}"; do
if find . -name "$pattern" -type f 2>/dev/null | grep -q .; then
echo "❌ Found blocked file: $pattern"
Expand All @@ -53,7 +53,7 @@ jobs:
"openhands"
"opencode"
)

for pattern in "${SENSITIVE_PATTERNS[@]}"; do
if grep -r "$pattern" . --include="*.ts" --include="*.js" --include="*.py" --include="*.md" 2>/dev/null | grep -v "node_modules" | grep -v ".git" | grep -q .; then
echo "⚠️ Found reference: $pattern"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/security-codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ["javascript", "python"]
language: ["javascript"]
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ Visit `http://localhost:3000` to access the application.

---

## 📖 Documentation

- **[User Manual](docs/user-manual.md)** — the full feature list and how to
configure and use Folio to manage your personal finances.
- **[Getting Started](docs/getting-started.md)** — install, set up your first
account, and learn the core concepts.
- **[Activity Types](docs/activities/activity-types.md)** — the 14 transaction
types and when to use each one.
- **[Addons](docs/addons/index.md)** — extend Folio with community features.

---

## 🛠️ Tech Stack

| Component | Technology |
Expand All @@ -115,15 +127,19 @@ Visit `http://localhost:3000` to access the application.

## 📊 Supported Banks

Folio supports automatic import from major Australian banks:
**Bank Connect** (automatic import from the desktop app) supports:

- Commonwealth Bank
- Westpac
- CommBank (CBA)
- ANZ
- NAB
- ING
- Macquarie
- And more...
- Bank of Melbourne
- Beyond Bank
- Interactive Brokers (broker, Beta)

Coming soon: CommSec, Sharesies, SelfWealth, and Stake.

Any other bank or broker can be tracked by importing a **CSV, OFX, or QIF**
statement file. Most Australian institutions offer a statement export.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function HelpPopover() {
<PopoverContent className="w-96" align="start">
<div className="space-y-4">
<div className="space-y-2">
<h4 className="font-medium leading-none">How It Works</h4>
<h4 className="leading-none font-medium">How It Works</h4>
<div className="text-muted-foreground space-y-2 text-sm">
<p>• Select a goal from your saved goals or track a custom target</p>
<p>• Each dot represents your chosen step amount towards your investment target</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function Tooltip({
<div className="bg-popover border-border w-64 rounded-md border p-3 text-sm shadow-md">
<div className="space-y-3">
<div className="space-y-1">
<h4 className="font-medium leading-none">Step {data.stepIndex + 1}</h4>
<h4 className="leading-none font-medium">Step {data.stepIndex + 1}</h4>
<p className="text-muted-foreground">
Target: {formatCurrency(data.stepAmount, isBalanceHidden)}
</p>
Expand All @@ -135,7 +135,7 @@ function Tooltip({
</div>
</div>
{/* Tooltip arrow */}
<div className="border-t-border absolute left-1/2 top-full h-0 w-0 -translate-x-1/2 transform border-l-4 border-r-4 border-t-4 border-l-transparent border-r-transparent"></div>
<div className="border-t-border absolute top-full left-1/2 h-0 w-0 -translate-x-1/2 transform border-t-4 border-r-4 border-l-4 border-r-transparent border-l-transparent"></div>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function EmptyPlaceholder({
{icon}
</div>
<h2 className="mt-2 text-xl font-semibold">{title}</h2>
<p className="text-muted-foreground mt-2 text-center text-sm font-normal leading-6">
<p className="text-muted-foreground mt-2 text-center text-sm leading-6 font-normal">
{description}
</p>
</div>
Expand Down Expand Up @@ -138,7 +138,7 @@ export function AccountBreakdown({
{percentage.toFixed(1)}% of total fees
</div>
{/* Tooltip arrow */}
<div className="border-t-border absolute left-1/2 top-full h-0 w-0 -translate-x-1/2 transform border-l-4 border-r-4 border-t-4 border-l-transparent border-r-transparent"></div>
<div className="border-t-border absolute top-full left-1/2 h-0 w-0 -translate-x-1/2 transform border-t-4 border-r-4 border-l-4 border-r-transparent border-l-transparent"></div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const FeeCategoriesChart = ({
<Card className="overflow-hidden backdrop-blur-sm">
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-muted-foreground text-sm font-medium uppercase tracking-wider">
<CardTitle className="text-muted-foreground text-sm font-medium tracking-wider uppercase">
Fee Categories
</CardTitle>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function FeeHistoryChart({
<CardTitle className="text-xl">Fee History</CardTitle>
<CardDescription>{periodDescription}</CardDescription>
</CardHeader>
<CardContent className="flex h-full flex-col px-4 pb-6 pt-0 sm:px-6">
<CardContent className="flex h-full flex-col px-4 pt-0 pb-6 sm:px-6">
{chartData.length === 0 ? (
<EmptyPlaceholder
className="mx-auto flex h-[300px] max-w-[420px] items-center justify-center"
Expand Down Expand Up @@ -127,7 +127,7 @@ export function FeeHistoryChart({
return (
<>
<div
className="border-border bg-(--color-bg) h-2.5 w-2.5 shrink-0 rounded-[2px]"
className="border-border h-2.5 w-2.5 shrink-0 rounded-[2px] bg-(--color-bg)"
style={
{
"--color-bg": entry.color,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function EmptyPlaceholder({
{icon}
</div>
<h2 className="mt-2 text-xl font-semibold">{title}</h2>
<p className="text-muted-foreground mt-2 text-center text-sm font-normal leading-6">
<p className="text-muted-foreground mt-2 text-center text-sm leading-6 font-normal">
{description}
</p>
</div>
Expand Down Expand Up @@ -138,7 +138,7 @@ export function TopFeeSources({ feeAnalytics, currency, isBalanceHidden }: TopFe
{percentage.toFixed(1)}% of total fees
</div>
{/* Tooltip arrow */}
<div className="border-t-border absolute left-1/2 top-full h-0 w-0 -translate-x-1/2 transform border-l-4 border-r-4 border-t-4 border-l-transparent border-r-transparent"></div>
<div className="border-t-border absolute top-full left-1/2 h-0 w-0 -translate-x-1/2 transform border-t-4 border-r-4 border-l-4 border-r-transparent border-l-transparent"></div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function DistributionCharts({ distribution, currency }: DistributionChart
return (
<>
<div
className="border-border bg-(--color-bg) h-2.5 w-2.5 shrink-0 rounded-[2px]"
className="border-border h-2.5 w-2.5 shrink-0 rounded-[2px] bg-(--color-bg)"
style={
{
"--color-bg": entry.color,
Expand Down Expand Up @@ -181,7 +181,7 @@ export function DistributionCharts({ distribution, currency }: DistributionChart
return (
<>
<div
className="border-border bg-(--color-bg) h-2.5 w-2.5 shrink-0 rounded-[2px]"
className="border-border h-2.5 w-2.5 shrink-0 rounded-[2px] bg-(--color-bg)"
style={
{
"--color-bg": entry.color,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function EquityCurveChart({
return (
<>
<div
className="border-border bg-(--color-bg) h-2.5 w-2.5 shrink-0 rounded-[2px]"
className="border-border h-2.5 w-2.5 shrink-0 rounded-[2px] bg-(--color-bg)"
style={
{
"--color-bg": entry.color,
Expand Down
4 changes: 2 additions & 2 deletions addons/swingfolio-addon/src/pages/dashboard-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export default function DashboardPage({ ctx }: DashboardPageProps) {
<Card
className={`${metrics.totalPL >= 0 ? "border-success/10 bg-success/10" : "border-destructive/10 bg-destructive/10"}`}
>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3 pt-4">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pt-4 pb-3">
<CardTitle className="text-sm font-medium">P/L</CardTitle>
<GainAmount
className="text-xl font-bold sm:text-2xl"
Expand Down Expand Up @@ -332,7 +332,7 @@ export default function DashboardPage({ ctx }: DashboardPageProps) {
{getChartPeriodDisplay(selectedPeriod).description}
</p>
</div>
<div className="bg-secondary text-muted-foreground self-start whitespace-nowrap rounded-full px-2 py-1 text-xs sm:self-auto">
<div className="bg-secondary text-muted-foreground self-start rounded-full px-2 py-1 text-xs whitespace-nowrap sm:self-auto">
{selectedPeriod} → {getChartPeriodDisplay(selectedPeriod).type}
</div>
</div>
Expand Down
4 changes: 1 addition & 3 deletions apps/frontend/src/addons/addons-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ async function loadAddon(addonFile: AddonFile, _context: AddonContext): Promise<
default?: unknown;
};
const defaultObj = asRecord.default as
| ((ctx: AddonContext) => unknown)
| { enable?: (ctx: AddonContext) => unknown }
| undefined;
((ctx: AddonContext) => unknown) | { enable?: (ctx: AddonContext) => unknown } | undefined;
const enableFunction: EnableFn =
(typeof defaultObj === "function" ? defaultObj : null) ??
(defaultObj &&
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/account-selector-mobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const AccountSelectorMobile = forwardRef<HTMLButtonElement, AccountSelect
{!iconOnly && "Add account"}
</Button>
</SheetTrigger>
<SheetContent side="bottom" className="rounded-t-4xl mx-1 h-[80vh] p-0">
<SheetContent side="bottom" className="mx-1 h-[80vh] rounded-t-4xl p-0">
<SheetHeader className="border-border border-b px-6 py-4">
<SheetTitle>Select Account</SheetTitle>
<SheetDescription>Choose an account to add to the comparison</SheetDescription>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/account-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ export const AccountSelector = forwardRef<HTMLButtonElement, AccountSelectorProp
role="combobox"
aria-expanded={open}
className={cn(
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
>
Expand Down
6 changes: 3 additions & 3 deletions apps/frontend/src/components/action-palette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function ActionPalette({
side={side}
sideOffset={8}
className={cn(
"w-auto min-w-[260px] max-w-[320px] p-0",
"w-auto max-w-[320px] min-w-[260px] p-0",
"rounded-2xl",
"border-border/50 border dark:border-white/10",
"bg-card backdrop-blur-xl",
Expand All @@ -74,7 +74,7 @@ export function ActionPalette({
>
{/* Header - only show if title provided */}
{title && (
<div className="flex items-center justify-between px-5 pb-3 pt-5">
<div className="flex items-center justify-between px-5 pt-5 pb-3">
<h3 className="text-foreground text-lg font-bold">{title}</h3>
<button
onClick={handleClose}
Expand All @@ -97,7 +97,7 @@ export function ActionPalette({
{groups.map((group, groupIndex) => (
<div key={groupIndex}>
{group.title && (
<div className="text-muted-foreground px-2 py-1.5 text-xs font-medium uppercase tracking-wider">
<div className="text-muted-foreground px-2 py-1.5 text-xs font-medium tracking-wider uppercase">
{group.title}
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/allocation-breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const AllocationBreadcrumb: React.FC<AllocationBreadcrumbProps> = ({
<nav className={cn("flex items-center gap-1 text-sm", className)}>
<button
onClick={() => onNavigate(0)}
className="text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors"
className="text-muted-foreground hover:text-foreground font-medium tracking-wider uppercase transition-colors"
>
{rootLabel}
</button>
Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/src/components/app-launcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ export function AppLauncher() {
<Sheet open={open} onOpenChange={setOpen}>
<SheetContent
side="bottom"
className="mx-auto flex h-[85vh] w-full max-w-screen-sm flex-col overflow-hidden rounded-t-3xl border-none px-0 pb-6 pt-4"
className="mx-auto flex h-[85vh] w-full max-w-screen-sm flex-col overflow-hidden rounded-t-3xl border-none px-0 pt-4 pb-6"
>
<SheetHeader className="px-6">
<SheetTitle>Quick launch</SheetTitle>
Expand All @@ -758,7 +758,7 @@ export function AppLauncher() {
className={cn(
"flex flex-1 flex-col bg-transparent",
"[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-4 [&_[cmdk-group-heading]]:font-medium",
"[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2",
"[&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0",
"[&_[cmdk-input-wrapper]]:px-5 [&_[cmdk-input]]:h-14 [&_[cmdk-input]]:text-base",
"[&_[cmdk-item]]:px-4 [&_[cmdk-item]]:py-4 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5",
"[&_[data-cmdk-input-wrapper]_svg]:h-5 [&_[data-cmdk-input-wrapper]_svg]:w-5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export function BenchmarkSymbolSelectorMobile({
{!iconOnly && "Add Benchmark"}
</Button>
</SheetTrigger>
<SheetContent side="bottom" className="rounded-t-4xl mx-1 h-[85vh] p-0">
<SheetContent side="bottom" className="mx-1 h-[85vh] rounded-t-4xl p-0">
<SheetHeader className="border-border border-b px-6 py-4">
<SheetTitle>Select Benchmark</SheetTitle>
<SheetDescription>Choose a benchmark or search for any symbol</SheetDescription>
Expand All @@ -197,13 +197,13 @@ export function BenchmarkSymbolSelectorMobile({
{/* Search Input */}
<div className="border-border border-b px-6 py-3">
<div className="relative">
<Icons.Search className="text-muted-foreground absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2" />
<Icons.Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
<input
type="text"
placeholder="Search benchmarks or any symbol..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="bg-background border-input ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring h-10 w-full rounded-md border px-3 py-2 pl-9 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
className="bg-background border-input ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring h-10 w-full rounded-md border px-3 py-2 pl-9 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function ClassificationSheet({
</SheetHeader>

<div className="min-h-0 flex-1 overflow-y-auto pr-1">
<div className="space-y-8 pb-8 pt-4">
<div className="space-y-8 pt-4 pb-8">
{/* Loading State */}
{isLoading && <ClassificationSkeleton />}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export function MultiSelectTaxonomy({
className="h-8 pr-6 text-sm"
placeholder="100"
/>
<span className="text-muted-foreground pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-sm">
<span className="text-muted-foreground pointer-events-none absolute top-1/2 right-2 -translate-y-1/2 text-sm">
%
</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/font-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function FontSelector({ value, onChange, className }: FontSelectorProps)
</div>
<div className="text-xs font-medium sm:text-sm">{font.label}</div>
{value === font.value && (
<div className="bg-primary absolute right-2 top-2 h-1.5 w-1.5 rounded-full" />
<div className="bg-primary absolute top-2 right-2 h-1.5 w-1.5 rounded-full" />
)}
</button>
))}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/liquid-glass.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function LiquidGlass({
style={{ ...style }}
>
<div className="relative z-10">{children}</div>
<div className="z-5 pointer-events-none absolute inset-0 bg-gradient-to-br from-white/10 via-transparent to-transparent" />
<div className="pointer-events-none absolute inset-0 z-5 bg-gradient-to-br from-white/10 via-transparent to-transparent" />
</div>
);
}
4 changes: 2 additions & 2 deletions apps/frontend/src/components/mobile-actions-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function MobileActionsMenu({
<Icons.MoreVertical className="h-4 w-4" />
</Button>
</SheetTrigger>
<SheetContent side="bottom" className="rounded-t-4xl mx-1 p-0">
<SheetContent side="bottom" className="mx-1 rounded-t-4xl p-0">
<SheetHeader className="border-border border-b px-6 py-4">
<SheetTitle>{title}</SheetTitle>
<SheetDescription>{description}</SheetDescription>
Expand All @@ -53,7 +53,7 @@ export function MobileActionsMenu({
action.onClick();
onOpenChange(false);
}}
className="hover:bg-accent active:bg-accent/80 focus:ring-primary flex items-center gap-4 rounded-lg border p-4 text-left transition-colors focus:outline-none focus:ring-2"
className="hover:bg-accent active:bg-accent/80 focus:ring-primary flex items-center gap-4 rounded-lg border p-4 text-left transition-colors focus:ring-2 focus:outline-none"
>
<div className="bg-primary/10 flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-full">
<IconComponent className="text-primary h-5 w-5" />
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/mobile-loading-indicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function MobileLoadingIndicator() {
}

return (
<div className="bg-primary/10 z-100 fixed inset-x-0 top-0 h-[3px] overflow-hidden">
<div className="bg-primary/10 fixed inset-x-0 top-0 z-100 h-[3px] overflow-hidden">
{/* Smooth indeterminate progress strip */}
<div
className="bg-primary h-full w-2/5 rounded-full"
Expand Down
Loading
Loading