Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
Binary file added .DS_Store
Binary file not shown.
42 changes: 31 additions & 11 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ FRONTEND_HOST=http://localhost:5173
# FRONTEND_HOST=https://dashboard.example.com

# Environment: local, staging, production
ENVIRONMENT=local
ENVIRONMENT=production

PROJECT_NAME="Full Stack FastAPI Project"
STACK_NAME=full-stack-fastapi-project
PROJECT_NAME="KeToanAuto"
STACK_NAME=ketoanauto

# Backend
BACKEND_CORS_ORIGINS="http://localhost,http://localhost:5173,https://localhost,https://localhost:5173,http://localhost.tiangolo.com"
SECRET_KEY=changethis
FIRST_SUPERUSER=admin@example.com
FIRST_SUPERUSER_PASSWORD=changethis
BACKEND_CORS_ORIGINS="http://localhost:5173,https://localhost:5173,http://localhost:3000,https://localhost:3000"
SECRET_KEY=Ti100600@12131231
FIRST_SUPERUSER=nguyenvantien0620@gmail.com
FIRST_SUPERUSER_PASSWORD=Ti100600@

# Emails
SMTP_HOST=
Expand All @@ -34,12 +34,32 @@ SMTP_PORT=587
# Postgres
POSTGRES_SERVER=localhost
POSTGRES_PORT=5432
POSTGRES_DB=app
POSTGRES_DB=KeToanAuto
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changethis
POSTGRES_PASSWORD=Ti100600@

SENTRY_DSN=

# Configure these with your own Docker registry images
DOCKER_IMAGE_BACKEND=backend
DOCKER_IMAGE_FRONTEND=frontend
DOCKER_IMAGE_BACKEND=nguyentien0620/backend
DOCKER_IMAGE_FRONTEND=nguyentien0620/frontend


# AWS S3 (Cloudflare R2) credentials
R2_ACCOUNT_ID="46252d78a71b1e948cca93580f21d6c8"
R2_ACCESS_KEY="fc94974446d24f787fc2c065211dd4b5"
R2_SECRET_KEY="7e2612409a61feb12a18d87cf960389e165b541680d660c86725de1e7cbbc753"
R2_BUCKET_NAME="ketoanauto"

# OCR API
OCR_API_URL="https://nas3fbh253sfifna.aistudio-app.com/layout-parsing"
OCR_API_TOKEN="24f39b195ccd25b584dd4d3edac1179d1688b1c3"
OCR_JOB_URL="https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
OCR_JOB_POLLING_INTERVAL=5 # in seconds
OCR_MODEL="PaddleOCR-VL-1.5"

# VNPAY credentials (for testing, use the provided demo credentials or set your own in the .env file)
VNPAY_TMN_CODE="36PBP850" # Replace with your actual
VNPAY_HASH_SECRET="Q6NRDOTHBWMJ5KWUMAZUNRT4MNYLHR2E" # Replace
VNPAY_RETURN_URL="https://localhost:5173/payment/return" # Update if your backend URL is different
VNP_URL="https://sandbox.vnpayment.vn/paymentv2/vpcpay.html" # VNPAY sandbox URL
59 changes: 59 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Domain
# This would be set to the production domain with an env var on deployment
# used by Traefik to transmit traffic and aqcuire TLS certificates
DOMAIN=localhost
# To test the local Traefik config
# DOMAIN=localhost.tiangolo.com

# Used by the backend to generate links in emails to the frontend
FRONTEND_HOST=http://localhost:5173
# In staging and production, set this env var to the frontend host, e.g.
# FRONTEND_HOST=https://dashboard.example.com

# Environment: local, staging, production
ENVIRONMENT=local

PROJECT_NAME="KeToanAuto"
STACK_NAME=ketoanauto

# Backend
BACKEND_CORS_ORIGINS="http://localhost,http://localhost:5173,https://localhost,https://localhost:5173,http://localhost.tiangolo.com"
SECRET_KEY=Ti100600@12131231
FIRST_SUPERUSER=nguyenvantien0620@gmail.com
FIRST_SUPERUSER_PASSWORD=Ti100600@

# Emails
SMTP_HOST=
SMTP_USER=
SMTP_PASSWORD=
EMAILS_FROM_EMAIL=info@example.com
SMTP_TLS=True
SMTP_SSL=False
SMTP_PORT=587

# Postgres
POSTGRES_SERVER=localhost
POSTGRES_PORT=5432
POSTGRES_DB=KeToanAuto
POSTGRES_USER=postgres
POSTGRES_PASSWORD=Ti100600@

