🧙♂️ Transform LifeRPG into The Wizard's Grimoire - Production-Ready Application
✨ Major Features Added: - Complete magical theming and rebranding from LifeRPG to The Wizard's Grimoire - Production-grade React frontend with Tailwind CSS v4 and magical aesthetics - Comprehensive analytics dashboard with Recharts integration (ScryingPortal) - Push notifications system with PWA service worker support - Drag & drop functionality using @dnd-kit for habit reordering - Social features with friends system and leaderboards - Performance optimization tools and monitoring - Mobile app enhancement with PWA installation support 🏗️ Technical Infrastructure: - Advanced service worker with offline support and background sync - Zustand state management for scalable application state - Production-ready UI component system with enhanced Button, Card, Input - Progressive Web App (PWA) with manifest and app installation - FastAPI backend with comprehensive API endpoints - Docker containerization and CI/CD pipeline setup 📱 Progressive Web App Features: - Offline functionality with intelligent caching - Push notification support for habit reminders - App installation on mobile and desktop platforms - Background sync for offline data management - Performance monitoring and optimization tools 🎨 User Experience: - Magical wizard/grimoire theming throughout application - Responsive design optimized for all device sizes - Drag & drop habit management with smooth animations - Interactive analytics with multiple chart types - Social connectivity with friends and competitive features - Comprehensive notification and performance settings 🔧 Developer Experience: - Modern development stack with Vite and React - Comprehensive testing setup and CI/CD pipelines - Code quality tools with pre-commit hooks - Docker development environment - Detailed documentation and implementation guides This represents a complete transformation from prototype to production-ready application with enterprise-grade features and magical user experience.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
from sqlalchemy import (
|
||||
Column, Integer, String, Text, DateTime, ForeignKey, create_engine, func
|
||||
Column, Integer, String, Text, DateTime, ForeignKey, create_engine, func, UniqueConstraint
|
||||
)
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import declarative_base
|
||||
from sqlalchemy.orm import relationship, sessionmaker
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
Base = declarative_base()
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./modern_dev.db")
|
||||
@@ -17,6 +18,9 @@ class User(Base):
|
||||
password_hash = Column(String)
|
||||
role = Column(String, default='user')
|
||||
display_name = Column(String)
|
||||
totp_secret = Column(String) # base32 secret (encrypted at rest optional)
|
||||
totp_enabled = Column(Integer, default=0) # 0/1
|
||||
recovery_codes = Column(Text) # newline-separated bcrypt hashes
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
updated_at = Column(DateTime, server_default=func.current_timestamp(), onupdate=func.current_timestamp())
|
||||
|
||||
@@ -54,6 +58,9 @@ class Habit(Base):
|
||||
cadence = Column(String)
|
||||
difficulty = Column(Integer, default=1)
|
||||
xp_reward = Column(Integer, default=10)
|
||||
status = Column(String, default='active') # active|completed|archived
|
||||
due_date = Column(DateTime)
|
||||
labels = Column(Text) # JSON list of labels
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
|
||||
user = relationship("User", back_populates="habits")
|
||||
@@ -120,6 +127,51 @@ class GuildMember(Base):
|
||||
role = Column(String, default='member')
|
||||
|
||||
|
||||
class TelemetryEvent(Base):
|
||||
__tablename__ = 'telemetry_events'
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer)
|
||||
name = Column(String, nullable=False)
|
||||
payload = Column(Text)
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class IntegrationItemMap(Base):
|
||||
__tablename__ = 'integration_item_map'
|
||||
id = Column(Integer, primary_key=True)
|
||||
integration_id = Column(Integer, ForeignKey('integrations.id'), nullable=False)
|
||||
external_id = Column(String, nullable=False)
|
||||
entity_type = Column(String, nullable=False)
|
||||
entity_id = Column(Integer, nullable=False)
|
||||
updated_at = Column(DateTime, server_default=func.current_timestamp(), onupdate=func.current_timestamp())
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
__table_args__ = (
|
||||
UniqueConstraint('integration_id', 'external_id', 'entity_type', name='uq_integration_item'),
|
||||
)
|
||||
|
||||
|
||||
class PublicToken(Base):
|
||||
__tablename__ = 'public_tokens'
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
name = Column(String, nullable=False)
|
||||
scope = Column(String, default='read:widgets')
|
||||
token_hash = Column(String, unique=True, nullable=False)
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
last_used_at = Column(DateTime)
|
||||
|
||||
|
||||
class OIDCLoginState(Base):
|
||||
__tablename__ = 'oidc_login_state'
|
||||
id = Column(Integer, primary_key=True)
|
||||
state = Column(String, unique=True, nullable=False)
|
||||
provider = Column(String, nullable=False)
|
||||
code_verifier = Column(String, nullable=False)
|
||||
redirect_to = Column(String)
|
||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
||||
expires_at = Column(DateTime)
|
||||
|
||||
|
||||
def init_db():
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user