community feature

This commit is contained in:
wass08
2026-02-11 15:23:18 +09:00
parent 4f9c4655e6
commit 2e8b663001
71 changed files with 1917 additions and 126 deletions
@@ -0,0 +1,80 @@
-- Better Auth tables (copied from working monorepo)
-- Using auth_ prefix and snake_case columns
CREATE TYPE "public"."auth_user_roles" AS ENUM('user', 'admin');
CREATE TABLE "auth_accounts" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"provider_id" text NOT NULL,
"account_id" text NOT NULL,
"password" text,
"access_token" text,
"refresh_token" text,
"id_token" text,
"access_token_expires_at" timestamp with time zone,
"refresh_token_expires_at" timestamp with time zone,
"scope" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "auth_accounts" ENABLE ROW LEVEL SECURITY;
CREATE TABLE "auth_jwks" (
"id" text PRIMARY KEY NOT NULL,
"public_key" text NOT NULL,
"private_key" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "auth_jwks" ENABLE ROW LEVEL SECURITY;
CREATE TABLE "auth_sessions" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"expires_at" timestamp with time zone,
"token" text NOT NULL,
"ip_address" text,
"user_agent" text,
"impersonated_by" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "auth_sessions" ENABLE ROW LEVEL SECURITY;
CREATE TABLE "auth_users" (
"id" text PRIMARY KEY NOT NULL,
"email" text NOT NULL,
"email_verified" boolean DEFAULT false NOT NULL,
"name" text NOT NULL,
"image" text,
"role" "auth_user_roles" DEFAULT 'user' NOT NULL,
"banned" boolean DEFAULT false NOT NULL,
"ban_reason" text,
"ban_expires" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "auth_users" ENABLE ROW LEVEL SECURITY;
CREATE TABLE "auth_verifications" (
"id" text PRIMARY KEY NOT NULL,
"value" text NOT NULL,
"identifier" text NOT NULL,
"expires_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "auth_verifications" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "auth_accounts" ADD CONSTRAINT "auth_accounts_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_impersonated_by_auth_users_id_fk" FOREIGN KEY ("impersonated_by") REFERENCES "public"."auth_users"("id") ON DELETE set null ON UPDATE no action;
CREATE UNIQUE INDEX "email_unique_index" ON "auth_users" USING btree (lower("email"));
@@ -0,0 +1,165 @@
-- Properties tables
-- Simple property management without organizations
-- Properties addresses table (must be created first due to foreign key)
CREATE TABLE IF NOT EXISTS properties_addresses (
id TEXT PRIMARY KEY,
street_number TEXT,
route TEXT,
route_short TEXT,
neighborhood TEXT,
city TEXT,
county TEXT,
state TEXT,
state_long TEXT,
postal_code TEXT,
postal_code_suffix TEXT,
country TEXT,
country_long TEXT,
latitude NUMERIC,
longitude NUMERIC,
raw_json JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(street_number, route, city, state, postal_code)
);
CREATE INDEX IF NOT EXISTS idx_properties_addresses_city_state ON properties_addresses(city, state);
-- Properties table
CREATE TABLE IF NOT EXISTS properties (
id TEXT PRIMARY KEY,
name TEXT,
address_id TEXT UNIQUE REFERENCES properties_addresses(id) ON DELETE SET NULL,
owner_id TEXT REFERENCES auth_users(id) ON DELETE SET NULL,
details_json JSONB,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_properties_owner_id ON properties(owner_id);
CREATE INDEX IF NOT EXISTS idx_properties_address_id ON properties(address_id);
-- Properties models table (scene graphs)
CREATE TABLE IF NOT EXISTS properties_models (
id TEXT PRIMARY KEY,
name TEXT,
version INTEGER DEFAULT 1,
description TEXT,
draft BOOLEAN DEFAULT true,
property_id TEXT REFERENCES properties(id) ON DELETE SET NULL,
scene_graph JSONB,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_properties_models_property_id ON properties_models(property_id);
CREATE INDEX IF NOT EXISTS idx_properties_models_version ON properties_models(property_id, version DESC);
-- Enable Row Level Security (RLS)
ALTER TABLE properties ENABLE ROW LEVEL SECURITY;
ALTER TABLE properties_addresses ENABLE ROW LEVEL SECURITY;
ALTER TABLE properties_models ENABLE ROW LEVEL SECURITY;
-- RLS Policies for properties table
CREATE POLICY "Users can view their own properties"
ON properties FOR SELECT
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
CREATE POLICY "Users can insert their own properties"
ON properties FOR INSERT
WITH CHECK (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
CREATE POLICY "Users can update their own properties"
ON properties FOR UPDATE
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
CREATE POLICY "Users can delete their own properties"
ON properties FOR DELETE
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
-- RLS Policies for properties_addresses table
-- Addresses table doesn't have property_id, so we'll allow all authenticated users
CREATE POLICY "Authenticated users can view all addresses"
ON properties_addresses FOR SELECT
USING (true);
CREATE POLICY "Authenticated users can insert addresses"
ON properties_addresses FOR INSERT
WITH CHECK (true);
CREATE POLICY "Authenticated users can update addresses"
ON properties_addresses FOR UPDATE
USING (true);
CREATE POLICY "Authenticated users can delete addresses"
ON properties_addresses FOR DELETE
USING (true);
-- RLS Policies for properties_models table
CREATE POLICY "Users can view models of their own properties"
ON properties_models FOR SELECT
USING (
EXISTS (
SELECT 1 FROM properties
WHERE properties.id = properties_models.property_id
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
)
);
CREATE POLICY "Users can insert models for their own properties"
ON properties_models FOR INSERT
WITH CHECK (
EXISTS (
SELECT 1 FROM properties
WHERE properties.id = properties_models.property_id
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
)
);
CREATE POLICY "Users can update models of their own properties"
ON properties_models FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM properties
WHERE properties.id = properties_models.property_id
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
)
);
CREATE POLICY "Users can delete models of their own properties"
ON properties_models FOR DELETE
USING (
EXISTS (
SELECT 1 FROM properties
WHERE properties.id = properties_models.property_id
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
)
);
-- Trigger to update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_properties_updated_at
BEFORE UPDATE ON properties
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_properties_addresses_updated_at
BEFORE UPDATE ON properties_addresses
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_properties_models_updated_at
BEFORE UPDATE ON properties_models
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
@@ -0,0 +1,2 @@
-- Add active_property_id to sessions table
ALTER TABLE auth_sessions ADD COLUMN IF NOT EXISTS active_property_id TEXT;