SENTRY_DSN=

# Configure these with your own Docker registry images
DOCKER_IMAGE_BACKEND=backend
DOCKER_IMAGE_FRONTEND=frontend


# AWS S3 (Cloudflare R2) credentials
R2_ACCOUNT_ID="46252d78a71b1e948cca93580f21d6c8"
R2_ACCESS_KEY="fc94974446d24f787fc2c065211dd4b5"
R2_SECRET_KEY="7e2612409a61feb12a18d87cf960389e165b541680d660c86725de1e7cbbc753"
R2_BUCKET_NAME="ketoanauto"

# OCR API
OCR_API_URL="https://nas3fbh253sfifna.aistudio-app.com/layout-parsing"
OCR_API_TOKEN="24f39b195ccd25b584dd4d3edac1179d1688b1c3"
OCR_JOB_URL="https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
OCR_JOB_POLLING_INTERVAL=5 # in seconds
OCR_MODEL="PaddleOCR-VL"
55 changes: 55 additions & 0 deletions backend/app/alembic/versions/16a9754259d0_add_topup_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""add topup tables

Revision ID: 16a9754259d0
Revises: e2f3a4b5c6d7
Create Date: 2026-04-25 01:40:28.720543

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes


# revision identifiers, used by Alembic.
revision = '16a9754259d0'
down_revision = 'e2f3a4b5c6d7'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('topup_transactions',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('user_id', sa.Uuid(), nullable=False),
sa.Column('txn_ref', sqlmodel.sql.sqltypes.AutoString(length=100), nullable=True),
sa.Column('amount', sa.Float(), nullable=False),
sa.Column('type', sa.Enum('CREDIT', 'DEBIT', name='topuptype'), nullable=False),
sa.Column('status', sa.Enum('PENDING', 'SUCCESS', 'FAILED', name='topupstatus'), nullable=False),
sa.Column('note', sqlmodel.sql.sqltypes.AutoString(length=500), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_topup_transactions_txn_ref'), 'topup_transactions', ['txn_ref'], unique=False)
op.create_index(op.f('ix_topup_transactions_user_id'), 'topup_transactions', ['user_id'], unique=False)
op.create_table('user_balances',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('user_id', sa.Uuid(), nullable=False),
sa.Column('balance', sa.Float(), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_user_balances_user_id'), 'user_balances', ['user_id'], unique=True)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_user_balances_user_id'), table_name='user_balances')
op.drop_table('user_balances')
op.drop_index(op.f('ix_topup_transactions_user_id'), table_name='topup_transactions')
op.drop_index(op.f('ix_topup_transactions_txn_ref'), table_name='topup_transactions')
op.drop_table('topup_transactions')
# ### end Alembic commands ###

This file was deleted.

This file was deleted.

39 changes: 39 additions & 0 deletions backend/app/alembic/versions/a24416477b07_create_api_keys_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""create_api_keys_table

Revision ID: a24416477b07
Revises: c4f659581040
Create Date: 2026-04-12 15:14:24.777302

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes


# revision identifiers, used by Alembic.
revision = 'a24416477b07'
down_revision = 'c4f659581040'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('api_keys',
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('user_id', sa.Uuid(), nullable=False),
sa.Column('key', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_api_keys_user_id'), 'api_keys', ['user_id'], unique=False)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_api_keys_user_id'), table_name='api_keys')
op.drop_table('api_keys')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""add user_type to users

Revision ID: a7b8c9d0e1f2
Revises: f1a2b3c4d5e6
Create Date: 2026-06-12 00:00:00.000000

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'a7b8c9d0e1f2'
down_revision = 'f1a2b3c4d5e6'
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
'users',
sa.Column(
'user_type',
sa.String(length=20),
nullable=False,
server_default='normal',
),
)
# Existing superusers become admins
op.execute("UPDATE users SET user_type = 'admin' WHERE is_superuser")
op.create_index(op.f('ix_users_user_type'), 'users', ['user_type'])


def downgrade():
op.drop_index(op.f('ix_users_user_type'), table_name='users')
op.drop_column('users', 'user_type')
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""add model to file_jobs

Revision ID: b1c2d3e4f5a6
Revises: a7b8c9d0e1f2
Create Date: 2026-06-14 00:00:00.000000

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'b1c2d3e4f5a6'
down_revision = 'a7b8c9d0e1f2'
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
'file_jobs',
sa.Column('model', sa.String(length=100), nullable=True),
)


def downgrade():
op.drop_column('file_jobs', 'model')
Loading
Loading