From c1d4df442eb2d19b2e74956f1e43dbb6d928fa66 Mon Sep 17 00:00:00 2001 From: mbsantiago Date: Wed, 9 Oct 2024 22:01:35 +0100 Subject: [PATCH 1/2] Added docker compose for prod with postgres --- Dockerfile | 6 +- Makefile | 2 +- back/Dockerfile | 2 +- back/docs/developer_guide/quickstart.md | 8 +- .../versions/03a1d239e06e_first_migration.py | 376 +++++++++++++++--- back/src/whombat/models/base.py | 4 + back/src/whombat/system/app.py | 8 +- back/src/whombat/system/settings.py | 9 +- back/uv.lock | 12 +- compose-dev.yaml => compose.dev.yaml | 0 compose.prod.yaml | 99 +++++ 11 files changed, 452 insertions(+), 74 deletions(-) rename compose-dev.yaml => compose.dev.yaml (100%) create mode 100644 compose.prod.yaml diff --git a/Dockerfile b/Dockerfile index 8c1b6be3..c3c69351 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ ENV UV_LINK_MODE=copy RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=back/uv.lock,target=uv.lock \ --mount=type=bind,source=back/pyproject.toml,target=pyproject.toml \ - uv sync --frozen --no-install-project --no-dev + uv sync --frozen --no-install-project --no-dev --all-extras # Then, add the rest of the project source code and install it # Installing separately from its dependencies allows optimal layer caching @@ -62,7 +62,7 @@ COPY --from=guide_builder /guide/out/ /app/src/whombat/user_guide/ COPY --from=frontend_builder /front/out/ /app/src/whombat/statics/ RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen --no-dev + uv sync --frozen --no-dev --all-extras # === STEP 4 === Final Image @@ -75,6 +75,8 @@ COPY --from=builder --chown=app:app /app /app # Place executables in the environment at the front of the path ENV PATH="/app/.venv/bin:$PATH" +WORKDIR /app + # Create a directory for audio files RUN mkdir /audio RUN mkdir /data diff --git a/Makefile b/Makefile index 0696fc65..ef735ce6 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ BACK_DIR := back .PHONY: dev dev-front dev-back dev-docs storybook install-dev build-frontend build-guide bundle publish clean dev: - docker-compose -f compose-dev.yaml up --watch --build frontend backend + docker-compose -f compose.dev.yaml up --watch --build frontend backend dev-front: cd $(FRONT_DIR) && npm run dev diff --git a/back/Dockerfile b/back/Dockerfile index b0218260..95f890bd 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -5,7 +5,7 @@ WORKDIR /code 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 --dev + uv sync --frozen --no-install-project --dev --all-extras ADD . /code diff --git a/back/docs/developer_guide/quickstart.md b/back/docs/developer_guide/quickstart.md index 8229dba5..1b9abb30 100644 --- a/back/docs/developer_guide/quickstart.md +++ b/back/docs/developer_guide/quickstart.md @@ -117,7 +117,7 @@ cd whombat - **Backend and Frontend:** ```bash - docker-compose -f compose-dev.yaml up backend frontend + docker-compose -f compose.dev.yaml up backend frontend ``` Access the Whombat development environment at http://localhost:3000 @@ -125,7 +125,7 @@ cd whombat - **Storybook:** ```bash - docker-compose -f compose-dev.yaml up storybook + docker-compose -f compose.dev.yaml up storybook ``` Access Storybook at http://localhost:6006. @@ -133,12 +133,12 @@ cd whombat - **Documentation Server:** ```bash - docker-compose -f compose-dev.yaml up docs + docker-compose -f compose.dev.yaml up docs ``` View the documentation at http://localhost:8000. - **All Services:** ```bash - docker-compose -f compose-dev.yaml up + docker-compose -f compose.dev.yaml up ``` diff --git a/back/src/whombat/migrations/versions/03a1d239e06e_first_migration.py b/back/src/whombat/migrations/versions/03a1d239e06e_first_migration.py index 76b95d8e..97cfdb19 100644 --- a/back/src/whombat/migrations/versions/03a1d239e06e_first_migration.py +++ b/back/src/whombat/migrations/versions/03a1d239e06e_first_migration.py @@ -32,7 +32,13 @@ def upgrade() -> None: sa.Column("name", sa.String(), nullable=False), sa.Column("description", sa.String(), nullable=False), sa.Column("annotation_instructions", sa.String(), nullable=True), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_annotation_project")), sa.UniqueConstraint("name", name=op.f("uq_annotation_project_name")), sa.UniqueConstraint("uuid", name=op.f("uq_annotation_project_uuid")), @@ -46,7 +52,13 @@ def upgrade() -> None: sa.Column("name", sa.String(), nullable=False), sa.Column("description", sa.String(), nullable=True), sa.Column("audio_dir", whombat.models.base.PathType(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_dataset")), sa.UniqueConstraint("audio_dir", name=op.f("uq_dataset_audio_dir")), sa.UniqueConstraint("name", name=op.f("uq_dataset_name")), @@ -60,7 +72,13 @@ def upgrade() -> None: ), sa.Column("task", sa.String(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_evaluation")), sa.UniqueConstraint("uuid", name=op.f("uq_evaluation_uuid")), ) @@ -73,7 +91,13 @@ def upgrade() -> None: sa.Column("name", sa.String(), nullable=False), sa.Column("description", sa.String(), nullable=False), sa.Column("task", sa.String(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_evaluation_set")), sa.UniqueConstraint("name", name=op.f("uq_evaluation_set_name")), sa.UniqueConstraint("uuid", name=op.f("uq_evaluation_set_uuid")), @@ -82,7 +106,13 @@ def upgrade() -> None: "feature_name", sa.Column("id", sa.Integer(), nullable=False), sa.Column("name", sa.String(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_feature_name")), sa.UniqueConstraint("name", name=op.f("uq_feature_name_name")), ) @@ -95,7 +125,13 @@ def upgrade() -> None: sa.Column("name", sa.String(), nullable=False), sa.Column("version", sa.String(), nullable=False), sa.Column("description", sa.String(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_model_run")), sa.UniqueConstraint("name", "version", name=op.f("uq_model_run_name")), sa.UniqueConstraint("uuid", name=op.f("uq_model_run_uuid")), @@ -117,7 +153,13 @@ def upgrade() -> None: sa.Column("longitude", sa.Float(), nullable=True), sa.Column("time_expansion", sa.Float(), nullable=False), sa.Column("rights", sa.String(), nullable=True), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_recording")), sa.UniqueConstraint("uuid", name=op.f("uq_recording_uuid")), ) @@ -132,7 +174,13 @@ def upgrade() -> None: sa.Column("id", sa.Integer(), nullable=False), sa.Column("key", sa.String(), nullable=False), sa.Column("value", sa.String(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_tag")), sa.UniqueConstraint("key", "value", name=op.f("uq_tag_key")), ) @@ -148,7 +196,13 @@ def upgrade() -> None: sa.Column("is_active", sa.Boolean(), nullable=False), sa.Column("is_superuser", sa.Boolean(), nullable=False), sa.Column("is_verified", sa.Boolean(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.PrimaryKeyConstraint("id", name=op.f("pk_user")), sa.UniqueConstraint("username", name=op.f("uq_user_username")), ) @@ -161,7 +215,13 @@ def upgrade() -> None: fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["user_id"], ["user.id"], @@ -174,7 +234,13 @@ def upgrade() -> None: "annotation_project_tag", sa.Column("annotation_project_id", sa.Integer(), nullable=False), sa.Column("tag_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["annotation_project_id"], ["annotation_project.id"], @@ -208,7 +274,13 @@ def upgrade() -> None: sa.Column("start_time", sa.Float(), nullable=False), sa.Column("end_time", sa.Float(), nullable=False), sa.Column("score", sa.Float(), nullable=True), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["recording_id"], ["recording.id"], @@ -228,7 +300,13 @@ def upgrade() -> None: sa.Column("dataset_id", sa.Integer(), nullable=False), sa.Column("recording_id", sa.Integer(), nullable=False), sa.Column("path", whombat.models.base.PathType(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["dataset_id"], ["dataset.id"], @@ -255,7 +333,13 @@ def upgrade() -> None: sa.Column("evaluation_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_id"], ["evaluation.id"], @@ -277,7 +361,13 @@ def upgrade() -> None: "evaluation_set_model_run", sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("model_run_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_set_id"], ["evaluation_set.id"], @@ -305,7 +395,13 @@ def upgrade() -> None: "evaluation_set_tag", sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("tag_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_set_id"], ["evaluation_set.id"], @@ -332,7 +428,13 @@ def upgrade() -> None: sa.Column("model_run_id", sa.Integer(), nullable=False), sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("evaluation_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_id"], ["evaluation.id"], @@ -375,7 +477,13 @@ def upgrade() -> None: sa.Column( "uuid", fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["created_by_id"], ["user.id"], @@ -389,7 +497,13 @@ def upgrade() -> None: sa.Column("recording_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["feature_name_id"], ["feature_name.id"], @@ -420,7 +534,13 @@ def upgrade() -> None: fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["recording_id"], ["recording.id"], @@ -444,7 +564,13 @@ def upgrade() -> None: "recording_tag", sa.Column("recording_id", sa.Integer(), nullable=False), sa.Column("tag_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["recording_id"], ["recording.id"], @@ -473,7 +599,13 @@ def upgrade() -> None: sa.Column( "geometry", whombat.models.base.GeometryType(), nullable=False ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["recording_id"], ["recording.id"], @@ -492,7 +624,13 @@ def upgrade() -> None: fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["user_id"], ["user.id"], name=op.f("fk_user_run_user_id_user") ), @@ -506,7 +644,13 @@ def upgrade() -> None: "uuid", fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False ), sa.Column("clip_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_id"], ["clip.id"], @@ -520,7 +664,13 @@ def upgrade() -> None: sa.Column("clip_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_id"], ["clip.id"], name=op.f("fk_clip_feature_clip_id_clip") ), @@ -543,7 +693,13 @@ def upgrade() -> None: "uuid", fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False ), sa.Column("clip_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_id"], ["clip.id"], @@ -556,7 +712,13 @@ def upgrade() -> None: "evaluation_set_user_run", sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("user_run_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_set_id"], ["evaluation_set.id"], @@ -584,7 +746,13 @@ def upgrade() -> None: "recording_note", sa.Column("recording_id", sa.Integer(), nullable=False), sa.Column("note_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["note_id"], ["note.id"], @@ -609,7 +777,13 @@ def upgrade() -> None: sa.Column("sound_event_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["feature_name_id"], ["feature_name.id"], @@ -636,7 +810,13 @@ def upgrade() -> None: sa.Column("user_run_id", sa.Integer(), nullable=False), sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("evaluation_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["evaluation_id"], ["evaluation.id"], @@ -675,7 +855,13 @@ def upgrade() -> None: sa.Column( "uuid", fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["annotation_project_id"], ["annotation_project.id"], @@ -706,7 +892,13 @@ def upgrade() -> None: sa.Column("id", sa.Integer(), nullable=False), sa.Column("clip_annotation_id", sa.Integer(), nullable=False), sa.Column("note_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_annotation_id"], ["clip_annotation.id"], @@ -736,7 +928,13 @@ def upgrade() -> None: fastapi_users_db_sqlalchemy.generics.GUID(), nullable=True, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_annotation_id"], ["clip_annotation.id"], @@ -772,7 +970,13 @@ def upgrade() -> None: sa.Column("clip_annotation_id", sa.Integer(), nullable=False), sa.Column("clip_prediction_id", sa.Integer(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_annotation_id"], ["clip_annotation.id"], @@ -803,7 +1007,13 @@ def upgrade() -> None: sa.Column("clip_prediction_id", sa.Integer(), nullable=False), sa.Column("tag_id", sa.Integer(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_prediction_id"], ["clip_prediction.id"], @@ -832,7 +1042,13 @@ def upgrade() -> None: "evaluation_set_annotation", sa.Column("evaluation_set_id", sa.Integer(), nullable=False), sa.Column("clip_annotation_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_annotation_id"], ["clip_annotation.id"], @@ -862,7 +1078,13 @@ def upgrade() -> None: "model_run_prediction", sa.Column("model_run_id", sa.Integer(), nullable=False), sa.Column("clip_prediction_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_prediction_id"], ["clip_prediction.id"], @@ -899,7 +1121,13 @@ def upgrade() -> None: nullable=True, ), sa.Column("sound_event_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_annotation_id"], ["clip_annotation.id"], @@ -931,7 +1159,13 @@ def upgrade() -> None: sa.Column("sound_event_id", sa.Integer(), nullable=False), sa.Column("clip_prediction_id", sa.Integer(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_prediction_id"], ["clip_prediction.id"], @@ -958,7 +1192,13 @@ def upgrade() -> None: "user_run_prediction", sa.Column("user_run_id", sa.Integer(), nullable=False), sa.Column("clip_prediction_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_prediction_id"], ["clip_prediction.id"], @@ -1002,7 +1242,13 @@ def upgrade() -> None: ), nullable=False, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["annotation_task_id"], ["annotation_task.id"], @@ -1029,7 +1275,13 @@ def upgrade() -> None: sa.Column("clip_evaluation_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_evaluation_id"], ["clip_evaluation.id"], @@ -1055,7 +1307,13 @@ def upgrade() -> None: "sound_event_annotation_note", sa.Column("sound_event_annotation_id", sa.Integer(), nullable=False), sa.Column("note_id", sa.Integer(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["note_id"], ["note.id"], @@ -1091,7 +1349,13 @@ def upgrade() -> None: fastapi_users_db_sqlalchemy.generics.GUID(), nullable=True, ), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["created_by_id"], ["user.id"], @@ -1132,7 +1396,13 @@ def upgrade() -> None: sa.Column("target_id", sa.Integer(), nullable=True), sa.Column("affinity", sa.Float(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["clip_evaluation_id"], ["clip_evaluation.id"], @@ -1164,7 +1434,13 @@ def upgrade() -> None: sa.Column("sound_event_prediction_id", sa.Integer(), nullable=False), sa.Column("tag_id", sa.Integer(), nullable=False), sa.Column("score", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["sound_event_prediction_id"], ["sound_event_prediction.id"], @@ -1196,7 +1472,13 @@ def upgrade() -> None: sa.Column("sound_event_evaluation_id", sa.Integer(), nullable=False), sa.Column("feature_name_id", sa.Integer(), nullable=False), sa.Column("value", sa.Float(), nullable=False), - sa.Column("created_on", sa.DateTime(), nullable=False), + sa.Column( + "created_on", + sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), + nullable=False, + ), sa.ForeignKeyConstraint( ["feature_name_id"], ["feature_name.id"], diff --git a/back/src/whombat/models/base.py b/back/src/whombat/models/base.py index 58b532d6..5b961d44 100644 --- a/back/src/whombat/models/base.py +++ b/back/src/whombat/models/base.py @@ -7,6 +7,7 @@ import uuid from pathlib import Path +import sqlalchemy as sa import sqlalchemy.orm as orm import sqlalchemy.types as types from fastapi_users_db_sqlalchemy.generics import GUID @@ -82,6 +83,9 @@ class Base(AsyncAttrs, orm.MappedAsDataclass, orm.DeclarativeBase): uuid.UUID: GUID, Path: PathType, data.Geometry: GeometryType, + datetime.datetime: sa.DateTime().with_variant( + sa.TIMESTAMP(timezone=True), "postgresql" + ), } # This is needed to make the default values work with diff --git a/back/src/whombat/system/app.py b/back/src/whombat/system/app.py index a1ff8eeb..96d2b6c0 100644 --- a/back/src/whombat/system/app.py +++ b/back/src/whombat/system/app.py @@ -31,14 +31,12 @@ def create_app(settings: Settings) -> FastAPI: app = FastAPI(lifespan=functools.partial(lifespan, settings)) - allowed_origins = [ - f"http://{settings.host}:{settings.port}", - *settings.cors_origins, - ] + print("Creating app") + print("settings cors origins", settings.cors_origins) app.add_middleware( CORSMiddleware, - allow_origins=allowed_origins, + allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], diff --git a/back/src/whombat/system/settings.py b/back/src/whombat/system/settings.py index a6d8760e..74737150 100644 --- a/back/src/whombat/system/settings.py +++ b/back/src/whombat/system/settings.py @@ -101,14 +101,7 @@ class Settings(BaseSettings): Should be set to INFO in production. """ - cors_origins: list[str] = [ - "http://localhost", - "http://localhost:3000", - "http://localhost:5000", - "https://localhost", - "https://localhost:3000", - "https://localhost:5000", - ] + cors_origins: list[str] = ["*"] """Allowed origins for CORS.""" open_on_startup: bool = True diff --git a/back/uv.lock b/back/uv.lock index 9629fc8f..e69c2ecf 100644 --- a/back/uv.lock +++ b/back/uv.lock @@ -576,11 +576,11 @@ wheels = [ [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c4/91/e2df406fb4efacdf46871c25cde65d3c6ee5e173b7e5a4547a47bae91920/distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64", size = 609931 } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/41/9307e4f5f9976bc8b7fea0b66367734e8faf3ec84bc0d412d8cfabbb66cd/distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", size = 468850 }, + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, ] [[package]] @@ -2306,15 +2306,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.31.0" +version = "0.31.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/96/ee52d900f8e41cc35eaebfda76f3619c2e45b741f3ee957d6fe32be1b2aa/uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906", size = 77140 } +sdist = { url = "https://files.pythonhosted.org/packages/76/87/a886eda9ed495a3a4506d5a125cd07c54524280718c4969bde88f075fe98/uvicorn-0.31.1.tar.gz", hash = "sha256:f5167919867b161b7bcaf32646c6a94cdbd4c3aa2eb5c17d36bb9aa5cfd8c493", size = 77368 } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/12/206aca5442524d16be7702d08b453d7c274c86fd759266b1f709d4ef43ba/uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced", size = 63656 }, + { url = "https://files.pythonhosted.org/packages/3c/55/37407280931038a3f21fa0245d60edeaa76f18419581aa3f4397761c78df/uvicorn-0.31.1-py3-none-any.whl", hash = "sha256:adc42d9cac80cf3e51af97c1851648066841e7cfb6993a4ca8de29ac1548ed41", size = 63666 }, ] [package.optional-dependencies] diff --git a/compose-dev.yaml b/compose.dev.yaml similarity index 100% rename from compose-dev.yaml rename to compose.dev.yaml diff --git a/compose.prod.yaml b/compose.prod.yaml new file mode 100644 index 00000000..6d8d2854 --- /dev/null +++ b/compose.prod.yaml @@ -0,0 +1,99 @@ +services: + reverse-proxy: + image: traefik:v3.1 + command: + - "--api.insecure=true" + - "--providers.docker" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + ports: + - "${PORT}:80" + - "8080:8080" + volumes: + - letsencrypt:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock + whombat: + build: + context: . + volumes: + - ${AUDIO_DIR}:/audio + env_file: + - .env + environment: + - WHOMBAT_DB_DIALECT=postgresql + - WHOMBAT_DB_USERNAME=${POSTGRES_USER?Variable not set} + - WHOMBAT_DB_PASSWORD=${POSTGRES_PASSWORD?Variable not set} + - WHOMBAT_DB_NAME=${POSTGRES_DB?Variable not set} + - WHOMBAT_DB_URL= + - WHOMBAT_DB_HOST=db + - WHOMBAT_DB_PORT=5432 + - WHOMBAT_HOST=0.0.0.0 + - WHOMBAT_PORT=5000 + - WHOMBAT_AUDIO_DIR=/audio + deploy: + mode: replicated + replicas: 3 + restart: always + labels: + - "traefik.enable=true" + - "traefik.http.routers.whombat.rule=Host(`${DOMAIN?Variable not set}`)" + - "traefik.http.routers.whombat.entrypoints=web" + - "traefik.http.services.whombat.loadbalancer.server.port=5000" + - "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*" + depends_on: + db: + condition: service_healthy + prestart: + condition: service_completed_successfully + networks: + - public + - private + prestart: + build: + context: . + networks: + - private + depends_on: + db: + condition: service_healthy + command: alembic upgrade head + env_file: + - .env + environment: + - WHOMBAT_DB_DIALECT=postgresql + - WHOMBAT_DB_USERNAME=${POSTGRES_USER?Variable not set} + - WHOMBAT_DB_PASSWORD=${POSTGRES_PASSWORD?Variable not set} + - WHOMBAT_DB_NAME=${POSTGRES_DB?Variable not set} + - WHOMBAT_DB_URL= + - WHOMBAT_DB_HOST=db + - WHOMBAT_DB_PORT=5432 + - WHOMBAT_HOST=0.0.0.0 + - WHOMBAT_PORT=5000 + - WHOMBAT_AUDIO_DIR=/audio + db: + image: postgres + restart: always + user: postgres + volumes: + - db-data:/var/lib/postgresql/data + env_file: + - .env + environment: + - POSTGRES_DB=${POSTGRES_DB?Variable not set} + - POSTGRES_USER=${POSTGRES_USER?Variable not set} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set} + expose: + - 5432 + healthcheck: + test: ["CMD", "pg_isready"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - private +volumes: + db-data: + letsencrypt: +networks: + public: + private: From 0868e7dea0297cc9a20e86bf9d209a64964b5a01 Mon Sep 17 00:00:00 2001 From: mbsantiago Date: Wed, 9 Oct 2024 22:02:07 +0100 Subject: [PATCH 2/2] Example env file --- .env | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..417e8bdb --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +POSTGRES_DB=whombat +POSTGRES_USER=postgres +POSTGRES_PASSWORD=whombat +DOMAIN=localhost +AUDIO_DIR=/home/user/ +PORT=5000