Add Next.js admin panel and implement background worker jobs

- Add full Next.js admin panel with:
  - User, residence, task, contractor, document management
  - Notifications and notification preferences management
  - Subscriptions and auth token management
  - Dashboard with stats
  - Lookup tables management (categories, priorities, statuses, etc.)
  - Admin user management

- Implement background worker job handlers:
  - HandleTaskReminder: sends push notifications for tasks due within 24h
  - HandleOverdueReminder: sends push notifications for overdue tasks
  - HandleDailyDigest: sends daily summary of pending tasks
  - HandleSendEmail: processes email sending jobs
  - HandleSendPush: processes push notification jobs

- Make worker job schedules configurable via environment variables:
  - TASK_REMINDER_HOUR, TASK_REMINDER_MINUTE (default: 20:00 UTC)
  - OVERDUE_REMINDER_HOUR (default: 09:00 UTC)
  - DAILY_DIGEST_HOUR (default: 11:00 UTC)

🤖 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-27 23:35:00 -06:00
parent eed5c21586
commit 2817deee3c
129 changed files with 26838 additions and 693 deletions

View File

@@ -20,6 +20,7 @@ type Config struct {
Push PushConfig
Worker WorkerConfig
Security SecurityConfig
Storage StorageConfig
}
type ServerConfig struct {
@@ -87,6 +88,14 @@ type SecurityConfig struct {
MaxPasswordResetRate int // per hour
}
// StorageConfig holds file storage settings
type StorageConfig struct {
UploadDir string // Directory to store uploaded files
BaseURL string // Public URL prefix for serving files (e.g., "/uploads")
MaxFileSize int64 // Max file size in bytes (default 10MB)
AllowedTypes string // Comma-separated MIME types
}
var cfg *Config
// Load reads configuration from environment variables
@@ -157,10 +166,10 @@ func Load() (*Config, error) {
FCMServerKey: viper.GetString("FCM_SERVER_KEY"),
},
Worker: WorkerConfig{
TaskReminderHour: viper.GetInt("CELERY_BEAT_REMINDER_HOUR"),
TaskReminderMinute: viper.GetInt("CELERY_BEAT_REMINDER_MINUTE"),
OverdueReminderHour: 9, // 9:00 AM UTC
DailyNotifHour: 11, // 11:00 AM UTC
TaskReminderHour: viper.GetInt("TASK_REMINDER_HOUR"),
TaskReminderMinute: viper.GetInt("TASK_REMINDER_MINUTE"),
OverdueReminderHour: viper.GetInt("OVERDUE_REMINDER_HOUR"),
DailyNotifHour: viper.GetInt("DAILY_DIGEST_HOUR"),
},
Security: SecurityConfig{
SecretKey: viper.GetString("SECRET_KEY"),
@@ -169,6 +178,12 @@ func Load() (*Config, error) {
ConfirmationExpiry: 24 * time.Hour,
MaxPasswordResetRate: 3,
},
Storage: StorageConfig{
UploadDir: viper.GetString("STORAGE_UPLOAD_DIR"),
BaseURL: viper.GetString("STORAGE_BASE_URL"),
MaxFileSize: viper.GetInt64("STORAGE_MAX_FILE_SIZE"),
AllowedTypes: viper.GetString("STORAGE_ALLOWED_TYPES"),
},
}
// Validate required fields
@@ -218,9 +233,17 @@ func setDefaults() {
viper.SetDefault("APNS_TOPIC", "com.example.mycrib")
viper.SetDefault("APNS_USE_SANDBOX", true)
// Worker defaults
viper.SetDefault("CELERY_BEAT_REMINDER_HOUR", 20)
viper.SetDefault("CELERY_BEAT_REMINDER_MINUTE", 0)
// Worker defaults (all times in UTC)
viper.SetDefault("TASK_REMINDER_HOUR", 20) // 8:00 PM UTC
viper.SetDefault("TASK_REMINDER_MINUTE", 0)
viper.SetDefault("OVERDUE_REMINDER_HOUR", 9) // 9:00 AM UTC
viper.SetDefault("DAILY_DIGEST_HOUR", 11) // 11:00 AM UTC
// Storage defaults
viper.SetDefault("STORAGE_UPLOAD_DIR", "./uploads")
viper.SetDefault("STORAGE_BASE_URL", "/uploads")
viper.SetDefault("STORAGE_MAX_FILE_SIZE", 10*1024*1024) // 10MB
viper.SetDefault("STORAGE_ALLOWED_TYPES", "image/jpeg,image/png,image/gif,image/webp,application/pdf")
}
func validate(cfg *Config) error {