Skip to content
Draft
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
107 changes: 54 additions & 53 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,53 +1,54 @@
# 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
# 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="Study Companion Project"
STACK_NAME=study-companion-project

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

# 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=app
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changethis

SENTRY_DSN=

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

NEXT_PUBLIC_API_URL=http://localhost:8000


PINECONE_API_KEY=changethis

OPENAI_API_KEY=changethis

NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:8000
# 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
# 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="Study Companion Project"
STACK_NAME=study-companion-project

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

# 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=app
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changethis

SENTRY_DSN=

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

NEXT_PUBLIC_API_URL=http://localhost:8000


PINECONE_API_KEY=changethis

OPENAI_API_KEY=changethis

NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:8000
NEXT_INTERNAL_BACKEND_BASE_URL=http://backend:8000
14 changes: 7 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.DS_Store
htmlcov
.env
*.env
.env*
/.idea/
frontend/.*
.DS_Store
htmlcov
*.env
/.idea/
frontend/.*
config.bat
node_modules
86 changes: 43 additions & 43 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
FROM python:3.10

ENV PYTHONUNBUFFERED=1

WORKDIR /app/

# Install uv
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
COPY --from=ghcr.io/astral-sh/uv:0.5.11 /uv /uvx /bin/

# Place executables in the environment at the front of the path
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#using-the-environment
ENV PATH="/app/.venv/bin:$PATH"

# Compile bytecode
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#compiling-bytecode
ENV UV_COMPILE_BYTECODE=1

# uv Cache
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#caching
ENV UV_LINK_MODE=copy

# Install dependencies
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project

ENV PYTHONPATH=/app

COPY ./scripts /app/scripts

COPY ./pyproject.toml ./uv.lock ./alembic.ini /app/

COPY ./app /app/app

# Sync the project
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync

CMD ["fastapi", "run", "--workers", "4", "app/main.py"]
FROM python:3.10
ENV PYTHONUNBUFFERED=1
WORKDIR /app/
# Install uv
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
COPY --from=ghcr.io/astral-sh/uv:0.5.11 /uv /uvx /bin/
# Place executables in the environment at the front of the path
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#using-the-environment
ENV PATH="/app/.venv/bin:$PATH"
# Compile bytecode
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#compiling-bytecode
ENV UV_COMPILE_BYTECODE=1
# uv Cache
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#caching
ENV UV_LINK_MODE=copy
# Install dependencies
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project
ENV PYTHONPATH=/app
COPY ./scripts /app/scripts
COPY ./pyproject.toml ./uv.lock ./alembic.ini /app/
COPY ./app /app/app
# Sync the project
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync
CMD ["fastapi", "run", "--workers", "4", "app/main.py"]
Original file line number Diff line number Diff line change
@@ -1,42 +1,31 @@
"""Fix delete document error.

Revision ID: 10368f38610b
Revises: b5370243d0bc
Create Date: 2025-10-02 07:06:36.831373

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


# revision identifiers, used by Alembic.
revision = '10368f38610b'
down_revision = 'b5370243d0bc'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('chat',
sa.Column('message', sqlmodel.sql.sqltypes.AutoString(length=1024), nullable=True),
sa.Column('is_system', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('course_id', sa.Uuid(), nullable=False),
sa.ForeignKeyConstraint(['course_id'], ['course.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.drop_constraint(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', type_='foreignkey')
op.create_foreign_key(None, 'quizattempt', 'quiz', ['quiz_id'], ['id'], ondelete='CASCADE')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'quizattempt', type_='foreignkey')
op.create_foreign_key(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', 'quiz', ['quiz_id'], ['id'])
op.drop_table('chat')
# ### end Alembic commands ###
"""Fix delete document error.

Revision ID: 10368f38610b
Revises: b5370243d0bc
Create Date: 2025-10-02 07:06:36.831373

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


# revision identifiers, used by Alembic.
revision = '10368f38610b'
down_revision = 'b5370243d0bc'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', type_='foreignkey')
op.create_foreign_key(None, 'quizattempt', 'quiz', ['quiz_id'], ['id'], ondelete='CASCADE')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'quizattempt', type_='foreignkey')
op.create_foreign_key(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', 'quiz', ['quiz_id'], ['id'])
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
"""Add created and updated time columns in course and document models

Revision ID: 177fc617fc0b
Revises: 9edab5efe2e4
Create Date: 2025-09-23 08:46:17.677184

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

# revision identifiers, used by Alembic.
revision = '177fc617fc0b'
down_revision = '9edab5efe2e4'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
# ### end Alembic commands ###
pass


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('chat',
sa.Column('message', sa.VARCHAR(length=1024), autoincrement=False, nullable=False),
sa.Column('is_system', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('course_id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False),
sa.Column('updated_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['course_id'], ['course.id'], name=op.f('chat_course_id_fkey'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('chat_pkey'))
)
# ### end Alembic commands ###
"""Add created and updated time columns in course and document models
Revision ID: 177fc617fc0b
Revises: 9edab5efe2e4
Create Date: 2025-09-23 08:46:17.677184
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '177fc617fc0b'
down_revision = '9edab5efe2e4'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
# ### end Alembic commands ###
pass
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('chat',
sa.Column('message', sa.VARCHAR(length=1024), autoincrement=False, nullable=False),
sa.Column('is_system', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('course_id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False),
sa.Column('updated_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['course_id'], ['course.id'], name=op.f('chat_course_id_fkey'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('chat_pkey'))
)
# ### end Alembic commands ###
Loading