Files
HOA_Financial_Platform/db/init/00-init.sql
olsch01 e0272f9d8a Rename to HOA LedgerIQ and implement remaining report pages
- Rename app from "HOA Financial Platform" to "HOA LedgerIQ" across all
  frontend pages, backend API docs, package.json files, and seed data
- Add Cash Flow Statement report (GET /reports/cash-flow) with operating
  and reserve fund activity breakdown, beginning/ending cash balances
- Add Aging Report (GET /reports/aging) with per-unit aging buckets
  (current, 1-30, 31-60, 61-90, 90+ days), expandable invoice details
- Add Year-End Package (GET /reports/year-end) with income statement
  summary, collection stats, 1099-NEC vendor report, reserve fund status
- Add Settings page showing org info, user profile, and system details
- Replace all PlaceholderPage references with real implementations
- Bump auth store version to 3 for localStorage migration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 09:09:50 -05:00

80 lines
2.9 KiB
SQL

-- HOA LedgerIQ - Database Initialization
-- Creates shared schema and base tables for multi-tenant architecture
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- Shared schema for cross-tenant data
CREATE SCHEMA IF NOT EXISTS shared;
-- Organizations (HOAs)
CREATE TABLE shared.organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
schema_name VARCHAR(63) NOT NULL UNIQUE,
subdomain VARCHAR(63) UNIQUE,
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'trial')),
settings JSONB DEFAULT '{}',
address_line1 VARCHAR(255),
address_line2 VARCHAR(255),
city VARCHAR(100),
state VARCHAR(2),
zip_code VARCHAR(10),
phone VARCHAR(20),
email VARCHAR(255),
tax_id VARCHAR(20),
fiscal_year_start_month INTEGER DEFAULT 1 CHECK (fiscal_year_start_month BETWEEN 1 AND 12),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Users (global, cross-tenant)
CREATE TABLE shared.users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255),
first_name VARCHAR(100),
last_name VARCHAR(100),
phone VARCHAR(20),
is_email_verified BOOLEAN DEFAULT FALSE,
mfa_enabled BOOLEAN DEFAULT FALSE,
mfa_secret VARCHAR(255),
oauth_provider VARCHAR(50),
oauth_provider_id VARCHAR(255),
last_login_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- User-Organization memberships with roles
CREATE TABLE shared.user_organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES shared.users(id) ON DELETE CASCADE,
organization_id UUID NOT NULL REFERENCES shared.organizations(id) ON DELETE CASCADE,
role VARCHAR(50) NOT NULL CHECK (role IN ('president', 'treasurer', 'secretary', 'member_at_large', 'manager', 'homeowner')),
is_active BOOLEAN DEFAULT TRUE,
joined_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, organization_id)
);
-- Invitations
CREATE TABLE shared.invitations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID NOT NULL REFERENCES shared.organizations(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL,
invited_by UUID NOT NULL REFERENCES shared.users(id),
token VARCHAR(255) NOT NULL UNIQUE,
expires_at TIMESTAMPTZ NOT NULL,
accepted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_user_orgs_user ON shared.user_organizations(user_id);
CREATE INDEX idx_user_orgs_org ON shared.user_organizations(organization_id);
CREATE INDEX idx_users_email ON shared.users(email);
CREATE INDEX idx_orgs_schema ON shared.organizations(schema_name);
CREATE INDEX idx_invitations_token ON shared.invitations(token);
CREATE INDEX idx_invitations_email ON shared.invitations(email);