GitHub Action commited on
Commit
be94759
·
1 Parent(s): c6b12ce

Despliegue limpio sin archivos pesados

Browse files
.env.example ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ==========================================
2
+ # MELODIX - Variables de Entorno
3
+ # ==========================================
4
+ # Copia este archivo a .env y ajusta los valores
5
+
6
+ # --- BASE DE DATOS ---
7
+ # PostgreSQL (producción):
8
+ # DATABASE_URL=postgresql://usuario:password@localhost:5432/melodix_db
9
+ # SQLite (desarrollo - dejar comentado para usar SQLite por defecto)
10
+ # DATABASE_URL=
11
+
12
+ # --- SEGURIDAD ---
13
+ # Clave secreta para JWT (cambiar en producción)
14
+ SECRET_KEY=tu_clave_secreta_muy_segura_cambia_esto_en_produccion_2024
15
+ ALGORITHM=HS256
16
+ ACCESS_TOKEN_EXPIRE_MINUTES=43200
17
+
18
+ # --- SUPABASE ---
19
+ SUPABASE_JWT_SECRET=tu_supabase_jwt_secret_aqui
20
+
21
+ # Contraseña por defecto para el usuario administrador inicial (isaacsalgado105@gmail.com)
22
+ DEFAULT_ADMIN_PASSWORD=Dis147258369
23
+
24
+ # --- REDIS (Celery) ---
25
+ # Redis local (desarrollo)
26
+ REDIS_URL=redis://localhost:6379/0
27
+ # Redis con contraseña (producción)
28
+ # REDIS_URL=redis://:tu_password_redis@localhost:6379/0
29
+
30
+
31
+ # --- BACKBLAZE B2 (almacenamiento de stems Premium/Grupos) ---
32
+ # Crear bucket privado en https://secure.backblaze.com/b2_buckets.htm
33
+ # Crear Application Key en https://secure.backblaze.com/app_keys.htm
34
+ B2_KEY_ID=tu_key_id_aqui
35
+ B2_APPLICATION_KEY=tu_application_key_aqui
36
+ B2_ENDPOINT=https://s3.us-east-005.backblazeb2.com
37
+ B2_BUCKET_NAME=melodix-stems
38
+
39
+ # --- DIRECTORIOS ---
40
+ BASE_DIR=C:\mfmm
41
+ PROCESSED_DIR=C:\mfmm\processed
42
+ UPLOADS_DIR=C:\mfmm\uploads
43
+
44
+ # --- DEMUCS ---
45
+ # Modelo por defecto: htdemucs, mdx_extra, htdemucs_6s
46
+ DEFAULT_MODEL=htdemucs
47
+ # Dispositivo: cuda, cpu
48
+ DEFAULT_DEVICE=cuda
49
+
50
+ # --- LIMITES DE ARCHIVOS ---
51
+ # Tamaño máximo de archivo en MB
52
+ MAX_FILE_SIZE_MB=100
53
+ # Extensiones permitidas
54
+ ALLOWED_EXTENSIONS=mp3,wav,flac,m4a,aac,ogg
55
+
56
+ # --- CORS ---
57
+ # Orígenes permitidos (separados por coma)
58
+ ALLOWED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
59
+
60
+ # --- AWS COMPATIBILIDAD CON TEBI ---
61
+ # AWS_REQUEST_CHECKSUM_CALCULATION=when_required
62
+ # AWS_RESPONSE_CHECKSUM_VALIDATION=when_required
.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CAMBIOS_REALIZADOS.md CHANGED
@@ -271,3 +271,17 @@ Si encuentras errores:
271
  ---
272
 
273
  **¡Todo está listo para usar Melodix v2.0! 🎵**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  ---
272
 
273
  **¡Todo está listo para usar Melodix v2.0! 🎵**
