Initial commit: MyCrib API in Go

Complete rewrite of Django REST API to Go with:
- Gin web framework for HTTP routing
- GORM for database operations
- GoAdmin for admin panel
- Gorush integration for push notifications
- Redis for caching and job queues

Features implemented:
- User authentication (login, register, logout, password reset)
- Residence management (CRUD, sharing, share codes)
- Task management (CRUD, kanban board, completions)
- Contractor management (CRUD, specialties)
- Document management (CRUD, warranties)
- Notifications (preferences, push notifications)
- Subscription management (tiers, limits)

Infrastructure:
- Docker Compose for local development
- Database migrations and seed data
- Admin panel for data management

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-26 20:07:16 -06:00
commit 1f12f3f62a
78 changed files with 13821 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
package models
import (
"time"
)
// SubscriptionTier represents the subscription tier
type SubscriptionTier string
const (
TierFree SubscriptionTier = "free"
TierPro SubscriptionTier = "pro"
)
// SubscriptionSettings represents the subscription_subscriptionsettings table (singleton)
type SubscriptionSettings struct {
ID uint `gorm:"primaryKey" json:"id"`
EnableLimitations bool `gorm:"column:enable_limitations;default:false" json:"enable_limitations"`
}
// TableName returns the table name for GORM
func (SubscriptionSettings) TableName() string {
return "subscription_subscriptionsettings"
}
// UserSubscription represents the subscription_usersubscription table
type UserSubscription struct {
BaseModel
UserID uint `gorm:"column:user_id;uniqueIndex;not null" json:"user_id"`
Tier SubscriptionTier `gorm:"column:tier;size:10;default:'free'" json:"tier"`
// In-App Purchase data
AppleReceiptData *string `gorm:"column:apple_receipt_data;type:text" json:"-"`
GooglePurchaseToken *string `gorm:"column:google_purchase_token;type:text" json:"-"`
// Subscription dates
SubscribedAt *time.Time `gorm:"column:subscribed_at" json:"subscribed_at"`
ExpiresAt *time.Time `gorm:"column:expires_at" json:"expires_at"`
AutoRenew bool `gorm:"column:auto_renew;default:true" json:"auto_renew"`
// Tracking
CancelledAt *time.Time `gorm:"column:cancelled_at" json:"cancelled_at"`
Platform string `gorm:"column:platform;size:10" json:"platform"` // ios, android
}
// TableName returns the table name for GORM
func (UserSubscription) TableName() string {
return "subscription_usersubscription"
}
// IsActive returns true if the subscription is active (pro tier and not expired)
func (s *UserSubscription) IsActive() bool {
if s.Tier != TierPro {
return false
}
if s.ExpiresAt != nil && time.Now().UTC().After(*s.ExpiresAt) {
return false
}
return true
}
// IsPro returns true if the user has a pro subscription
func (s *UserSubscription) IsPro() bool {
return s.Tier == TierPro && s.IsActive()
}
// UpgradeTrigger represents the subscription_upgradetrigger table
type UpgradeTrigger struct {
BaseModel
TriggerKey string `gorm:"column:trigger_key;uniqueIndex;size:50;not null" json:"trigger_key"`
Title string `gorm:"column:title;size:200;not null" json:"title"`
Message string `gorm:"column:message;type:text;not null" json:"message"`
PromoHTML string `gorm:"column:promo_html;type:text" json:"promo_html"`
ButtonText string `gorm:"column:button_text;size:50;default:'Upgrade to Pro'" json:"button_text"`
IsActive bool `gorm:"column:is_active;default:true" json:"is_active"`
}
// TableName returns the table name for GORM
func (UpgradeTrigger) TableName() string {
return "subscription_upgradetrigger"
}
// FeatureBenefit represents the subscription_featurebenefit table
type FeatureBenefit struct {
BaseModel
FeatureName string `gorm:"column:feature_name;size:200;not null" json:"feature_name"`
FreeTierText string `gorm:"column:free_tier_text;size:200;not null" json:"free_tier_text"`
ProTierText string `gorm:"column:pro_tier_text;size:200;not null" json:"pro_tier_text"`
DisplayOrder int `gorm:"column:display_order;default:0" json:"display_order"`
IsActive bool `gorm:"column:is_active;default:true" json:"is_active"`
}
// TableName returns the table name for GORM
func (FeatureBenefit) TableName() string {
return "subscription_featurebenefit"
}
// Promotion represents the subscription_promotion table
type Promotion struct {
BaseModel
PromotionID string `gorm:"column:promotion_id;uniqueIndex;size:50;not null" json:"promotion_id"`
Title string `gorm:"column:title;size:200;not null" json:"title"`
Message string `gorm:"column:message;type:text;not null" json:"message"`
Link *string `gorm:"column:link;size:200" json:"link"`
StartDate time.Time `gorm:"column:start_date;not null" json:"start_date"`
EndDate time.Time `gorm:"column:end_date;not null" json:"end_date"`
TargetTier SubscriptionTier `gorm:"column:target_tier;size:10;default:'free'" json:"target_tier"`
IsActive bool `gorm:"column:is_active;default:true" json:"is_active"`
}
// TableName returns the table name for GORM
func (Promotion) TableName() string {
return "subscription_promotion"
}
// IsCurrentlyActive returns true if the promotion is currently active
func (p *Promotion) IsCurrentlyActive() bool {
if !p.IsActive {
return false
}
now := time.Now().UTC()
return now.After(p.StartDate) && now.Before(p.EndDate)
}
// TierLimits represents the subscription_tierlimits table
type TierLimits struct {
BaseModel
Tier SubscriptionTier `gorm:"column:tier;uniqueIndex;size:10;not null" json:"tier"`
PropertiesLimit *int `gorm:"column:properties_limit" json:"properties_limit"`
TasksLimit *int `gorm:"column:tasks_limit" json:"tasks_limit"`
ContractorsLimit *int `gorm:"column:contractors_limit" json:"contractors_limit"`
DocumentsLimit *int `gorm:"column:documents_limit" json:"documents_limit"`
}
// TableName returns the table name for GORM
func (TierLimits) TableName() string {
return "subscription_tierlimits"
}
// GetDefaultFreeLimits returns the default limits for the free tier
func GetDefaultFreeLimits() TierLimits {
one := 1
ten := 10
zero := 0
return TierLimits{
Tier: TierFree,
PropertiesLimit: &one,
TasksLimit: &ten,
ContractorsLimit: &zero,
DocumentsLimit: &zero,
}
}
// GetDefaultProLimits returns the default limits for the pro tier (unlimited)
func GetDefaultProLimits() TierLimits {
return TierLimits{
Tier: TierPro,
PropertiesLimit: nil, // nil = unlimited
TasksLimit: nil,
ContractorsLimit: nil,
DocumentsLimit: nil,
}
}