Remove schema fix classes and document manual schema updates
All checks were successful
build-and-deploy / build-deploy (push) Successful in 36s

This commit is contained in:
androidlover5842
2026-02-01 20:24:43 +05:30
parent fbb06ca709
commit c4b83d2122
16 changed files with 1 additions and 654 deletions

View File

@@ -196,6 +196,7 @@ Notes / constraints
Operational notes
- Payment provider migrated: PayU removed; Razorpay now used for settings, QR, payment links, and webhooks.
- Server access: SSH host alias `hotel` is available for server operations (e.g., `ssh hotel`). Use carefully; DB changes were done via `sudo -u postgres psql` on the server when needed.
- Schema changes: schema fix classes have been removed. If a new column/table is required, apply it manually on the server using `ssh hotel` and `sudo -u postgres psql -d trisolaris`, e.g. `alter table ... add column ...`. Keep a note of the exact SQL applied.
Access / ops notes (prod)
- Service: `TrisolarisServer.service` (systemd). `systemctl cat TrisolarisServer.service`.

View File

@@ -1,70 +0,0 @@
package com.android.trisolarisserver.config.booking
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class BookingSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasExpectedGuestCount = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'booking'
and column_name = 'expected_guest_count'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasExpectedGuestCount == 0) {
logger.info("Adding booking.expected_guest_count column")
jdbcTemplate.execute("alter table booking add column expected_guest_count integer")
}
val hasFromCity = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'booking'
and column_name = 'from_city'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasFromCity == 0) {
logger.info("Adding booking.from_city column")
jdbcTemplate.execute("alter table booking add column from_city varchar")
}
val hasToCity = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'booking'
and column_name = 'to_city'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasToCity == 0) {
logger.info("Adding booking.to_city column")
jdbcTemplate.execute("alter table booking add column to_city varchar")
}
val hasMemberRelation = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'booking'
and column_name = 'member_relation'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasMemberRelation == 0) {
logger.info("Adding booking.member_relation column")
jdbcTemplate.execute("alter table booking add column member_relation varchar")
}
}
}

View File

@@ -1,45 +0,0 @@
package com.android.trisolarisserver.config.card
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class IssuedCardSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val isNullable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'issued_card'
and column_name = 'room_stay_id'
and is_nullable = 'YES'
""".trimIndent(),
Int::class.java
) ?: 0
if (isNullable == 0) {
logger.info("Dropping NOT NULL on issued_card.room_stay_id")
jdbcTemplate.execute("alter table issued_card alter column room_stay_id drop not null")
}
val uniqueIndexExists = jdbcTemplate.queryForObject(
"""
select count(*)
from pg_indexes
where schemaname = 'public'
and tablename = 'issued_card'
and indexname = 'idx_issued_card_property_card_id_unique'
""".trimIndent(),
Int::class.java
) ?: 0
if (uniqueIndexExists > 0) {
logger.info("Dropping unique index on issued_card(property_id, lower(card_id))")
jdbcTemplate.execute("drop index if exists idx_issued_card_property_card_id_unique")
}
}
}

View File

@@ -1,24 +0,0 @@
package com.android.trisolarisserver.config.db
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.slf4j.LoggerFactory
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.jdbc.core.JdbcTemplate
abstract class PostgresSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : ApplicationRunner {
protected val logger = LoggerFactory.getLogger(this::class.java)
override fun run(args: ApplicationArguments) {
val version = jdbcTemplate.queryForObject("select version()", String::class.java) ?: return
if (!version.contains("PostgreSQL", ignoreCase = true)) {
return
}
runPostgres(jdbcTemplate)
}
protected abstract fun runPostgres(jdbcTemplate: JdbcTemplate)
}

View File

@@ -1,42 +0,0 @@
package com.android.trisolarisserver.config.guest
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class GuestDocumentSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'guest_document'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) return
val hasHash = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'guest_document'
and column_name = 'file_hash'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasHash == 0) {
logger.info("Adding file_hash to guest_document table")
jdbcTemplate.execute(
"""
alter table guest_document
add column file_hash varchar
""".trimIndent()
)
}
}
}

View File

@@ -1,38 +0,0 @@
package com.android.trisolarisserver.config.payment
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class PaymentSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
ensureColumn("payment", "gateway_payment_id", "varchar")
ensureColumn("payment", "gateway_txn_id", "varchar")
ensureColumn("payment", "bank_ref_num", "varchar")
ensureColumn("payment", "mode", "varchar")
ensureColumn("payment", "pg_type", "varchar")
ensureColumn("payment", "payer_vpa", "varchar")
ensureColumn("payment", "payer_name", "varchar")
ensureColumn("payment", "payment_source", "varchar")
}
private fun ensureColumn(table: String, column: String, type: String) {
val exists = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = '$table'
and column_name = '$column'
""".trimIndent(),
Int::class.java
) ?: 0
if (exists == 0) {
logger.info("Adding $table.$column column")
jdbcTemplate.execute("alter table $table add column $column $type")
}
}
}