274
+
275
+ ---
276
+
277
+ ## 📱 Sincronización y Caché Offline en Melodix Mobile (v2.1)
278
+
279
+ | Archivo | Cambio |
280
+ |---------|--------|
281
+ | `MelodixMobile/src/services/api.js` | Implementación de fallback en caché offline (búsqueda por prefijo si la clave exacta de parámetros falla) y soporte de peticiones silenciadas para evitar alertas molestas de conexión. |
282
+ | `MelodixMobile/src/screens/iglesia/FinanzasScreen.js` | Carga de caché usando los parámetros dinámicos de fechas del mes y actualizaciones silenciosas. |
283
+ | `MelodixMobile/src/screens/iglesia/InventarioScreen.js` | Carga de caché admitiendo listas vacías sin bloquear la interfaz y refresco automático silenciado. |
284
+ | `MelodixMobile/src/screens/iglesia/MomentosScreen.js` | Soporte de caché en momentos y miembros sin validaciones restrictivas de longitud, y refresco silencioso. |
285
+ | `MelodixMobile/src/components/OfflineSyncBanner.js` | Registro global del callback de conflictos de asistencia offline para alertar en cualquier pantalla. |
286
+ | `MelodixMobile/src/screens/iglesia/TomarAsistenciaScreen.js` | Remoción del callback de conflicto local para evitar race conditions al desmontar. |
287
+ | `MelodixMobile/src/navigation/AppNavigator.js` | Remoción del chequeo de torneos en el montaje inicial, evitando redirección no deseada al Quiz en Expo. |
app/models/aprendizaje.py DELETED
@@ -1,110 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Text, Float
2
- from sqlalchemy.orm import relationship
3
- from datetime import datetime
4
- from app.database import Base
5
- from app.models.user import User
6
- from app.models.iglesia import Iglesia
7
-
8
- class BibliaLibro(Base):
9
- __tablename__ = "biblia_libros"
10
- id = Column(Integer, primary_key=True, index=True)
11
- nombre = Column(String, index=True)
12
- testamento = Column(String) # "Antiguo" o "Nuevo"
13
-
14
- class BibliaVersiculo(Base):
15
- __tablename__ = "biblia_versiculos"
16
- id = Column(Integer, primary_key=True, index=True)
17
- libro_id = Column(Integer, ForeignKey("biblia_libros.id"))
18
- capitulo = Column(Integer, index=True)
19
- versiculo = Column(Integer, index=True)
20
- texto = Column(Text)
21
-
22
- libro = relationship("BibliaLibro")
23
-
24
- class PlanLectura(Base):
25
- __tablename__ = "planes_lectura"
26
- id = Column(Integer, primary_key=True, index=True)
27
- nombre = Column(String)
28
- descripcion = Column(Text)
29
- dias_totales = Column(Integer)
30
- created_at = Column(DateTime, default=datetime.utcnow)
31
-
32
- class DiaLectura(Base):
33
- __tablename__ = "dias_lectura"
34
- id = Column(Integer, primary_key=True, index=True)
35
- plan_id = Column(Integer, ForeignKey("planes_lectura.id"))
36
- dia_numero = Column(Integer)
37
- pasajes = Column(String) # "Génesis 1-3"
38
- titulo = Column(String, nullable=True)
39
-
40
- plan = relationship("PlanLectura")
41
-
42
- class PreguntaQuiz(Base):
43
- __tablename__ = "preguntas_quiz"
44
- id = Column(Integer, primary_key=True, index=True)
45
- dia_lectura_id = Column(Integer, ForeignKey("dias_lectura.id"))
46
- tipo = Column(String) # multiple, verdadero_falso, unir, manual
47
- pregunta = Column(String)
48
- opciones = Column(Text) # JSON string
49
- respuesta_correcta = Column(String)
50
-
51
- dia_lectura = relationship("DiaLectura")
52
-
53
- class ProgresoPlan(Base):
54
- __tablename__ = "progresos_plan"
55
- id = Column(Integer, primary_key=True, index=True)
56
- user_id = Column(Integer, ForeignKey("users.id"))
57
- plan_id = Column(Integer, ForeignKey("planes_lectura.id"))
58
- iglesia_id = Column(Integer, ForeignKey("iglesias.id", ondelete="CASCADE"), nullable=True)
59
- dia_actual = Column(Integer, default=1)
60
- completado = Column(Boolean, default=False)
61
- ultima_lectura_fecha = Column(String, nullable=True) # "YYYY-MM-DD"
62
- racha_actual = Column(Integer, default=0)
63
- repaso_completado_hasta = Column(Integer, default=0)
64
- escudos_racha = Column(Integer, default=0)
65
-
66
- user = relationship("User")
67
- plan = relationship("PlanLectura")
68
- iglesia = relationship("Iglesia")
69
-
70
- class PuntuacionLiga(Base):
71
- __tablename__ = "puntuaciones_liga"
72
- id = Column(Integer, primary_key=True, index=True)
73
- user_id = Column(Integer, ForeignKey("users.id"))
74
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
75
- puntos_totales = Column(Integer, default=0)
76
- maxima_racha = Column(Integer, default=0)
77
-
78
- user = relationship("User")
79
- iglesia = relationship("Iglesia")
80
-
81
- class Torneo(Base):
82
- __tablename__ = "torneos"
83
- id = Column(Integer, primary_key=True, index=True)
84
- codigo = Column(String, unique=True, index=True) # e.g. "BIB-7A2F"
85
- nombre = Column(String)
86
- creador_id = Column(Integer, ForeignKey("users.id"))
87
- estado = Column(String, default="activo") # "activo", "desempate", "terminado"
88
- ganador_id = Column(Integer, ForeignKey("users.id"), nullable=True)
89
- preguntas_json = Column(Text) # JSON list of 5 question IDs
90
- desempate_preguntas_json = Column(Text, nullable=True)
91
- fecha_creacion = Column(String)
92
- primero_termino_en = Column(String, nullable=True)
93
-
94
- creador = relationship("User", foreign_keys=[creador_id])
95
- ganador = relationship("User", foreign_keys=[ganador_id])
96
-
97
- class ParticipanteTorneo(Base):
98
- __tablename__ = "participantes_torneo"
99
- id = Column(Integer, primary_key=True, index=True)
100
- torneo_id = Column(Integer, ForeignKey("torneos.id"))
101
- user_id = Column(Integer, ForeignKey("users.id"))
102
- score = Column(Integer, default=0)
103
- tiempo_empleado = Column(Float, default=0.0) # seconds taken
104
- score_desempate = Column(Integer, default=0)
105
- tiempo_desempate = Column(Float, default=0.0)
106
- eliminado = Column(Boolean, default=False)
107
- estado = Column(String, default="pendiente") # "pendiente", "jugado", "desempate_pendiente", "desempate_jugado"
108
-
109
- user = relationship("User")
110
- torneo = relationship("Torneo")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/iglesia.py DELETED
@@ -1,218 +0,0 @@
1
- # ==========================================
2
- # MELODIX - Modelos de Iglesia
3
- # ==========================================
4
-
5
- from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Float, Text
6
- from sqlalchemy.orm import relationship
7
- from datetime import datetime
8
- from app.database import Base
9
-
10
-
11
- class Iglesia(Base):
12
- __tablename__ = "iglesias"
13
-
14
- id = Column(Integer, primary_key=True, index=True)
15
- nombre = Column(String, index=True)
16
- pastor = Column(String)
17
- codigo = Column(String(5), unique=True, index=True) # Código único de 5 dígitos
18
- admin_id = Column(Integer, ForeignKey("users.id"))
19
- icono = Column(String, nullable=True)
20
- foto_base64 = Column(Text, nullable=True)
21
- foto_pastor = Column(String, nullable=True)
22
- imgbb_api_key = Column(String(100), nullable=True)
23
- requiere_aprobacion = Column(Boolean, default=False)
24
- created_at = Column(DateTime, default=datetime.utcnow)
25
-
26
- admin = relationship("User")
27
- miembros_app = relationship("IglesiaMember", back_populates="iglesia")
28
- miembros = relationship("Miembro", back_populates="iglesia")
29
- calendarios = relationship("Calendario", back_populates="iglesia")
30
- finanzas = relationship("Finanza", back_populates="iglesia")
31
- momentos = relationship("Momento", back_populates="iglesia")
32
- inventario = relationship("Inventario", back_populates="iglesia")
33
-
34
-
35
- class IglesiaRol(Base):
36
- """Roles personalizados y granulares de la iglesia (RBAC)"""
37
- __tablename__ = "iglesia_roles"
38
-
39
- id = Column(Integer, primary_key=True, index=True)
40
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
41
- nombre = Column(String) # Administrador, Tesorero, Lider, Miembro
42
- descripcion = Column(String, nullable=True)
43
- permisos = Column(Text) # JSON string con permisos granulares (CRUD por modulo)
44
- is_system = Column(Boolean, default=False) # Para roles fijos que no se pueden borrar
45
-
46
- iglesia = relationship("Iglesia")
47
-
48
-
49
- class IglesiaMember(Base):
50
- """Usuarios de la app que pertenecen a esta iglesia"""
51
- __tablename__ = "iglesia_members"
52
-
53
- id = Column(Integer, primary_key=True, index=True)
54
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
55
- user_id = Column(Integer, ForeignKey("users.id"))
56
- rol = Column(String, default="miembro") # Mantenido por retrocompatibilidad temporal
57
- rol_id = Column(Integer, ForeignKey("iglesia_roles.id"), nullable=True)
58
- estado = Column(String, default="activo") # activo, pendiente, expulsado
59
- joined_at = Column(DateTime, default=datetime.utcnow)
60
-
61
- iglesia = relationship("Iglesia", back_populates="miembros_app")
62
- user = relationship("User")
63
- rol_obj = relationship("IglesiaRol")
64
-
65
-
66
- class Miembro(Base):
67
- """Personas registradas en la iglesia (no necesariamente usuarios de la app)"""
68
- __tablename__ = "miembros"
69
-
70
- id = Column(Integer, primary_key=True, index=True)
71
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
72
- nombre_completo = Column(String, index=True)
73
- tipo = Column(String) # Caballero, Dama, Señorita, Joven, Niño, Niña
74
- edad = Column(Integer, nullable=True)
75
- fecha_nacimiento = Column(String, nullable=True) # Guardado como string "YYYY-MM-DD"
76
- documento_identidad = Column(String, nullable=True)
77
- foto_base64 = Column(Text, nullable=True) # Foto en Base64 reducida
78
- activo = Column(Boolean, default=True)
79
- telefono = Column(String, nullable=True)
80
- direccion = Column(String, nullable=True)
81
- estado = Column(String, default="Activo") # Activo, Visita
82
- ministerio = Column(String, default="Miembro")
83
- user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
84
- created_at = Column(DateTime, default=datetime.utcnow)
85
-
86
- iglesia = relationship("Iglesia", back_populates="miembros")
87
- user = relationship("User")
88
- asistencias = relationship("Asistencia", back_populates="miembro")
89
- momentos = relationship("Momento", back_populates="miembro")
90
- relaciones = relationship("RelacionFamiliar", foreign_keys="[RelacionFamiliar.miembro_id]")
91
-
92
-
93
- class RelacionFamiliar(Base):
94
- __tablename__ = "relaciones_familiares"
95
-
96
- id = Column(Integer, primary_key=True, index=True)
97
- miembro_id = Column(Integer, ForeignKey("miembros.id"))
98
- pariente_id = Column(Integer, ForeignKey("miembros.id"))
99
- tipo_relacion = Column(String) # Padre, Hijo, Esposo, Esposa, etc.
100
-
101
- miembro = relationship("Miembro", foreign_keys=[miembro_id])
102
- pariente = relationship("Miembro", foreign_keys=[pariente_id])
103
-
104
-
105
- class Calendario(Base):
106
- __tablename__ = "calendarios"
107
-
108
- id = Column(Integer, primary_key=True, index=True)
109
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
110
- nombre = Column(String) # "Culto Dominical", "Limpieza", etc.
111
- icono = Column(String, default="calendar")
112
- color_fondo = Column(String, default="#CE93D8")
113
- created_by = Column(Integer, ForeignKey("users.id"))
114
- created_at = Column(DateTime, default=datetime.utcnow)
115
-
116
- iglesia = relationship("Iglesia", back_populates="calendarios")
117
- creator = relationship("User")
118
- servicios = relationship("Servicio", back_populates="calendario")
119
-
120
-
121
- class Servicio(Base):
122
- """Un día específico de servicio dentro de un calendario"""
123
- __tablename__ = "servicios"
124
-
125
- id = Column(Integer, primary_key=True, index=True)
126
- calendario_id = Column(Integer, ForeignKey("calendarios.id"))
127
- nombre = Column(String, nullable=True) # Nombre del servicio/evento
128
- fecha = Column(String) # "YYYY-MM-DD"
129
- descripcion = Column(String, nullable=True)
130
- hora = Column(String, nullable=True)
131
- color_fondo = Column(String, nullable=True)
132
- created_at = Column(DateTime, default=datetime.utcnow)
133
-
134
- calendario = relationship("Calendario", back_populates="servicios")
135
- asistencias = relationship("Asistencia", back_populates="servicio")
136
-
137
-
138
- class Asistencia(Base):
139
- __tablename__ = "asistencias"
140
-
141
- id = Column(Integer, primary_key=True, index=True)
142
- servicio_id = Column(Integer, ForeignKey("servicios.id"))
143
- miembro_id = Column(Integer, ForeignKey("miembros.id"))
144
- asistio = Column(Boolean, default=False)
145
- registrado_por = Column(Integer, ForeignKey("users.id"))
146
- created_at = Column(DateTime, default=datetime.utcnow)
147
-
148
- servicio = relationship("Servicio", back_populates="asistencias")
149
- miembro = relationship("Miembro", back_populates="asistencias")
150
- registrador = relationship("User")
151
-
152
-
153
- class Finanza(Base):
154
- __tablename__ = "finanzas"
155
-
156
- id = Column(Integer, primary_key=True, index=True)
157
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
158
- tipo = Column(String) # "entrada" | "salida"
159
- monto = Column(Float)
160
- concepto = Column(String)
161
- responsable = Column(String) # Nombre libre de quien realizó el movimiento
162
- registrado_por = Column(Integer, ForeignKey("users.id")) # Usuario de la app
163
- fecha = Column(DateTime, default=datetime.utcnow)
164
- reference_uuid = Column(String, unique=True, nullable=True, index=True)
165
-
166
- iglesia = relationship("Iglesia", back_populates="finanzas")
167
- registrador = relationship("User")
168
-
169
-
170
- class Momento(Base):
171
- """Momentos espirituales importantes: bautizos, reconciliaciones, etc."""
172
- __tablename__ = "momentos"
173
-
174
- id = Column(Integer, primary_key=True, index=True)
175
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
176
- miembro_id = Column(Integer, ForeignKey("miembros.id"), nullable=True)
177
- tipo = Column(String) # "Bautizo", "Reconciliación", "Aceptar a Cristo", etc.
178
- descripcion = Column(Text, nullable=True)
179
- fecha = Column(String) # "YYYY-MM-DD"
180
- registrado_por = Column(Integer, ForeignKey("users.id"))
181
- created_at = Column(DateTime, default=datetime.utcnow)
182
-
183
- iglesia = relationship("Iglesia", back_populates="momentos")
184
- miembro = relationship("Miembro", back_populates="momentos")
185
- registrador = relationship("User")
186
-
187
-
188
- class Inventario(Base):
189
- __tablename__ = "inventario"
190
-
191
- id = Column(Integer, primary_key=True, index=True)
192
- iglesia_id = Column(Integer, ForeignKey("iglesias.id"))
193
- nombre = Column(String)
194
- marca = Column(String)
195
- cantidad = Column(Integer)
196
- fecha_compra = Column(String)
197
- precio = Column(Float)
198
- foto_url = Column(Text, nullable=True)
199
- estado = Column(String, default="Activo")
200
- nota = Column(Text, nullable=True)
201
- registrado_por = Column(Integer, ForeignKey("users.id"))
202
- created_at = Column(DateTime, default=datetime.utcnow)
203
-
204
- iglesia = relationship("Iglesia", back_populates="inventario")
205
- registrador = relationship("User")
206
-
207
-
208
- class DismissedVisita(Base):
209
- """Notificaciones de visita que un administrador en particular ya marcó como vista/leída"""
210
- __tablename__ = "dismissed_visitas"
211
-
212
- id = Column(Integer, primary_key=True, index=True)
213
- user_id = Column(Integer, ForeignKey("users.id"))
214
- miembro_id = Column(Integer, ForeignKey("miembros.id"))
215
- dismissed_at = Column(DateTime, default=datetime.utcnow)
216
-
217
- user = relationship("User")
218
- miembro = relationship("Miembro")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/lyrics.py DELETED
@@ -1,120 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Table, Boolean
2
- from sqlalchemy.orm import relationship
3
- from datetime import datetime
4
- from app.database import Base
5
-
6
- lyric_groups = Table(
7
- "lyric_groups",
8
- Base.metadata,
9
- Column("lyric_id", Integer, ForeignKey("lyrics.id", ondelete="CASCADE"), primary_key=True),
10
- Column("group_id", Integer, ForeignKey("groups.id", ondelete="CASCADE"), primary_key=True),
11
- )
12
-
13
- task_groups = Table(
14
- "task_groups",
15
- Base.metadata,
16
- Column("task_id", Integer, ForeignKey("tasks.id", ondelete="CASCADE"), primary_key=True),
17
- Column("group_id", Integer, ForeignKey("groups.id", ondelete="CASCADE"), primary_key=True),
18
- )
19
-
20
- class Group(Base):
21
- __tablename__ = "groups"
22
-
23
- id = Column(Integer, primary_key=True, index=True)
24
- name = Column(String, index=True)
25
- codigo = Column(String, unique=True, index=True, nullable=True)
26
- foto_base64 = Column(String, nullable=True)
27
- requiere_aprobacion = Column(Boolean, default=False)
28
- created_at = Column(DateTime, default=datetime.utcnow)
29
-
30
- members = relationship("UserGroup", back_populates="group")
31
- lyrics = relationship("Lyric", back_populates="group")
32
- repertorios = relationship("Repertorio", back_populates="group")
33
- lyrics_shared = relationship("Lyric", secondary=lyric_groups, back_populates="groups_shared")
34
- tasks_shared = relationship("Task", secondary=task_groups, back_populates="groups_shared")
35
-
36
- class UserGroup(Base):
37
- __tablename__ = "user_groups"
38
-
39
- user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
40
- group_id = Column(Integer, ForeignKey("groups.id"), primary_key=True)
41
- role = Column(String, default="member") # admin, member
42
- estado = Column(String, default="activo") # activo, pendiente, expulsado
43
- joined_at = Column(DateTime, default=datetime.utcnow)
44
-
45
- # Permisos granulares
46
- perm_compartir_pistas = Column(Boolean, default=True)
47
- perm_compartir_letras = Column(Boolean, default=True)
48
- perm_crud_repertorios = Column(Boolean, default=False)
49
- perm_crud_letras = Column(Boolean, default=True)
50
- perm_ver_pistas = Column(Boolean, default=True)
51
- perm_ver_letras = Column(Boolean, default=True)
52
- perm_ver_repertorios = Column(Boolean, default=True)
53
- perm_gestionar_solicitudes = Column(Boolean, default=False)
54
-
55
- # Registro de última lectura para notificaciones
56
- last_read_pistas = Column(DateTime, nullable=True, default=None)
57
- last_read_letras = Column(DateTime, nullable=True, default=None)
58
- last_read_repertorios = Column(DateTime, nullable=True, default=None)
59
-
60
- user = relationship("User", back_populates="groups")
61
- group = relationship("Group", back_populates="members")
62
-
63
- class Lyric(Base):
64
- __tablename__ = "lyrics"
65
-
66
- id = Column(Integer, primary_key=True, index=True)
67
- title = Column(String, index=True)
68
- artist = Column(String, index=True)
69
- content = Column(String) # ChordPro format
70
- key = Column(String) # Original key (e.g., "C")
71
- group_id = Column(Integer, ForeignKey("groups.id"))
72
- created_by = Column(Integer, ForeignKey("users.id"))
73
- transpose_offset = Column(Integer, default=0, nullable=True)
74
- created_at = Column(DateTime, default=datetime.utcnow)
75
- updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
76
-
77
- group = relationship("Group", back_populates="lyrics")
78
- creator = relationship("User")
79
- groups_shared = relationship("Group", secondary=lyric_groups, back_populates="lyrics_shared")
80
-
81
- @property
82
- def group_ids(self):
83
- return [g.id for g in self.groups_shared]
84
-
85
- class Repertorio(Base):
86
- __tablename__ = "repertorios"
87
-
88
- id = Column(Integer, primary_key=True, index=True)
89
- name = Column(String, index=True)
90
- group_id = Column(Integer, ForeignKey("groups.id"))
91
- created_by = Column(Integer, ForeignKey("users.id"))
92
- created_at = Column(DateTime, default=datetime.utcnow)
93
-
94
- group = relationship("Group", back_populates="repertorios")
95
- creator = relationship("User")
96
- lyrics = relationship("RepertorioLyric", back_populates="repertorio")
97
-
98
- class RepertorioLyric(Base):
99
- __tablename__ = "repertorio_lyrics"
100
-
101
- repertorio_id = Column(Integer, ForeignKey("repertorios.id"), primary_key=True)
102
- lyric_id = Column(Integer, ForeignKey("lyrics.id"), primary_key=True)
103
- order = Column(Integer) # Order in the setlist
104
-
105
- repertorio = relationship("Repertorio", back_populates="lyrics")
106
- lyric = relationship("Lyric")
107
-
108
- class Invitation(Base):
109
- __tablename__ = "invitations"
110
-
111
- id = Column(Integer, primary_key=True, index=True)
112
- code = Column(String, unique=True, index=True) # Unique code or link token
113
- group_id = Column(Integer, ForeignKey("groups.id"))
114
- created_by = Column(Integer, ForeignKey("users.id"))
115
- created_at = Column(DateTime, default=datetime.utcnow)
116
- expires_at = Column(DateTime)
117
- used_at = Column(DateTime) # Nullable, if used
118
-
119
- group = relationship("Group")
120
- creator = relationship("User")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/midi.py DELETED
@@ -1,19 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey
2
- from sqlalchemy.orm import relationship
3
- from datetime import datetime
4
- from app.database import Base
5
-
6
- class PartituraMidi(Base):
7
- __tablename__ = "partituras_midi"
8
-
9
- id = Column(Integer, primary_key=True, index=True)
10
- title = Column(String, index=True, nullable=False)
11
- artist = Column(String, default="Artista desconocido")
12
- filename = Column(String, nullable=False)
13
- filepath = Column(String, nullable=False)
14
- tempo_bpm = Column(Float, default=120.0)
15
- device_id = Column(String, index=True, nullable=True)
16
- user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
17
- created_at = Column(DateTime, default=datetime.utcnow)
18
-
19
- user = relationship("User")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/process.py DELETED
@@ -1,59 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Text
2
- from sqlalchemy.orm import relationship
3
- from datetime import datetime
4
- from app.database import Base
5
- from app.models.user import User
6
- from app.models.lyrics import task_groups
7
-
8
- class Task(Base):
9
- __tablename__ = "tasks"
10
-
11
- id = Column(Integer, primary_key=True, index=True)
12
- task_id = Column(String, unique=True, index=True)
13
- user_id = Column(Integer, ForeignKey("users.id"))
14
- device_id = Column(String)
15
- song_name = Column(String)
16
- artist = Column(String, nullable=True, default=None)
17
- album = Column(String, nullable=True, default=None)
18
- cover_url = Column(String, nullable=True, default=None)
19
- stems = Column(Integer)
20
- status = Column(String, default="PENDING")
21
- created_at = Column(DateTime, default=datetime.utcnow)
22
- # Fecha en que el cliente confirmó que descargó todos los stems.
23
- downloaded_at = Column(DateTime, nullable=True, default=None)
24
- cloud_url = Column(Text, nullable=True, default=None)
25
- # JSON: {"vocals": "BQACAgIA...", "bass": "BQACAgIB..."} - file_ids de Telegram por stem
26
- telegram_file_ids = Column(Text, nullable=True, default=None)
27
- # JSON: {"vocals": 12345, "bass": 12346} - message_ids de Telegram (para borrar si el usuario elimina)
28
- telegram_message_ids = Column(Text, nullable=True, default=None)
29
- group_id = Column(Integer, ForeignKey("groups.id"), nullable=True)
30
- # JSON string con lista de acordes editados por el usuario [{"t": 0.5, "ch": "Am"}, ...]
31
- chords = Column(Text, nullable=True, default=None)
32
- # Fecha en que los archivos de Tebi (stems + voces corales) serán eliminados automáticamente
33
- # Normal: 3 días, Premium: 7 días desde la subida. NULL = ya expirado o tarea anterior al feature.
34
- cloud_expires_at = Column(DateTime, nullable=True, default=None)
35
-
36
- user = relationship("User", back_populates="tasks")
37
- group = relationship("Group", foreign_keys=[group_id])
38
- groups_shared = relationship("Group", secondary=task_groups, back_populates="tasks_shared")
39
-
40
- @property
41
- def group_ids(self):
42
- return [g.id for g in self.groups_shared]
43
-
44
-
45
- class Worker(Base):
46
- __tablename__ = "workers"
47
-
48
- id = Column(Integer, primary_key=True, index=True)
49
- hostname = Column(String, unique=True, index=True)
50
- name = Column(String, nullable=True) # User-friendly custom name
51
- status = Column(String, default="offline") # online | offline | busy
52
- last_seen = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
53
-
54
- # BYOK / Local Worker
55
- user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, unique=True)
56
- token = Column(String, unique=True, index=True, nullable=True)
57
- command = Column(String, default="none") # start | stop | none
58
- is_active = Column(Boolean, default=False)
59
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/sync.py DELETED
@@ -1,32 +0,0 @@
1
- from sqlalchemy import Column, String, DateTime, JSON, Boolean, Integer
2
- from datetime import datetime
3
- import uuid
4
- from app.database import Base
5
-
6
- class B2SyncQueue(Base):
7
- __tablename__ = "b2_sync_queue"
8
-
9
- id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
10
- file_key = Column(String, nullable=False)
11
- file_url = Column(String, nullable=False)
12
- sync_type = Column(String, nullable=False) # "device" o "group"
13
- target_id = Column(String, nullable=False) # userId o groupId
14
- pending_recipients = Column(JSON, nullable=False) # lista de IDs de dispositivos o usuarios
15
- created_at = Column(DateTime, default=datetime.utcnow)
16
-
17
- is_uploaded = Column(Boolean, default=True)
18
- uploading_by = Column(String, nullable=True, default=None)
19
- uploading_claimed_at = Column(DateTime, nullable=True, default=None)
20
- missing_stems = Column(JSON, nullable=True, default=None) # JSON: {"recipient_id": ["vocals", "drums"]}
21
-
22
- class MigrationBackup(Base):
23
- __tablename__ = "migration_backups"
24
-
25
- id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
26
- user_id = Column(Integer, nullable=False, index=True)
27
- created_at = Column(DateTime, default=datetime.utcnow)
28
- expires_at = Column(DateTime, nullable=False)
29
- status = Column(String, default="pending") # "pending", "completed", "restored", "expired"
30
- metadata_json = Column(JSON, nullable=True) # Mapa de metadatos locales
31
- files_info = Column(JSON, nullable=True, default=[]) # Lista de stems respaldados: [{"task_id": "...", "stem_name": "..."}]
32
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/models/user.py DELETED
@@ -1,116 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, JSON
2
- from sqlalchemy.orm import relationship
3
- from datetime import datetime
4
- from app.database import Base
5
-
6
- class User(Base):
7
- __tablename__ = "users"
8
-
9
- id = Column(Integer, primary_key=True, index=True)
10
- username = Column(String, unique=True, index=True)
11
- email = Column(String, unique=True, index=True)
12
- hashed_password = Column(String)
13
- credits = Column(Integer, default=10)
14
- is_premium = Column(Boolean, default=False)
15
- avatar_url = Column(String, nullable=True)
16
- reset_token = Column(String, nullable=True)
17
- reset_token_expires = Column(DateTime, nullable=True)
18
-
19
- devices = relationship("Device", back_populates="user")
20
- tasks = relationship("Task", back_populates="user")
21
- groups = relationship("UserGroup", back_populates="user")
22
- credit_transactions = relationship("CreditTransaction", back_populates="user", cascade="all, delete-orphan")
23
-
24
- class Device(Base):
25
- __tablename__ = "devices"
26
-
27
- id = Column(Integer, primary_key=True, index=True)
28
- user_id = Column(Integer, ForeignKey("users.id"))
29
- device_id = Column(String, index=True)
30
- name = Column(String)
31
- registered_at = Column(DateTime, default=datetime.utcnow)
32
- last_active = Column(DateTime, default=datetime.utcnow)
33
-
34
- user = relationship("User", back_populates="devices")
35
-
36
- class CreditTransaction(Base):
37
- __tablename__ = "credit_transactions"
38
-
39
- id = Column(Integer, primary_key=True, index=True)
40
- user_id = Column(Integer, ForeignKey("users.id"))
41
- amount = Column(Integer)
42
- concept = Column(String)
43
- reference_id = Column(String, nullable=True)
44
- created_at = Column(DateTime, default=datetime.utcnow)
45
-
46
- user = relationship("User", back_populates="credit_transactions")
47
-
48
-
49
- class SystemNotification(Base):
50
- __tablename__ = "system_notifications"
51
-
52
- id = Column(Integer, primary_key=True, index=True)
53
- title = Column(String, index=True)
54
- message = Column(String)
55
- created_at = Column(DateTime, default=datetime.utcnow)
56
-
57
-
58
- class AdminUser(Base):
59
- __tablename__ = "admin_users"
60
-
61
- id = Column(Integer, primary_key=True, index=True)
62
- username = Column(String, unique=True, index=True)
63
- hashed_password = Column(String)
64
- avatar_url = Column(String, nullable=True)
65
- perm_users = Column(Boolean, default=True)
66
- perm_workers = Column(Boolean, default=True)
67
- perm_churches = Column(Boolean, default=True)
68
- perm_groups = Column(Boolean, default=True)
69
- perm_notifications = Column(Boolean, default=True)
70
- created_at = Column(DateTime, default=datetime.utcnow)
71
-
72
-
73
- class AdminNotification(Base):
74
- __tablename__ = "admin_notifications"
75
-
76
- id = Column(Integer, primary_key=True, index=True)
77
- title = Column(String, index=True)
78
- message = Column(String)
79
- created_at = Column(DateTime, default=datetime.utcnow)
80
- read = Column(Boolean, default=False)
81
-
82
-
83
- class LandingFeature(Base):
84
- __tablename__ = "landing_features"
85
-
86
- id = Column(Integer, primary_key=True, index=True)
87
- icon_svg = Column(String, nullable=True)
88
- icon_color = Column(String, default="cyan") # cyan | purple | green | blue | yellow | red
89
- title = Column(String)
90
- description = Column(String)
91
- order = Column(Integer, default=0)
92
-
93
-
94
- class LandingPlatform(Base):
95
- __tablename__ = "landing_platforms"
96
-
97
- id = Column(Integer, primary_key=True, index=True)
98
- name = Column(String, nullable=False)
99
- version = Column(String, nullable=True)
100
- os_details = Column(String, nullable=True)
101
- description = Column(String, nullable=True)
102
- download_url = Column(String, nullable=True)
103
- button_text = Column(String, nullable=True)
104
- os_type = Column(String, default="windows") # windows | android | apple
105
- is_visible = Column(Boolean, default=True)
106
- order = Column(Integer, default=0)
107
-
108
-
109
- class LandingTutorial(Base):
110
- __tablename__ = "landing_tutorials"
111
-
112
- id = Column(Integer, primary_key=True, index=True)
113
- title = Column(String, nullable=False)
114
- desc = Column(String, nullable=True)
115
- steps = Column(JSON, default=[]) # list of strings
116
- order = Column(Integer, default=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/btc_chord.pth DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:71c2c5db17e8c43b8a9a9da5db36ef2d667158c07a214eba16344c154c00bf54
3
- size 12154754
 
 
 
 
tunnel_url.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ https://proceeds-sol-entirely-maximize.trycloudflare.com