+ );
+}
diff --git a/supabase/migrations/20260609170000_budget_workbook.sql b/supabase/migrations/20260609170000_budget_workbook.sql
new file mode 100644
index 0000000..02baec7
--- /dev/null
+++ b/supabase/migrations/20260609170000_budget_workbook.sql
@@ -0,0 +1,41 @@
+-- Budget Workbook: standalone worksheet state (chosen month + per-line inflation %
+-- and overrides) for the Budget Workbook page. Computed values come from the GL at
+-- runtime; only the user's edits are persisted here. Company-scoped, RLS mirrors
+-- accounting.accounts (accounting staff OR company member).
+
+create table if not exists accounting.budget_workbooks (
+ id uuid primary key default gen_random_uuid(),
+ company_id uuid not null references accounting.companies(id) on delete cascade,
+ fiscal_year int not null,
+ through_month int not null default 1,
+ created_at timestamptz not null default now(),
+ updated_at timestamptz not null default now(),
+ unique (company_id, fiscal_year)
+);
+
+create table if not exists accounting.budget_workbook_lines (
+ id uuid primary key default gen_random_uuid(),
+ workbook_id uuid not null references accounting.budget_workbooks(id) on delete cascade,
+ account_id uuid not null references accounting.accounts(id) on delete cascade,
+ ytd_override numeric,
+ inflation_pct numeric,
+ projected_override numeric,
+ unique (workbook_id, account_id)
+);
+
+alter table accounting.budget_workbooks enable row level security;
+alter table accounting.budget_workbook_lines enable row level security;
+
+create policy "wb staff" on accounting.budget_workbooks for all to authenticated
+ using (accounting.is_accounting_staff()) with check (accounting.is_accounting_staff());
+create policy "wb members" on accounting.budget_workbooks for all to authenticated
+ using (accounting.is_company_member(company_id, auth.uid())) with check (accounting.is_company_member(company_id, auth.uid()));
+
+create policy "wbl staff" on accounting.budget_workbook_lines for all to authenticated
+ using (accounting.is_accounting_staff()) with check (accounting.is_accounting_staff());
+create policy "wbl members" on accounting.budget_workbook_lines for all to authenticated
+ using (exists (select 1 from accounting.budget_workbooks w where w.id = workbook_id and accounting.is_company_member(w.company_id, auth.uid())))
+ with check (exists (select 1 from accounting.budget_workbooks w where w.id = workbook_id and accounting.is_company_member(w.company_id, auth.uid())));
+
+grant select, insert, update, delete on accounting.budget_workbooks to authenticated;
+grant select, insert, update, delete on accounting.budget_workbook_lines to authenticated;