View File

@@ -1,43 +0,0 @@
package com.android.trisolarisserver.config.rate
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RatePlanSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val constraints = jdbcTemplate.query(
"""
select tc.constraint_name,
array_agg(kcu.column_name order by kcu.ordinal_position) as cols
from information_schema.table_constraints tc
join information_schema.key_column_usage kcu
on tc.constraint_name = kcu.constraint_name
and tc.table_schema = kcu.table_schema
where tc.table_name = 'rate_plan'
and tc.constraint_type = 'UNIQUE'
group by tc.constraint_name
""".trimIndent()
) { rs, _ ->
rs.getString("constraint_name") to (rs.getArray("cols").array as Array<*>).map { it.toString() }
}
val oldConstraint = constraints.firstOrNull { it.second == listOf("property_id", "code") }
if (oldConstraint != null) {
logger.info("Dropping old unique constraint on rate_plan(property_id, code)")
jdbcTemplate.execute("alter table rate_plan drop constraint if exists ${oldConstraint.first}")
}
val hasNew = constraints.any { it.second == listOf("property_id", "room_type_id", "code") }
if (!hasNew) {
logger.info("Adding unique constraint on rate_plan(property_id, room_type_id, code)")
jdbcTemplate.execute(
"alter table rate_plan add constraint rate_plan_property_roomtype_code_key unique (property_id, room_type_id, code)"
)
}
}
}

View File

@@ -1,44 +0,0 @@
package com.android.trisolarisserver.config.razorpay
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RazorpayPaymentAttemptSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'razorpay_payment_attempt'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) {
logger.info("Creating razorpay_payment_attempt table")
jdbcTemplate.execute(
"""
create table razorpay_payment_attempt (
id uuid primary key,
property_id uuid not null references property(id) on delete cascade,
booking_id uuid references booking(id) on delete set null,
event varchar,
status varchar,
amount bigint,
currency varchar,
payment_id varchar,
order_id varchar,
payload text,
received_at timestamptz not null
)
""".trimIndent()
)
}
logger.info("Ensuring razorpay_payment_attempt text column sizes")
jdbcTemplate.execute("alter table razorpay_payment_attempt alter column payload type text")
}
}

View File

@@ -1,46 +0,0 @@
package com.android.trisolarisserver.config.razorpay
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RazorpayPaymentLinkRequestSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'razorpay_payment_link_request'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) {
logger.info("Creating razorpay_payment_link_request table")
jdbcTemplate.execute(
"""
create table razorpay_payment_link_request (
id uuid primary key,
property_id uuid not null references property(id) on delete cascade,
booking_id uuid not null references booking(id) on delete cascade,
payment_link_id varchar,
amount bigint not null,
currency varchar not null,
status varchar not null,
short_url text,
request_payload text,
response_payload text,
created_at timestamptz not null
)
""".trimIndent()
)
}
logger.info("Ensuring razorpay_payment_link_request text column sizes")
jdbcTemplate.execute("alter table razorpay_payment_link_request alter column short_url type text")
jdbcTemplate.execute("alter table razorpay_payment_link_request alter column request_payload type text")
jdbcTemplate.execute("alter table razorpay_payment_link_request alter column response_payload type text")
}
}

View File

@@ -1,50 +0,0 @@
package com.android.trisolarisserver.config.razorpay
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RazorpayQrRequestSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'razorpay_qr_request'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) {
logger.info("Creating razorpay_qr_request table")
jdbcTemplate.execute(
"""
create table razorpay_qr_request (
id uuid primary key,
property_id uuid not null references property(id) on delete cascade,
booking_id uuid not null references booking(id) on delete cascade,
qr_id varchar,
amount bigint not null,
currency varchar not null,
status varchar not null,
image_url text,
request_payload text,
response_payload text,
expiry_at timestamptz,
created_at timestamptz not null
)
""".trimIndent()
)
}
logger.info("Ensuring razorpay_qr_request text column sizes")
jdbcTemplate.execute("alter table razorpay_qr_request alter column qr_id type text")
jdbcTemplate.execute("alter table razorpay_qr_request alter column currency type text")
jdbcTemplate.execute("alter table razorpay_qr_request alter column status type text")
jdbcTemplate.execute("alter table razorpay_qr_request alter column image_url type text")
jdbcTemplate.execute("alter table razorpay_qr_request alter column request_payload type text")
jdbcTemplate.execute("alter table razorpay_qr_request alter column response_payload type text")
}
}

