Skip to main content

Overview

RLink uses PostgreSQL (hosted on Neon) with Drizzle ORM for type-safe database operations. The schema is organized into three main domains:

CMS Tables

Content, projects, articles, careers

CRM Tables

Leads, reservations, inquiries, campaigns

IAM Tables

Users, sessions, access control, logs

Schema Files

The database schema is split across two files:
  • db/schema.ts: Application-specific tables (CMS, CRM, IAM)
  • db/auth-schema.ts: Better Auth tables (users, sessions, etc.)

Entity Relationship Diagram

CMS Tables

Projects

Stores property development projects.
ColumnTypeDescription
idUUIDPrimary key
nameVARCHARProject name
slugVARCHARURL-friendly identifier
descriptionTEXTProject description
statusENUMactive, upcoming, completed, on-hold
typeENUMresidential, commercial, mixed-use
stageENUMpre-selling, selling, sold-out, under-construction
locationTEXTPhysical address
coordinatesJSONLatitude/longitude
nearby_landmarksJSONArray of nearby places
amenitiesJSONArray of amenity IDs
price_rangeJSON{ min, max } pricing
cover_photoVARCHARCover image URL
seo_titleVARCHARSEO meta title
seo_descriptionTEXTSEO meta description
seo_keywordsTEXTComma-separated keywords
publishedBOOLEANVisibility status
publish_dateTIMESTAMPPublication date
created_atTIMESTAMPCreation timestamp
updated_atTIMESTAMPLast update timestamp
Enums:
status: 'active' | 'upcoming' | 'completed' | 'on-hold'
type: 'residential' | 'commercial' | 'mixed-use'
stage: 'pre-selling' | 'selling' | 'sold-out' | 'under-construction'

Project Galleries

Photo galleries for projects.
ColumnTypeDescription
idUUIDPrimary key
project_idUUIDForeign key → projects.id
image_urlVARCHARImage file URL
captionTEXTImage caption
display_orderINTEGERSort order
house_modelVARCHARAssociated model (optional)
created_atTIMESTAMPUpload timestamp

Amenities

Property amenities catalog.
ColumnTypeDescription
idUUIDPrimary key
nameVARCHARAmenity name
descriptionTEXTDescription
iconVARCHARIcon identifier
cover_photoVARCHARCover image URL
categoryVARCHARAmenity category
created_atTIMESTAMPCreation timestamp

Careers

Job postings.
ColumnTypeDescription
idUUIDPrimary key
titleVARCHARJob title
slugVARCHARURL-friendly identifier
departmentENUMDepartment (see Departments)
descriptionTEXTJob description (Markdown)
requirementsTEXTJob requirements (Markdown)
locationVARCHARWork location
employment_typeENUMfull-time, part-time, contract
salary_rangeJSON{ min, max, currency }
publishedBOOLEANVisibility status
publish_dateTIMESTAMPPublication date
created_atTIMESTAMPCreation timestamp
updated_atTIMESTAMPLast update timestamp

Articles

News articles and announcements.
ColumnTypeDescription
idUUIDPrimary key
titleVARCHARArticle title
slugVARCHARURL-friendly identifier
contentTEXTArticle content (Markdown)
excerptTEXTShort summary
typeENUMnews, announcement, blog
cover_imageVARCHARCover image URL
author_idUUIDForeign key → users.id
tagsTEXT[]Array of tags
publishedBOOLEANVisibility status
publish_dateTIMESTAMPPublication date
seo_titleVARCHARSEO meta title
seo_descriptionTEXTSEO meta description
created_atTIMESTAMPCreation timestamp
updated_atTIMESTAMPLast update timestamp

CRM Tables

Leads

Potential customer leads.
ColumnTypeDescription
idUUIDPrimary key
first_nameVARCHARFirst name
last_nameVARCHARLast name
emailVARCHAREmail address
phoneVARCHARPhone number
sourceENUMwebsite, referral, event, social
statusENUMnew, contacted, qualified, converted, lost
interestTEXTAreas of interest
notesTEXTInternal notes
assigned_toUUIDForeign key → users.id
created_atTIMESTAMPLead creation time
updated_atTIMESTAMPLast update time

Reservations

Property unit reservations.
ColumnTypeDescription
idUUIDPrimary key
inventory_idUUIDForeign key → inventory.id
project_nameVARCHARProject reference
client_nameVARCHARClient full name
contact_numberVARCHARClient phone
emailVARCHARClient email
reservation_dateTIMESTAMPReservation timestamp
statusENUMpending, confirmed, cancelled
payment_statusENUMunpaid, partial, paid
notesTEXTAdditional notes
created_byUUIDForeign key → users.id
created_atTIMESTAMPRecord creation time
updated_atTIMESTAMPLast update time

Inventory

Property unit inventory.
ColumnTypeDescription
idUUIDPrimary key
project_idUUIDForeign key → projects.id
inventory_codeVARCHARAuto-generated code (e.g., “AR-B1-L5”)
blockVARCHARBlock number
lotVARCHARLot number
house_modelVARCHARModel type
floor_areaDECIMALSquare meters
lot_areaDECIMALSquare meters
priceDECIMALUnit price
statusENUMavailable, reserved, sold
sold_toUUIDForeign key → reservations.id (nullable)
created_atTIMESTAMPRecord creation time
updated_atTIMESTAMPLast update time
Inventory Code Format: {ProjectInitials}-{Block}-{Lot}
  • Example: “AR-B1-L5” for Arcoe Residence, Block 1, Lot 5

