Skip to main content

Overview

The Inmobiliaria Web application uses PostgreSQL as its primary database. The schema is designed to support a comprehensive real estate management system with authentication, property listings, and user management.
The complete schema is available in inmobiliaria_complete_schema.sql in the project root.

Authentication Tables

The authentication system uses Better Auth compatible tables.

users

Core user account information.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYUnique user identifier
emailVARCHAR(255)NOT NULL, UNIQUEUser email address
nameVARCHAR(255)User’s full name
imageTEXTProfile image URL
email_verifiedTIMESTAMPEmail verification timestamp
roleVARCHAR(50)DEFAULT ‘user’User role: ‘user’ or ‘admin’
created_atTIMESTAMPDEFAULT NOW()Account creation timestamp
updated_atTIMESTAMPDEFAULT NOW()Last update timestamp

accounts

OAuth provider accounts linked to users.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYAccount identifier
user_idINTEGERNOT NULL, FK → users(id)Associated user
typeVARCHAR(50)NOT NULL’oauth’ or ‘email’
providerVARCHAR(50)NOT NULL’google’, ‘email’, etc.
provider_account_idVARCHAR(255)NOT NULLProvider’s user ID
refresh_tokenTEXTOAuth refresh token
access_tokenTEXTOAuth access token
expires_atINTEGERToken expiration timestamp
token_typeVARCHAR(50)Token type (e.g., ‘Bearer’)
scopeTEXTOAuth scopes
id_tokenTEXTOpenID Connect ID token
session_stateVARCHAR(255)Session state
created_atTIMESTAMPDEFAULT NOW()Creation timestamp
The (provider, provider_account_id) combination is unique.

sessions

Active user sessions.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYSession identifier
session_tokenVARCHAR(255)NOT NULL, UNIQUESession token
user_idINTEGERNOT NULL, FK → users(id)Associated user
expiresTIMESTAMPNOT NULLSession expiration
created_atTIMESTAMPDEFAULT NOW()Creation timestamp

verification_tokens

Email verification and password reset tokens.
ColumnTypeConstraintsDescription
identifierVARCHAR(255)NOT NULL, PKUser identifier (email)
tokenVARCHAR(255)NOT NULL, PKVerification token
expiresTIMESTAMPNOT NULLToken expiration

user_passwords

Password hashes for email/password authentication.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYRecord identifier
user_idINTEGERNOT NULL, FK → users(id)Associated user
password_hashVARCHAR(255)NOT NULLHashed password
created_atTIMESTAMPDEFAULT NOW()Creation timestamp
updated_atTIMESTAMPDEFAULT NOW()Last update timestamp

Property Management Tables

property_types

Types of properties (Casa, Departamento, etc.).
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYType identifier
nameVARCHAR(100)NOT NULL, UNIQUEDisplay name
slugVARCHAR(100)NOT NULL, UNIQUEURL-friendly slug
Pre-populated data (14 types):
  • Casa, Departamento, PH, Terreno, Local comercial, Galpón, Oficina comercial, Campo, Depósito, Bodega, Consultorio, Fondo de comercio, Hotel, Cochera

property_subtypes

Subtypes for more specific property classification.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYSubtype identifier
type_idINTEGERFK → property_types(id)Parent property type
nameVARCHAR(100)NOT NULLDisplay name
slugVARCHAR(100)NOT NULLURL-friendly slug
Examples:
  • Casa: “Casa en barrio cerrado”, “Casa en country”
  • Departamento: “Monoambiente”, “Departamento tipo dúplex”, “Departamento en torre”
  • PH: “PH con jardín”, “PH al fondo”

operation_types

Types of property operations.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYOperation identifier
nameVARCHAR(50)NOT NULL, UNIQUEDisplay name
slugVARCHAR(50)NOT NULL, UNIQUEURL-friendly slug
Pre-populated data:
  • Venta, Alquiler, Alquiler temporal, Permuta

property_conditions

Property condition/state.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYCondition identifier
nameVARCHAR(50)NOT NULL, UNIQUECondition name
Pre-populated data:
  • A estrenar, Bueno, Muy bueno, Excelente, Reciclado, Para refaccionar

