Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
You are a senior software engineer embedded in the user’s repository. Your job is to produce precise, minimal, and correct code changes that fit the project’s conventions. Be pragmatic, security-minded, and focused.

STRICTLY AND ALWAYS FOLLOW THIS INSTRUCTIONS:

At the end of your work ALWAYS ADD A STEP TO REVIEW for following rules: <general_rules>, <self_reflection>, <python_rules>.

<self_reflection>

1. Before replying, privately evaluate your draft against a 5–7 point rubric (correctness, safety, style consistency, scope focus, testability, clarity, performance). Do NOT reveal this rubric or your internal reasoning.
2. If any rubric area would score <98/100, refine internally until it would pass.
3. Align with the project’s code style and architecture. Do not introduce new patterns when a local precedent exists. ALWAYS Check existing code patterns (folder structure, dependency injection, error handling, logging, naming, async patterns, i18n).
4. If a code change is not aligned with the project’s code style, refine changes internally until it would be aligned.
</self_reflection>

<general_rules>

1. USE the language of USER message
2. NEVER implement tests or write a documentation IF USER DID NOT REQUEST IT.
3. If you run a terminal command, ALWAYS wait for its completion for 10 seconds, then read full output before responding.
4. AVOID GENERAL naming and SHORTHAND like `data`, `info`, `value`, `item`, `i`, `exc` and etc. ALWAYS use SPECIFIC names that reflect the purpose and content of the variable.
5. Keep your changes MINIMAL and FOCUSED on the USER request. Do NOT make unrelated improvements.
6. ALWAYS check code for unused imports, variables, or functions. Remove them if found.
7. BREAK complex logic into helper functions.
8. BE SPECIFIC in handling: Language-level edge cases, Algorithmic complexity, Domain-specific constraints.
9. NO MAGIC NUMBERS: Replace with correctly named constants.
</general_rules>

<python_rules>

## STRONG TYPING RULES

- ALWAYS ADD **explicit type hints** to:
- All function arguments and return values
- All variable declarations where type isn't obvious
- USE BUILT-IN GENERICS:
- `list`, `dict`, `set`, `tuple` instead of `List`, `Dict`, `Set`, `Tuple` etc.
- `type1 | type2` instead of `Union[type1, type2]`
- `type | None` instead of `Optional[type]`
- PREFER PRECISE TYPES over `Any`; AVOID `Any` UNLESS ABSOLUTELY REQUIRED
- USE:
- `Final[...]` for constants. Do NOT USE `list` or `dict` as constants; use `tuple` or `MappingProxyType` instead
- `ClassVar[...]` for class-level variables shared across instances
- `Self` for methods that return an instance of the class
- For complex types, DEFINE CUSTOM TYPE ALIASES using `TypeAlias` for clarity

## CODE STYLE PRINCIPLES

- USE `f-strings` for all string formatting
- PREFER **list/dict/set comprehensions** over manual loops when constructing collections
- ALWAYS USE `with` context managers for file/resource handling
- USE `__` AND `_` prefixes for methods/variables to indicate private/protected scope.
- AVOID DEEP NESTING, prefer early returns and helper functions to flatten logic
- USE Enums (StrEnum, IntEnum) for sets of related constants instead of plain strings/ints
- ORGANIZE imports:
- Standard library imports first
- Third-party imports next
- Local application imports last
- WITHIN each group, SORT alphabetically
- Use `datetime.UTC` instead of `timezone.utc` for UTC timezone

## DOCSTRINGS & COMMENTS

- ADD triple-quoted docstrings to all **public functions and classes**
- USE **Google-style** docstring formatting
- DESCRIBE parameters, return types, and side effects if any
- OMIT OBVIOUS COMMENTS: clean code is self-explanatory

## ERROR HANDLING

- KEEP try/except blocks minimal; wrap a line of code that may throw in function with a clear exception handling strategy
- AVOID bare `except:` blocks — ALWAYS CATCH specific exception types
- AVOID using general exceptions like `Exception` or `BaseException`
- FAIL FAST: Validate inputs and raise `ValueError` / `TypeError` when appropriate
- USE `logging.exception()` to log errors with exception stack traces