Inquiries

Customer inquiry inbox.
ColumnTypeDescription
idUUIDPrimary key
nameVARCHARInquirer name
emailVARCHAREmail address
phoneVARCHARPhone number
subjectVARCHARInquiry subject
messageTEXTInquiry message
statusENUMunread, read, responded, closed
responded_byUUIDForeign key → users.id
responseTEXTAdmin response
created_atTIMESTAMPInquiry timestamp
updated_atTIMESTAMPLast update time

Newsletters

Newsletter subscriptions.
ColumnTypeDescription
idUUIDPrimary key
emailVARCHARSubscriber email
nameVARCHARSubscriber name (optional)
statusENUMsubscribed, unsubscribed
subscribed_atTIMESTAMPSubscription timestamp
unsubscribed_atTIMESTAMPUnsubscription timestamp

Campaigns

Marketing email campaigns.
ColumnTypeDescription
idUUIDPrimary key
nameVARCHARCampaign name
subjectVARCHAREmail subject
contentTEXTEmail content (Markdown)
recipientsTEXT[]Array of emails or “all”
statusENUMdraft, scheduled, sent
scheduled_atTIMESTAMPSend time (nullable)
sent_atTIMESTAMPActual send time
created_byUUIDForeign key → users.id
created_atTIMESTAMPCreation timestamp
updated_atTIMESTAMPLast update time

DSL Tracker

Document Status List tracking.
ColumnTypeDescription
idUUIDPrimary key
client_nameVARCHARClient name
projectVARCHARProject reference
document_typeVARCHARType of document
statusENUMpending, submitted, approved, rejected
submission_dateTIMESTAMPSubmission timestamp
notesTEXTTracking notes
created_atTIMESTAMPRecord creation time
updated_atTIMESTAMPLast update time

IAM Tables

Users (Better Auth)

User accounts managed by Better Auth.
ColumnTypeDescription
idUUIDPrimary key
emailVARCHAREmail address (unique)
emailVerifiedBOOLEANEmail verification status
nameVARCHARDisplay name
imageVARCHARProfile image URL
department_idUUIDForeign key → departments.id
createdAtTIMESTAMPAccount creation time
updatedAtTIMESTAMPLast update time
Additional Better Auth tables include sessions, accounts, verifications, and twoFactor. See Better Auth documentation for details.

Departments

Company departments for user organization.
ColumnTypeDescription
idUUIDPrimary key
nameVARCHARDepartment name
descriptionTEXTDepartment description
created_atTIMESTAMPCreation timestamp
Standard Departments (based on CHANGELOG):
// Actual departments vary - check db/schema.ts for current enum
departments: 
  | 'Executive'
  | 'Sales'
  | 'Marketing'
  | 'Operations'
  | 'Finance'
  | 'IT'
  | 'HR'
  // ... etc

Module Access

Granular module-level permissions.
ColumnTypeDescription
idUUIDPrimary key
user_idUUIDForeign key → users.id
moduleENUMcms, crm, iam, settings
can_readBOOLEANRead permission
can_writeBOOLEANWrite permission
can_deleteBOOLEANDelete permission
created_atTIMESTAMPCreation timestamp
updated_atTIMESTAMPLast update time

Activity Logs

Audit trail for user actions.
ColumnTypeDescription
idUUIDPrimary key
user_idUUIDForeign key → users.id
actionVARCHARAction type (e.g., “create”, “update”, “delete”)
moduleVARCHARAffected module
resourceVARCHARAffected resource type
resource_idUUIDAffected resource ID
changesJSONBefore/after snapshot
ip_addressVARCHARRequest IP address
user_agentTEXTBrowser user agent
created_atTIMESTAMPAction timestamp
Retention Policy: Logs older than 90 days are automatically deleted via daily cron job.

Relationships

One-to-Many

  • usersactivity_logs: A user creates many activity logs
  • usersmodule_access: A user has many module access permissions
  • projectsproject_galleries: A project has many gallery images
  • projectsinventory: A project contains many units
  • usersarticles: A user authors many articles

Many-to-One

  • inventoryprojects: Many units belong to one project
  • reservationsinventory: Many reservations link to inventory
  • usersdepartments: Many users belong to one department

Optional Relationships

  • inventory.sold_toreservations.id: Inventory linked to reservation (nullable)
  • leads.assigned_tousers.id: Lead assigned to user (nullable)
  • inquiries.responded_byusers.id: Inquiry handled by user (nullable)

Migrations

Managing Schema Changes

  1. Edit schema files: Modify db/schema.ts or db/auth-schema.ts
  2. Generate migration: npx drizzle-kit generate
  3. Review migration: Check generated SQL in drizzle/ directory
  4. Apply migration: npx drizzle-kit migrate

Migration Files

Located in drizzle/ directory with timestamp prefixes:
drizzle/
├── 0000_initial_schema.sql
├── 0001_add_departments.sql
├── 0002_add_module_access.sql
└── ...
Always review generated migrations before applying to production. Drizzle Kit generates SQL based on schema changes, but complex migrations may require manual adjustments.

Indexes

Common indexes for performance often include:
  • Email fields (for lookups)
  • Foreign keys (for joins)
  • Status fields (for filtering)
  • Created/updated timestamps (for sorting)
Check db/schema.ts for actual index definitions.

Next Steps

REST API reference

Explore database operations via API

Drizzle ORM docs

Query API and migration guides