currencies

Supported currencies for pricing.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYCurrency identifier
codeVARCHAR(3)NOT NULL, UNIQUEISO currency code
symbolVARCHAR(10)NOT NULLCurrency symbol
nameVARCHAR(50)NOT NULLCurrency name
Pre-populated data:
  • ARS (Peso Argentino), USD (Dólar Estadounidense), EUR (Euro)

features

Available property features/amenities.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYFeature identifier
nameVARCHAR(100)NOT NULL, UNIQUEFeature name
Pre-populated data:
  • Parrilla, Pileta, Aire acondicionado, SUM, Gimnasio, Seguridad 24hs, Ascensor, Balcón, Terraza, Jardín, Cochera, Lavadero, Internet, Electricidad

tags

Property tags for highlighting special characteristics.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYTag identifier
nameVARCHAR(100)NOT NULL, UNIQUETag name
Pre-populated data:
  • Oportunidad, Crédito hipotecario, Apto profesional, Acepta permuta, Apto crédito, Amoblado, Acepta mascotas, Dueño directo

property_statuses

Property publication status.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYStatus identifier
nameVARCHAR(50)NOT NULL, UNIQUEStatus display name
slugVARCHAR(50)NOT NULL, UNIQUEURL-friendly slug
Pre-populated data:
  • Activo, Pendiente, Vendido, Alquilado, Pausado

properties

Main property listings table.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYProperty identifier
titleVARCHAR(255)NOT NULLProperty title
descriptionTEXTDetailed description
property_type_idINTEGERFK → property_types(id)Property type
property_subtype_idINTEGERFK → property_subtypes(id)Property subtype
operation_type_idINTEGERFK → operation_types(id)Operation type
status_idINTEGERFK → property_statuses(id)Publication status
priceNUMERIC(12,2)NOT NULLProperty price
original_priceNUMERIC(12,2)Original price (for discounts)
currency_idINTEGERFK → currencies(id)Price currency
expensesNUMERIC(12,2)Monthly expenses
surface_total_m2NUMERIC(8,2)Total surface area
surface_covered_m2NUMERIC(8,2)Covered surface area
lot_size_m2NUMERIC(10,2)Lot/land size
roomsINTEGERNumber of rooms
bedroomsINTEGERNumber of bedrooms
bathroomsINTEGERNumber of bathrooms
year_builtINTEGERConstruction year
condition_idINTEGERFK → property_conditions(id)Property condition
floorINTEGERFloor number
has_balconyBOOLEANDEFAULT FALSEHas balcony
has_terraceBOOLEANDEFAULT FALSEHas terrace
has_garageBOOLEANDEFAULT FALSEHas garage
has_laundryBOOLEANDEFAULT FALSEHas laundry
has_gardenBOOLEANDEFAULT FALSEHas garden
pets_allowedBOOLEANDEFAULT FALSEPets allowed
contact_phoneVARCHAR(50)Contact phone
contact_emailVARCHAR(255)Contact email
user_idINTEGERFK → users(id)Property owner/agent
views_countINTEGERDEFAULT 0View counter
created_atTIMESTAMPDEFAULT NOW()Creation timestamp
updated_atTIMESTAMPDEFAULT NOW()Last update timestamp
published_atTIMESTAMPPublication timestamp
url_slugVARCHAR(255)UNIQUEURL-friendly slug
search_vectorTSVECTORFull-text search vector

property_locations

Geographic location data for properties.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYLocation identifier
property_idINTEGERFK → properties(id), UNIQUEAssociated property
streetVARCHAR(255)Street name
street_numberVARCHAR(20)Street number
floor_apartmentVARCHAR(50)Floor/apartment
neighborhoodVARCHAR(100)Neighborhood
cityVARCHAR(100)NOT NULLCity
provinceVARCHAR(100)NOT NULLProvince/state
postal_codeVARCHAR(20)Postal code
countryVARCHAR(100)DEFAULT ‘Argentina’Country
latitudeDECIMAL(10,7)GPS latitude
longitudeDECIMAL(10,7)GPS longitude
show_exact_addressBOOLEANDEFAULT FALSEDisplay full address

