feat: add tenant entity, repository, and database migration
Tenants table with slug, tier (LOW/MID/HIGH/BUSINESS), status (PROVISIONING/ACTIVE/SUSPENDED/DELETED), Logto org reference, and Stripe IDs.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package net.siegeln.cameleer.saas.tenant;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.PrePersist;
|
||||
import jakarta.persistence.PreUpdate;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "tenants")
|
||||
public class TenantEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "name", nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "slug", nullable = false, unique = true, length = 100)
|
||||
private String slug;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "tier", nullable = false, length = 20)
|
||||
private Tier tier = Tier.LOW;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private TenantStatus status = TenantStatus.PROVISIONING;
|
||||
|
||||
@Column(name = "logto_org_id")
|
||||
private String logtoOrgId;
|
||||
|
||||
@Column(name = "stripe_customer_id")
|
||||
private String stripeCustomerId;
|
||||
|
||||
@Column(name = "stripe_subscription_id")
|
||||
private String stripeSubscriptionId;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "settings", columnDefinition = "jsonb")
|
||||
private Map<String, Object> settings = Map.of();
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private Instant updatedAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
Instant now = Instant.now();
|
||||
if (createdAt == null) createdAt = now;
|
||||
if (updatedAt == null) updatedAt = now;
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = Instant.now();
|
||||
}
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getSlug() { return slug; }
|
||||
public void setSlug(String slug) { this.slug = slug; }
|
||||
public Tier getTier() { return tier; }
|
||||
public void setTier(Tier tier) { this.tier = tier; }
|
||||
public TenantStatus getStatus() { return status; }
|
||||
public void setStatus(TenantStatus status) { this.status = status; }
|
||||
public String getLogtoOrgId() { return logtoOrgId; }
|
||||
public void setLogtoOrgId(String logtoOrgId) { this.logtoOrgId = logtoOrgId; }
|
||||
public String getStripeCustomerId() { return stripeCustomerId; }
|
||||
public void setStripeCustomerId(String stripeCustomerId) { this.stripeCustomerId = stripeCustomerId; }
|
||||
public String getStripeSubscriptionId() { return stripeSubscriptionId; }
|
||||
public void setStripeSubscriptionId(String stripeSubscriptionId) { this.stripeSubscriptionId = stripeSubscriptionId; }
|
||||
public Map<String, Object> getSettings() { return settings; }
|
||||
public void setSettings(Map<String, Object> settings) { this.settings = settings; }
|
||||
public Instant getCreatedAt() { return createdAt; }
|
||||
public Instant getUpdatedAt() { return updatedAt; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.siegeln.cameleer.saas.tenant;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface TenantRepository extends JpaRepository<TenantEntity, UUID> {
|
||||
Optional<TenantEntity> findBySlug(String slug);
|
||||
Optional<TenantEntity> findByLogtoOrgId(String logtoOrgId);
|
||||
List<TenantEntity> findByStatus(TenantStatus status);
|
||||
boolean existsBySlug(String slug);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.siegeln.cameleer.saas.tenant;
|
||||
|
||||
public enum TenantStatus {
|
||||
PROVISIONING, ACTIVE, SUSPENDED, DELETED
|
||||
}
|
||||
5
src/main/java/net/siegeln/cameleer/saas/tenant/Tier.java
Normal file
5
src/main/java/net/siegeln/cameleer/saas/tenant/Tier.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package net.siegeln.cameleer.saas.tenant;
|
||||
|
||||
public enum Tier {
|
||||
LOW, MID, HIGH, BUSINESS
|
||||
}
|
||||
17
src/main/resources/db/migration/V005__create_tenants.sql
Normal file
17
src/main/resources/db/migration/V005__create_tenants.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE tenants (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(100) NOT NULL UNIQUE,
|
||||
tier VARCHAR(20) NOT NULL DEFAULT 'LOW',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'PROVISIONING',
|
||||
logto_org_id VARCHAR(255),
|
||||
stripe_customer_id VARCHAR(255),
|
||||
stripe_subscription_id VARCHAR(255),
|
||||
settings JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tenants_slug ON tenants (slug);
|
||||
CREATE INDEX idx_tenants_status ON tenants (status);
|
||||
CREATE INDEX idx_tenants_logto_org_id ON tenants (logto_org_id);
|
||||
Reference in New Issue
Block a user