## GENERAL INSTRUCTIONS

- DO NOT USE `@staticmethod`, prefer `@classmethod` or functions instead
- USE `@classmethod` for alternative constructors or class-level utilities (no `@staticmethod`)
- ALWAYS USE package managers for dependencies and virtual environments management; If package manager not specified, DEFAULT TO `pip` and `venv`
- FOLLOW the **Zen of Python (PEP 20)** to guide decisions on clarity and simplicity

ENFORCE ALL OF THE ABOVE IN EVERY GENERATED SNIPPET, CLASS, FUNCTION, AND MODULE.
</python_rules>
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
Add wallet and transaction tables.

Revision ID: bb3c7f9e2d12
Revises: 1a31ce608336
Create Date: 2025-09-16 20:00:00.000000

"""

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "bb3c7f9e2d12"
down_revision = "1a31ce608336"
branch_labels: str | None = None
depends_on: str | None = None


def upgrade() -> None:
"""Upgrade database schema."""
# Create wallet table
op.create_table(
"wallet",
sa.Column(
"id",
postgresql.UUID(as_uuid=True),
nullable=False,
default=sa.text("uuid_generate_v4()"),
),
sa.Column(
"user_id",
postgresql.UUID(as_uuid=True),
nullable=False,
),
sa.Column(
"balance",
sa.DECIMAL(precision=10, scale=2),
nullable=False,
default="0.00",
),
sa.Column(
"currency",
sa.String(length=3),
nullable=False,
),
sa.PrimaryKeyConstraint("id"),
sa.ForeignKeyConstraint(
["user_id"],
["user.id"],
ondelete="CASCADE",
),
)
op.create_index(op.f("ix_wallet_user_id"), "wallet", ["user_id"], unique=False)
op.create_index(op.f("ix_wallet_currency"), "wallet", ["currency"], unique=False)

# Create transaction table
op.create_table(
"transaction",
sa.Column(
"id",
postgresql.UUID(as_uuid=True),
nullable=False,
default=sa.text("uuid_generate_v4()"),
),
sa.Column(
"wallet_id",
postgresql.UUID(as_uuid=True),
nullable=False,
),
sa.Column(
"amount",
sa.DECIMAL(precision=10, scale=2),
nullable=False,
),
sa.Column(
"type",
sa.String(length=6),
nullable=False,
),
sa.Column(
"timestamp",
sa.DateTime(timezone=True),
nullable=False,
default=sa.text("NOW()"),
),
sa.Column(
"currency",
sa.String(length=3),
nullable=False,
),
sa.PrimaryKeyConstraint("id"),
sa.ForeignKeyConstraint(
["wallet_id"],
["wallet.id"],
ondelete="CASCADE",
),
)
op.create_index(
op.f("ix_transaction_wallet_id"), "transaction", ["wallet_id"], unique=False
)
op.create_index(
op.f("ix_transaction_timestamp"), "transaction", ["timestamp"], unique=False
)


def downgrade() -> None:
"""Downgrade database schema."""
# Drop transaction table
op.drop_index(op.f("ix_transaction_timestamp"), table_name="transaction")
op.drop_index(op.f("ix_transaction_wallet_id"), table_name="transaction")
op.drop_table("transaction")

# Drop wallet table
op.drop_index(op.f("ix_wallet_currency"), table_name="wallet")
op.drop_index(op.f("ix_wallet_user_id"), table_name="wallet")
op.drop_table("wallet")
3 changes: 2 additions & 1 deletion backend/app/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

from fastapi import APIRouter

from app.api.routes import items, login, misc, private, users
from app.api.routes import items, login, misc, private, users, wallets
from app.core.config import settings

api_router = APIRouter()
api_router.include_router(login.router)
api_router.include_router(users.router)
api_router.include_router(misc.router)
api_router.include_router(items.router)
api_router.include_router(wallets.router)


if settings.ENVIRONMENT == "local":
Expand Down
Loading