property_images

Property photos and images.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYImage identifier
property_idINTEGERFK → properties(id)Associated property
image_urlTEXTNOT NULLImage URL
order_indexINTEGERDEFAULT 0Display order
is_mainBOOLEANDEFAULT FALSEMain/featured image
uploaded_atTIMESTAMPDEFAULT NOW()Upload timestamp

property_features

Many-to-many relationship between properties and features.
ColumnTypeConstraintsDescription
property_idINTEGERFK → properties(id), PKProperty reference
feature_idINTEGERFK → features(id), PKFeature reference

property_tags

Many-to-many relationship between properties and tags.
ColumnTypeConstraintsDescription
property_idINTEGERFK → properties(id), PKProperty reference
tag_idINTEGERFK → tags(id), PKTag reference

User Interaction Tables

user_favorites

User’s favorite/saved properties.
ColumnTypeConstraintsDescription
idSERIALPRIMARY KEYFavorite identifier
user_idINTEGERFK → users(id)User reference
property_idINTEGERFK → properties(id)Property reference
created_atTIMESTAMPDEFAULT NOW()Creation timestamp
The (user_id, property_id) combination is unique.

Indexes

Performance indexes for common queries:

Authentication Indexes

CREATE INDEX idx_sessions_token ON sessions(session_token);
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
CREATE INDEX idx_accounts_user_id ON accounts(user_id);

Property Indexes

CREATE INDEX idx_properties_type ON properties(property_type_id);
CREATE INDEX idx_properties_operation ON properties(operation_type_id);
CREATE INDEX idx_properties_status ON properties(status_id);

Location Indexes

CREATE INDEX idx_locations_city ON property_locations(city);
CREATE INDEX idx_locations_province ON property_locations(province);

Full-Text Search Index

CREATE INDEX idx_properties_search ON properties USING GIN(search_vector);
The GIN index enables fast full-text search on property titles and descriptions in Spanish.

Triggers

Automatic database triggers for data maintenance.

Update Timestamps

Automatically updates updated_at columns:
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_users_updated_at 
    BEFORE UPDATE ON users
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_properties_updated_at 
    BEFORE UPDATE ON properties
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

Full-Text Search Vector

Automatically maintains search vectors for properties:
CREATE OR REPLACE FUNCTION update_property_search_vector()
RETURNS TRIGGER AS $$
BEGIN
    NEW.search_vector := 
        setweight(to_tsvector('spanish', COALESCE(NEW.title, '')), 'A') ||
        setweight(to_tsvector('spanish', COALESCE(NEW.description, '')), 'B');
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_properties_search_vector 
    BEFORE INSERT OR UPDATE ON properties
    FOR EACH ROW EXECUTE FUNCTION update_property_search_vector();
  • Title text is weighted higher (‘A’) than description (‘B’) in search results
  • Uses Spanish language configuration for proper stemming and stop words

Relationships Diagram

Users & Authentication:
  • usersaccounts (one-to-many)
  • userssessions (one-to-many)
  • usersuser_passwords (one-to-one)
Properties & Metadata:
  • propertiesproperty_types (many-to-one)
  • propertiesproperty_subtypes (many-to-one)
  • propertiesoperation_types (many-to-one)
  • propertiesproperty_statuses (many-to-one)
  • propertiescurrencies (many-to-one)
  • propertiesproperty_conditions (many-to-one)
  • propertiesusers (many-to-one)
Property Details:
  • propertiesproperty_locations (one-to-one)
  • propertiesproperty_images (one-to-many)
  • propertiesfeatures (many-to-many via property_features)
  • propertiestags (many-to-many via property_tags)
User Interactions:
  • usersproperties (many-to-many via user_favorites)

Database Setup

To set up the complete database schema:
# Create the database
creatdb inmobiliaria

# Load the schema
psql -d inmobiliaria -f inmobiliaria_complete_schema.sql

# Verify tables were created
psql -d inmobiliaria -c "\dt"
All foreign key relationships use ON DELETE CASCADE, meaning deleting a parent record will automatically delete related child records.

Next Steps

Build docs developers (and LLMs) love