Add Sentry integration for error tracking; update requirements and configuration files. Introduce new Alembic migration for missing indexes and constraints in the database schema.
This commit is contained in:
parent
9583aa4bab
commit
18f759aa7c
@ -0,0 +1,60 @@
|
|||||||
|
"""add_missing_indexes_and_constraints
|
||||||
|
|
||||||
|
Revision ID: 7c26d62e8005
|
||||||
|
Revises: bc37e9c7ae19
|
||||||
|
Create Date: 2025-05-13 21:44:46.408395
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '7c26d62e8005'
|
||||||
|
down_revision: Union[str, None] = 'bc37e9c7ae19'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_index('ix_expense_splits_user_id', 'expense_splits', ['user_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_expenses_group_id'), 'expenses', ['group_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_expenses_list_id'), 'expenses', ['list_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_expenses_paid_by_user_id'), 'expenses', ['paid_by_user_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_settlements_group_id'), 'settlements', ['group_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_settlements_paid_by_user_id'), 'settlements', ['paid_by_user_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_settlements_paid_to_user_id'), 'settlements', ['paid_to_user_id'], unique=False)
|
||||||
|
|
||||||
|
# Add check constraints
|
||||||
|
op.create_check_constraint(
|
||||||
|
'chk_expense_context',
|
||||||
|
'expenses',
|
||||||
|
'(item_id IS NOT NULL) OR (list_id IS NOT NULL) OR (group_id IS NOT NULL)'
|
||||||
|
)
|
||||||
|
op.create_check_constraint(
|
||||||
|
'chk_settlement_different_users',
|
||||||
|
'settlements',
|
||||||
|
'paid_by_user_id != paid_to_user_id'
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
# Drop check constraints
|
||||||
|
op.drop_constraint('chk_settlement_different_users', 'settlements', type_='check')
|
||||||
|
op.drop_constraint('chk_expense_context', 'expenses', type_='check')
|
||||||
|
|
||||||
|
op.drop_index(op.f('ix_settlements_paid_to_user_id'), table_name='settlements')
|
||||||
|
op.drop_index(op.f('ix_settlements_paid_by_user_id'), table_name='settlements')
|
||||||
|
op.drop_index(op.f('ix_settlements_group_id'), table_name='settlements')
|
||||||
|
op.drop_index(op.f('ix_expenses_paid_by_user_id'), table_name='expenses')
|
||||||
|
op.drop_index(op.f('ix_expenses_list_id'), table_name='expenses')
|
||||||
|
op.drop_index(op.f('ix_expenses_group_id'), table_name='expenses')
|
||||||
|
op.drop_index('ix_expense_splits_user_id', table_name='expense_splits')
|
||||||
|
# ### end Alembic commands ###
|
@ -11,6 +11,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
DATABASE_URL: str | None = None
|
DATABASE_URL: str | None = None
|
||||||
GEMINI_API_KEY: str | None = None
|
GEMINI_API_KEY: str | None = None
|
||||||
|
SENTRY_DSN: str | None = None # Sentry DSN for error tracking
|
||||||
|
|
||||||
# --- JWT Settings ---
|
# --- JWT Settings ---
|
||||||
SECRET_KEY: str # Must be set via environment variable
|
SECRET_KEY: str # Must be set via environment variable
|
||||||
|
@ -3,6 +3,8 @@ import logging
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
||||||
|
|
||||||
from app.api.api_router import api_router
|
from app.api.api_router import api_router
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
@ -10,6 +12,20 @@ from app.core.api_config import API_METADATA, API_TAGS
|
|||||||
# Import database and models if needed for startup/shutdown events later
|
# Import database and models if needed for startup/shutdown events later
|
||||||
# from . import database, models
|
# from . import database, models
|
||||||
|
|
||||||
|
# Initialize Sentry
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=settings.SENTRY_DSN,
|
||||||
|
integrations=[
|
||||||
|
FastApiIntegration(),
|
||||||
|
],
|
||||||
|
# Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||||
|
# We recommend adjusting this value in production.
|
||||||
|
traces_sample_rate=1.0,
|
||||||
|
# If you wish to associate users to errors (assuming you are using
|
||||||
|
# FastAPI's users system) you may enable sending PII data.
|
||||||
|
send_default_pii=True
|
||||||
|
)
|
||||||
|
|
||||||
# --- Logging Setup ---
|
# --- Logging Setup ---
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=getattr(logging, settings.LOG_LEVEL),
|
level=getattr(logging, settings.LOG_LEVEL),
|
||||||
|
@ -19,7 +19,8 @@ from sqlalchemy import (
|
|||||||
func,
|
func,
|
||||||
text as sa_text,
|
text as sa_text,
|
||||||
Text, # <-- Add Text for description
|
Text, # <-- Add Text for description
|
||||||
Numeric # <-- Add Numeric for price
|
Numeric, # <-- Add Numeric for price
|
||||||
|
CheckConstraint
|
||||||
)
|
)
|
||||||
from sqlalchemy.orm import relationship, backref
|
from sqlalchemy.orm import relationship, backref
|
||||||
|
|
||||||
@ -184,15 +185,15 @@ class Expense(Base):
|
|||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
description = Column(String, nullable=False)
|
description = Column(String, nullable=False)
|
||||||
total_amount = Column(Numeric(10, 2), nullable=False)
|
total_amount = Column(Numeric(10, 2), nullable=False)
|
||||||
currency = Column(String, nullable=False, default="USD") # Consider making this an Enum too if few currencies
|
currency = Column(String, nullable=False, default="USD")
|
||||||
expense_date = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
expense_date = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
split_type = Column(SAEnum(SplitTypeEnum, name="splittypeenum", create_type=True), nullable=False)
|
split_type = Column(SAEnum(SplitTypeEnum, name="splittypeenum", create_type=True), nullable=False)
|
||||||
|
|
||||||
# Foreign Keys
|
# Foreign Keys
|
||||||
list_id = Column(Integer, ForeignKey("lists.id"), nullable=True)
|
list_id = Column(Integer, ForeignKey("lists.id"), nullable=True, index=True)
|
||||||
group_id = Column(Integer, ForeignKey("groups.id"), nullable=True) # If not list-specific but group-specific
|
group_id = Column(Integer, ForeignKey("groups.id"), nullable=True, index=True)
|
||||||
item_id = Column(Integer, ForeignKey("items.id"), nullable=True) # If the expense is for a specific item
|
item_id = Column(Integer, ForeignKey("items.id"), nullable=True)
|
||||||
paid_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
paid_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
|
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||||
@ -206,27 +207,25 @@ class Expense(Base):
|
|||||||
splits = relationship("ExpenseSplit", back_populates="expense", cascade="all, delete-orphan")
|
splits = relationship("ExpenseSplit", back_populates="expense", cascade="all, delete-orphan")
|
||||||
|
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
# Example: Ensure either list_id or group_id is present if item_id is null
|
# Ensure at least one context is provided
|
||||||
# CheckConstraint('(item_id IS NOT NULL) OR (list_id IS NOT NULL) OR (group_id IS NOT NULL)', name='chk_expense_context'),
|
CheckConstraint('(item_id IS NOT NULL) OR (list_id IS NOT NULL) OR (group_id IS NOT NULL)', name='chk_expense_context'),
|
||||||
)
|
)
|
||||||
|
|
||||||
class ExpenseSplit(Base):
|
class ExpenseSplit(Base):
|
||||||
__tablename__ = "expense_splits"
|
__tablename__ = "expense_splits"
|
||||||
__table_args__ = (UniqueConstraint('expense_id', 'user_id', name='uq_expense_user_split'),)
|
__table_args__ = (
|
||||||
|
UniqueConstraint('expense_id', 'user_id', name='uq_expense_user_split'),
|
||||||
|
Index('ix_expense_splits_user_id', 'user_id'), # For looking up user's splits
|
||||||
|
)
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
expense_id = Column(Integer, ForeignKey("expenses.id", ondelete="CASCADE"), nullable=False)
|
expense_id = Column(Integer, ForeignKey("expenses.id", ondelete="CASCADE"), nullable=False)
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
|
||||||
owed_amount = Column(Numeric(10, 2), nullable=False) # For EQUAL or EXACT_AMOUNTS
|
owed_amount = Column(Numeric(10, 2), nullable=False)
|
||||||
# For PERCENTAGE split (value from 0.00 to 100.00)
|
|
||||||
share_percentage = Column(Numeric(5, 2), nullable=True)
|
share_percentage = Column(Numeric(5, 2), nullable=True)
|
||||||
# For SHARES split (e.g., user A has 2 shares, user B has 3 shares)
|
|
||||||
share_units = Column(Integer, nullable=True)
|
share_units = Column(Integer, nullable=True)
|
||||||
|
|
||||||
# is_settled might be better tracked via actual Settlement records or a reconciliation process
|
|
||||||
# is_settled = Column(Boolean, default=False, nullable=False)
|
|
||||||
|
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||||
|
|
||||||
@ -234,14 +233,13 @@ class ExpenseSplit(Base):
|
|||||||
expense = relationship("Expense", back_populates="splits")
|
expense = relationship("Expense", back_populates="splits")
|
||||||
user = relationship("User", foreign_keys=[user_id], back_populates="expense_splits")
|
user = relationship("User", foreign_keys=[user_id], back_populates="expense_splits")
|
||||||
|
|
||||||
|
|
||||||
class Settlement(Base):
|
class Settlement(Base):
|
||||||
__tablename__ = "settlements"
|
__tablename__ = "settlements"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
group_id = Column(Integer, ForeignKey("groups.id"), nullable=False) # Settlements usually within a group
|
group_id = Column(Integer, ForeignKey("groups.id"), nullable=False, index=True)
|
||||||
paid_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
paid_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
paid_to_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
paid_to_user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
amount = Column(Numeric(10, 2), nullable=False)
|
amount = Column(Numeric(10, 2), nullable=False)
|
||||||
settlement_date = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
settlement_date = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
description = Column(Text, nullable=True)
|
description = Column(Text, nullable=True)
|
||||||
@ -257,7 +255,7 @@ class Settlement(Base):
|
|||||||
|
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
# Ensure payer and payee are different users
|
# Ensure payer and payee are different users
|
||||||
# CheckConstraint('paid_by_user_id <> paid_to_user_id', name='chk_settlement_payer_ne_payee'),
|
CheckConstraint('paid_by_user_id != paid_to_user_id', name='chk_settlement_different_users'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Potential future: PaymentMethod model, etc.
|
# Potential future: PaymentMethod model, etc.
|
@ -9,4 +9,5 @@ python-dotenv>=1.0.0 # To load .env file for scripts/alembic
|
|||||||
passlib[bcrypt]>=1.7.4
|
passlib[bcrypt]>=1.7.4
|
||||||
python-jose[cryptography]>=3.3.0
|
python-jose[cryptography]>=3.3.0
|
||||||
pydantic[email]
|
pydantic[email]
|
||||||
google-generativeai>=0.5.0
|
google-generativeai>=0.5.0
|
||||||
|
sentry-sdk[fastapi]>=1.39.0
|
182
fe/package-lock.json
generated
182
fe/package-lock.json
generated
@ -8,6 +8,8 @@
|
|||||||
"name": "fe",
|
"name": "fe",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sentry/tracing": "^7.120.3",
|
||||||
|
"@sentry/vue": "^7.120.3",
|
||||||
"@supabase/auth-js": "^2.69.1",
|
"@supabase/auth-js": "^2.69.1",
|
||||||
"@supabase/supabase-js": "^2.49.4",
|
"@supabase/supabase-js": "^2.49.4",
|
||||||
"@vueuse/core": "^13.1.0",
|
"@vueuse/core": "^13.1.0",
|
||||||
@ -3825,6 +3827,162 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@sentry-internal/feedback": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-ewJJIQ0mbsOX6jfiVFvqMjokxNtgP3dNwUv+4nenN+iJJPQsM6a0ocro3iscxwVdbkjw5hY3BUV2ICI5Q0UWoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-s5xy+bVL1eDZchM6gmaOiXvTqpAsUfO7122DxVdEDMtwVq3e22bS2aiGa8CUgOiJkulZ+09q73nufM77kOmT/A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/replay": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/tracing": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-Ausx+Jw1pAMbIBHStoQ6ZqDZR60PsCByvHdw/jdH9AqPrNE9xlBSf9EwcycvmrzwyKspSLaB52grlje2cRIUMg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/browser": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-i9vGcK9N8zZ/JQo1TCEfHHYZ2miidOvgOABRUc9zQKhYdcYQB2/LU1kqlj77Pxdxf4wOa9137d6rPrSn9iiBxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/feedback": "7.120.3",
|
||||||
|
"@sentry-internal/replay-canvas": "7.120.3",
|
||||||
|
"@sentry-internal/tracing": "7.120.3",
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/integrations": "7.120.3",
|
||||||
|
"@sentry/replay": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/core": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-vyy11fCGpkGK3qI5DSXOjgIboBZTriw0YDx/0KyX5CjIjDDNgp5AGgpgFkfZyiYiaU2Ww3iFuKo4wHmBusz1uA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/integrations": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-6i/lYp0BubHPDTg91/uxHvNui427df9r17SsIEXa2eKDwQ9gW2qRx5IWgvnxs2GV/GfSbwcx4swUB3RfEWrXrQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3",
|
||||||
|
"localforage": "^1.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/replay": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-CjVq1fP6bpDiX8VQxudD5MPWwatfXk8EJ2jQhJTcWu/4bCSOQmHxnnmBM+GVn5acKUBCodWHBN+IUZgnJheZSg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/tracing": "7.120.3",
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/tracing": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-B7bqyYFgHuab1Pn7w5KXsZP/nfFo4VDBDdSXDSWYk5+TYJ3IDruO3eJFhOrircfsz4YwazWm9kbeZhkpsHDyHg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/tracing": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/types": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-C4z+3kGWNFJ303FC+FxAd4KkHvxpNFYAFN8iMIgBwJdpIl25KZ8Q/VdGn0MLLUEHNLvjob0+wvwlcRBBNLXOow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/utils": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-UDAOQJtJDxZHQ5Nm1olycBIsz2wdGX8SdzyGVHmD8EOQYAeDZQyIlQYohDe9nazdIOQLZCIc3fU0G9gqVLkaGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/vue": {
|
||||||
|
"version": "7.120.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-7.120.3.tgz",
|
||||||
|
"integrity": "sha512-YKKLGx6VNk5OTz5JqIsjIqOgaU8u88Q1OBfLZgOpm55vhrvpZGGc+rHyh8XtXxh4DfC+6vTRTrAngvdPOG9Oxw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/browser": "7.120.3",
|
||||||
|
"@sentry/core": "7.120.3",
|
||||||
|
"@sentry/types": "7.120.3",
|
||||||
|
"@sentry/utils": "7.120.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "2.x || 3.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sindresorhus/merge-streams": {
|
"node_modules/@sindresorhus/merge-streams": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
||||||
@ -7440,6 +7598,12 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz",
|
||||||
@ -8413,6 +8577,24 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/localforage": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
"format": "prettier --write src/"
|
"format": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sentry/tracing": "^7.120.3",
|
||||||
|
"@sentry/vue": "^7.120.3",
|
||||||
"@supabase/auth-js": "^2.69.1",
|
"@supabase/auth-js": "^2.69.1",
|
||||||
"@supabase/supabase-js": "^2.49.4",
|
"@supabase/supabase-js": "^2.49.4",
|
||||||
"@vueuse/core": "^13.1.0",
|
"@vueuse/core": "^13.1.0",
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
|
import * as Sentry from '@sentry/vue';
|
||||||
|
import { BrowserTracing } from '@sentry/tracing';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
// import { createI18n } from 'vue-i18n';
|
// import { createI18n } from 'vue-i18n';
|
||||||
@ -33,6 +35,23 @@ const app = createApp(App);
|
|||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
|
|
||||||
|
// Initialize Sentry
|
||||||
|
Sentry.init({
|
||||||
|
app,
|
||||||
|
dsn: import.meta.env.VITE_SENTRY_DSN,
|
||||||
|
integrations: [
|
||||||
|
new BrowserTracing({
|
||||||
|
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
|
||||||
|
tracingOrigins: ['localhost', /^\//],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||||
|
// We recommend adjusting this value in production
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
// Set environment
|
||||||
|
environment: import.meta.env.MODE,
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize auth state before mounting the app
|
// Initialize auth state before mounting the app
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
if (authStore.accessToken) {
|
if (authStore.accessToken) {
|
||||||
|
Loading…
Reference in New Issue
Block a user