0.2.39: bitcoin-denominated view, first-login flow, unfunded + tax center
- BTC prices: btc_prices table, CSV upload on Import page (auto-detected date/close columns, upsert by date), entities.close_date as the BTC entry mark; statements carry btc_price_cents (as-of) + btc_close_price_cents. LP capital blocks show paid-in vs current value in bitcoin terms. - First login: accounts on the shared default password are flagged (must_change_password) and blocked behind a full-screen password change; external accounts then get a one-time welcome tour with a 2FA offer (users.onboarded_at). - LP portal: Unfunded (callable commitment) metric; Tax documents center aggregating K-1/tax docs across funds, grouped by year. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
0822eca887
commit
eac3262f29
@@ -45,6 +45,8 @@ export interface User {
|
||||
is_service_admin: boolean;
|
||||
primary_account_id: number | null;
|
||||
totp_enabled: boolean;
|
||||
must_change_password: boolean;
|
||||
onboarded_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
@@ -154,6 +156,18 @@ export interface BatchCapitalImportResult {
|
||||
total_statements: number;
|
||||
}
|
||||
|
||||
export interface BtcPricesStatus {
|
||||
count: number;
|
||||
first_date: string | null;
|
||||
last_date: string | null;
|
||||
latest_price_cents: number | null;
|
||||
}
|
||||
|
||||
export interface BtcPricesImportResult extends BtcPricesStatus {
|
||||
imported: number;
|
||||
skipped_rows: number;
|
||||
}
|
||||
|
||||
export interface CapitalAccount {
|
||||
id: number;
|
||||
entity_id: number;
|
||||
@@ -168,6 +182,9 @@ export interface CapitalAccount {
|
||||
document_id: number | null;
|
||||
created_at: string;
|
||||
exited_on: string | null;
|
||||
// BTC/USD marks for the bitcoin-denominated view (null = no price data / no close date)
|
||||
btc_price_cents: number | null;
|
||||
btc_close_price_cents: number | null;
|
||||
}
|
||||
|
||||
export interface Entity {
|
||||
@@ -178,6 +195,7 @@ export interface Entity {
|
||||
fund_size_cents: number | null;
|
||||
status: EntityStatus;
|
||||
linked_user_id: number | null;
|
||||
close_date: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
@@ -514,6 +532,20 @@ export const api = {
|
||||
if (!res.ok) throw new ApiError(res.status, data.detail || "Batch import failed");
|
||||
return data;
|
||||
},
|
||||
// BTC prices (bitcoin-denominated view)
|
||||
btcPricesStatus: () => request<BtcPricesStatus>("/api/import/btc-prices"),
|
||||
importBtcPrices: async (file: File): Promise<BtcPricesImportResult> => {
|
||||
const form = new FormData();
|
||||
form.set("file", file);
|
||||
const res = await fetch("/api/import/btc-prices", { method: "POST", body: form });
|
||||
const data = await res.json().catch(() => ({ detail: res.statusText }));
|
||||
if (!res.ok) throw new ApiError(res.status, data.detail || "Price import failed");
|
||||
return data;
|
||||
},
|
||||
|
||||
markOnboarded: () =>
|
||||
request<{ status: string }>("/api/auth/onboarded", { method: "POST" }),
|
||||
|
||||
getUser: (id: number) => request<UserDetail>(`/api/users/${id}`),
|
||||
createUser: (data: {
|
||||
name: string;
|
||||
|
||||
Reference in New Issue
Block a user