View File

@@ -1,48 +0,0 @@
package com.android.trisolarisserver.config.razorpay
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RazorpaySettingsSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'razorpay_settings'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) {
logger.info("Creating razorpay_settings table")
jdbcTemplate.execute(
"""
create table razorpay_settings (
id uuid primary key,
property_id uuid not null unique references property(id) on delete cascade,
key_id varchar not null,
key_secret varchar not null,
webhook_secret varchar,
key_id_test varchar,
key_secret_test varchar,
webhook_secret_test varchar,
is_test boolean not null default false,
updated_at timestamptz not null
)
""".trimIndent()
)
}
logger.info("Ensuring razorpay_settings text column sizes")
jdbcTemplate.execute("alter table razorpay_settings alter column key_id type text")
jdbcTemplate.execute("alter table razorpay_settings alter column key_secret type text")
jdbcTemplate.execute("alter table razorpay_settings alter column webhook_secret type text")
jdbcTemplate.execute("alter table razorpay_settings add column if not exists key_id_test text")
jdbcTemplate.execute("alter table razorpay_settings add column if not exists key_secret_test text")
jdbcTemplate.execute("alter table razorpay_settings add column if not exists webhook_secret_test text")
}
}

View File

@@ -1,41 +0,0 @@
package com.android.trisolarisserver.config.razorpay
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RazorpayWebhookLogSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasTable = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'razorpay_webhook_log'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasTable == 0) {
logger.info("Creating razorpay_webhook_log table")
jdbcTemplate.execute(
"""
create table razorpay_webhook_log (
id uuid primary key,
property_id uuid not null references property(id) on delete cascade,
headers text,
payload text,
content_type varchar,
received_at timestamptz not null
)
""".trimIndent()
)
}
logger.info("Ensuring razorpay_webhook_log text column sizes")
jdbcTemplate.execute("alter table razorpay_webhook_log alter column headers type text")
jdbcTemplate.execute("alter table razorpay_webhook_log alter column payload type text")
jdbcTemplate.execute("alter table razorpay_webhook_log alter column content_type type text")
}
}

View File

@@ -1,28 +0,0 @@
package com.android.trisolarisserver.config.room
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RoomImageSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasContentHash = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'room_image'
and column_name = 'content_hash'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasContentHash == 0) {
logger.info("Adding room_image.content_hash column")
jdbcTemplate.execute("alter table room_image add column content_hash text")
}
}
}

View File

@@ -1,71 +0,0 @@
package com.android.trisolarisserver.config.room
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RoomImageTagSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasOldRoomImageId = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'room_image_tag'
and column_name = 'room_image_id'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasOldRoomImageId > 0) {
logger.info("Dropping legacy room_image_tag table")
jdbcTemplate.execute("drop table if exists room_image_tag cascade")
}
val hasRoomImageTag = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'room_image_tag'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasRoomImageTag == 0) {
logger.info("Creating room_image_tag table")
jdbcTemplate.execute(
"""
create table room_image_tag (
id uuid primary key,
name text not null unique,
created_at timestamptz not null
)
""".trimIndent()
)
}
val hasLink = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.tables
where table_name = 'room_image_tag_link'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasLink == 0) {
logger.info("Creating room_image_tag_link table")
jdbcTemplate.execute(
"""
create table room_image_tag_link (
room_image_id uuid not null,
tag_id uuid not null
)
""".trimIndent()
)
}
}
}

View File

@@ -1,36 +0,0 @@
package com.android.trisolarisserver.config.room
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RoomStaySchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val exists = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.table_constraints
where table_name = 'room_stay'
and constraint_name = 'room_stay_rate_source_check'
""".trimIndent(),
Int::class.java
) ?: 0
if (exists > 0) {
logger.info("Updating room_stay_rate_source_check constraint")
jdbcTemplate.execute("alter table room_stay drop constraint room_stay_rate_source_check")
}
jdbcTemplate.execute(
"""
alter table room_stay
add constraint room_stay_rate_source_check
check (rate_source in ('MANUAL','PRESET','RATE_PLAN','NEGOTIATED','OTA'))
""".trimIndent()
)
}
}

View File

@@ -1,28 +0,0 @@
package com.android.trisolarisserver.config.room
import com.android.trisolarisserver.config.db.PostgresSchemaFix
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class RoomTypeSchemaFix(
private val jdbcTemplate: JdbcTemplate
) : PostgresSchemaFix(jdbcTemplate) {
override fun runPostgres(jdbcTemplate: JdbcTemplate) {
val hasActive = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'room_type'
and column_name = 'is_active'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasActive == 0) {
logger.info("Adding room_type.is_active column")
jdbcTemplate.execute("alter table room_type add column is_active boolean not null default true")
}
}
}