diff --git a/backend/.env b/backend/.env index 0e1a2f9..5e44bf0 100644 --- a/backend/.env +++ b/backend/.env @@ -7,19 +7,19 @@ DOMAIN=localhost # Environment: local, staging, production ENVIRONMENT=local -PROJECT_NAME="FastAPI Supabase Template" +PROJECT_NAME="XTablo" # Backend BACKEND_CORS_ORIGINS="http://localhost" SECRET_KEY=local_dev -FIRST_SUPERUSER=admin@example.com -FIRST_SUPERUSER_PASSWORD=admin12345 +FIRST_SUPERUSER=baptiste@xtablo.com +FIRST_SUPERUSER_PASSWORD=admin12345_gxydlksjwqnlk # run `supabase status` # API URL -SUPABASE_URL=http://127.0.0.1:54321 +SUPABASE_URL=https://mhcafqvzbrrwvahpvvzd.supabase.co # service_role key -SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU +SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1oY2FmcXZ6YnJyd3ZhaHB2dnpkIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MTI0MTMyMSwiZXhwIjoyMDU2ODE3MzIxfQ.9r33CUsu6ZR4vyv4ed-UY6cLE1FZzSSxTNE8pFUKjN4 # Postgres # DB URL: postgresql://postgres:postgres@localhost:54322/postgres diff --git a/backend/.github/CODEOWNERS b/backend/.github/CODEOWNERS deleted file mode 100644 index f4748cf..0000000 --- a/backend/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @Atticuszz diff --git a/backend/.github/ISSUE_TEMPLATE/bug_report.md b/backend/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 3205926..0000000 --- a/backend/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - -- OS: [e.g. iOS] -- Browser [e.g. chrome, safari] -- Version [e.g. 22] - -**Smartphone (please complete the following information):** - -- Device: [e.g. iPhone6] -- OS: [e.g. iOS8.1] -- Browser [e.g. stock browser, safari] -- Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/backend/.github/ISSUE_TEMPLATE/feature_request.md b/backend/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/backend/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/backend/.github/dependabot.yml b/backend/.github/dependabot.yml deleted file mode 100644 index cd972a0..0000000 --- a/backend/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -updates: - # GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - commit-message: - prefix: ⬆ - # Python - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "daily" - commit-message: - prefix: ⬆ diff --git a/backend/.github/workflows/main.yml b/backend/.github/workflows/main.yml deleted file mode 100644 index 29fd90f..0000000 --- a/backend/.github/workflows/main.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Test And Release - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - test: - name: Run Tests / OS ${{ matrix.os }} / Python ${{ matrix.python-version }} - strategy: - matrix: - os: [ ubuntu-latest ] - python-version: ["3.11", "3.12", "3.13"] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v5 - with: - enable-cache: true - - name: Install brew - run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - - - name: Install Supabase - run: | - echo >> /home/runner/.bashrc - echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/runner/.bashrc - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - HOMEBREW_NO_INSTALL_CLEANUP=1 - brew install supabase/tap/supabase - bash scripts/update-env.sh - uv python install ${{ matrix.python-version }} - cd backend - uv sync --python ${{ matrix.python-version }} --all-extras --dev - uv run bash scripts/pre-start.sh - uv run bash scripts/tests-start.sh - - release: - name: Bump Version and Release - needs: test - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/') - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install uv - uses: astral-sh/setup-uv@v5 - with: - enable-cache: true - - - name: Install dependencies - run: uv sync --dev - - - name: Generate a changelog - env: - ATTICUS_PAT: ${{ secrets.ATTICUS_PAT }} - run: uv run git-cliff -vv --latest --strip header --github-token "$ATTICUS_PAT" -o CHANGES.md - - - name: Release - uses: softprops/action-gh-release@v2 - with: - body_path: CHANGES.md - token: ${{ secrets.GITHUB_TOKEN }} - -# Reference -# 1. https://docs.astral.sh/uv/guides/integration/github/#syncing-and-running -# 2. https://github.com/Kludex/python-template/blob/main/.github/workflows/main.yml -# 3. https://github.com/softprops/action-gh-release/tree/master/ diff --git a/backend/CHANGELOG.md b/backend/CHANGELOG.md deleted file mode 100644 index 62b11da..0000000 --- a/backend/CHANGELOG.md +++ /dev/null @@ -1,138 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -## unreleased - -### 🐛 Bug Fixes - -- Lint error - -### 🚜 Refactor - -- Move src/app to top level of dir as app/ - -### 📚 Documentation - -- Add docs dir for mkdocs - -### ⚙️ Miscellaneous Tasks - -- Vscode import -- Remove semantic-release and add mkdocs build -- *(git)* Pre-commit upgrade to ruff -- Add scripts for test and lint etc. - -## 0.4.1 - 2024-09-18 - -### 🐛 Bug Fixes - -- Remove supabase-py-async with supabase-py -- Merge pull request #139 from Atticuszz/work-with-supabase-py in #139 - -### ⚙️ Miscellaneous Tasks - -- Update README.md -- Remove ci - -## 0.4.0 - 2024-08-30 - -### 🚀 Features - -- Use uv to manage venvs - -### 🐛 Bug Fixes - -- Remove ci -- Ci docker push -- Ci - -## 0.3.2 - 2024-07-30 - -### 🐛 Bug Fixes - -- Update deps - -### ⚙️ Miscellaneous Tasks - -- Update README.md - -## 0.3.1 - 2024-01-15 - -### 🐛 Bug Fixes - -- Bump version to 0.3.1 - -### ⚙️ Miscellaneous Tasks - -- Delete .idea directory -- Update README.md - -## 0.3.0 - 2024-01-13 - -### 🚀 Features - -- Add Dockerfile -- Add Dockerfile and image push ci - -### ⚙️ Miscellaneous Tasks - -- Update README.md -- RUN pre-commit-hooks -- Add Dockerfile - -## 0.2.1 - 2024-01-13 - -### ⚙️ Miscellaneous Tasks - -- Update README.md -- Add latest_changes.yml in #22 -- Update latest_changes.yml -- Update ci.yml - -## 0.2.0 - 2024-01-13 - -### 🚀 Features - -- Release in #21 - -## 0.1.0 - 2024-01-13 - -### 🚀 Features - -- Update ci and README.md -- Release in #20 - -### 🐛 Bug Fixes - -- Add latest_changes.yml - -### ⚙️ Miscellaneous Tasks - -- Update ci - -## 0.0.2 - 2024-01-13 - -### ⚙️ Miscellaneous Tasks - -- Remove latest-changes: ci -- Set pro-commit-hooks autofix_prs -> True -- Update ci -- Update README.md - -### Bugs - -- Failed to auth as dep on new user by access token - -### Upgrade - -- Release 0.1.0 - -## 0.0.1 - 2024-01-11 - -### ⚙️ Miscellaneous Tasks - -- Update ci,add changelog as pushed ,Publish to GitHub Releases as test passed and merged from PR -- Update ci - - diff --git a/backend/LICENSE b/backend/LICENSE deleted file mode 100644 index 07e5fd9..0000000 --- a/backend/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Atticus Zeller - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/backend/backend/app/core/auth.py b/backend/backend/app/core/auth.py index b819b52..2df7722 100644 --- a/backend/backend/app/core/auth.py +++ b/backend/backend/app/core/auth.py @@ -35,7 +35,7 @@ TokenDep = Annotated[str, Depends(reusable_oauth2)] async def get_current_user(token: TokenDep, super_client: SuperClient) -> UserIn: - """get current user from token and validate same time""" + """get current user from token and validate same time""" user_rsp = await super_client.auth.get_user(jwt=token) if not user_rsp: logging.error("User not found") diff --git a/backend/backend/app/main.py b/backend/backend/app/main.py index 9d75b12..bfe3ccb 100644 --- a/backend/backend/app/main.py +++ b/backend/backend/app/main.py @@ -2,6 +2,8 @@ import logging from collections.abc import AsyncGenerator from typing import Any +from app.core.auth import AsyncClient +from app.schemas.auth import UserInDB import uvicorn from fastapi import FastAPI from fastapi.concurrency import asynccontextmanager @@ -53,6 +55,10 @@ app.include_router(api_router, prefix=settings.API_V1_STR) async def read_root() -> dict[str, str]: return {"Hello": "World"} +@app.get("/users", tags=["root"]) +async def get_users(super_client): + users = await super_client.auth.admin.list_users() + return users # Logger def timestamp_log_config(uvicorn_log_config: dict[str, Any]) -> dict[str, Any]: diff --git a/backend/backend/pyproject.toml b/backend/backend/pyproject.toml index 6f7eadf..16d8eb4 100644 --- a/backend/backend/pyproject.toml +++ b/backend/backend/pyproject.toml @@ -14,6 +14,9 @@ dependencies = [ "tenacity>=9.0.0", "psycopg2-binary>=2.9.10", "psycopg>=3.2.4", + "coverage>=7.6.10", + "pytest>=8.3.4", + "faker>=35.0.0", ] [dependency-groups] diff --git a/backend/backend/supabase/.gitignore b/backend/backend/supabase/.gitignore new file mode 100644 index 0000000..ad9264f --- /dev/null +++ b/backend/backend/supabase/.gitignore @@ -0,0 +1,8 @@ +# Supabase +.branches +.temp + +# dotenvx +.env.keys +.env.local +.env.*.local diff --git a/backend/supabase/config.toml b/backend/backend/supabase/config.toml similarity index 74% rename from backend/supabase/config.toml rename to backend/backend/supabase/config.toml index 995f49b..c760d0d 100644 --- a/backend/supabase/config.toml +++ b/backend/backend/supabase/config.toml @@ -1,21 +1,24 @@ +# For detailed configuration reference documentation, visit: +# https://supabase.com/docs/guides/local-development/cli/config # A string used to distinguish different Supabase projects on the same host. Defaults to the # working directory name when running `supabase init`. -project_id = "test" +project_id = "backend" [api] enabled = true # Port to use for the API URL. port = 54321 # Schemas to expose in your API. Tables, views and stored procedures in this schema will get API -# endpoints. `public` is always included. +# endpoints. `public` and `graphql_public` schemas are included by default. schemas = ["public", "graphql_public"] -# Extra schemas to add to the search_path of every request. `public` is always included. +# Extra schemas to add to the search_path of every request. extra_search_path = ["public", "extensions"] # The maximum number of rows returns from a view, table, or stored procedure. Limits payload size # for accidental or malicious requests. max_rows = 1000 [api.tls] +# Enable HTTPS endpoints locally using a self-signed certificate. enabled = false [db] @@ -39,13 +42,20 @@ default_pool_size = 20 # Maximum number of client connections allowed. max_client_conn = 100 +# [db.vault] +# secret_key = "env(SECRET_VALUE)" + +[db.migrations] +# Specifies an ordered list of schema files that describe your database. +# Supports glob patterns relative to supabase directory: "./schemas/*.sql" +schema_paths = [] + [db.seed] # If enabled, seeds the database after migrations during a db reset. enabled = true # Specifies an ordered list of seed files to load during db reset. -# Supports glob patterns relative to supabase directory. For example: -# sql_paths = ['./seeds/*.sql', '../project-src/seeds/*-load-testing.sql'] -sql_paths = ['./seed.sql'] +# Supports glob patterns relative to supabase directory: "./seeds/*.sql" +sql_paths = ["./seed.sql"] [realtime] enabled = true @@ -72,14 +82,17 @@ port = 54324 # Uncomment to expose additional ports for testing user applications that send emails. # smtp_port = 54325 # pop3_port = 54326 +# admin_email = "admin@email.com" +# sender_name = "Admin" [storage] enabled = true # The maximum file size allowed (e.g. "5MB", "500KB"). file_size_limit = "50MiB" -[storage.image_transformation] -enabled = true +# Image transformation API is available to Supabase Pro plan. +# [storage.image_transformation] +# enabled = true # Uncomment to configure local storage buckets # [storage.buckets.images] @@ -108,6 +121,32 @@ enable_signup = true enable_anonymous_sign_ins = false # Allow/disallow testing manual linking of accounts enable_manual_linking = false +# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more. +minimum_password_length = 6 +# Passwords that do not meet the following requirements will be rejected as weak. Supported values +# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols` +password_requirements = "" + +[auth.rate_limit] +# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled. +email_sent = 2 +# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled. +sms_sent = 30 +# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true. +anonymous_users = 30 +# Number of sessions that can be refreshed in a 5 minute interval per IP address. +token_refresh = 150 +# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users). +sign_in_sign_ups = 30 +# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address. +token_verifications = 30 + + +# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`. +# [auth.captcha] +# enabled = true +# provider = "hcaptcha" +# secret = "" [auth.email] # Allow/disallow new user signups via email to your project. @@ -128,6 +167,7 @@ otp_expiry = 3600 # Use a production-ready SMTP server # [auth.email.smtp] +# enabled = true # host = "smtp.sendgrid.net" # port = 587 # user = "apikey" @@ -142,11 +182,11 @@ otp_expiry = 3600 [auth.sms] # Allow/disallow new user signups via SMS to your project. -enable_signup = true +enable_signup = false # If enabled, users need to confirm their phone number before signing in. enable_confirmations = false # Template for sending OTP to users -template = "Your code is {{ .Code }} ." +template = "Your code is {{ .Code }}" # Controls the minimum amount of time that must pass before sending another sms otp. max_frequency = "5s" @@ -174,24 +214,25 @@ message_service_sid = "" # DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" +# Multi-factor-authentication is available to Supabase Pro plan. [auth.mfa] # Control how many MFA factors can be enrolled at once per user. max_enrolled_factors = 10 -# Control use of MFA via App Authenticator (TOTP) +# Control MFA via App Authenticator (TOTP) [auth.mfa.totp] -enroll_enabled = true -verify_enabled = true +enroll_enabled = false +verify_enabled = false -# Configure Multi-factor-authentication via Phone Messaging -# [auth.mfa.phone] -# enroll_enabled = true -# verify_enabled = true -# otp_length = 6 -# template = "Your code is {{ .Code }} ." -# max_frequency = "10s" +# Configure MFA via Phone Messaging +[auth.mfa.phone] +enroll_enabled = false +verify_enabled = false +otp_length = 6 +template = "Your code is {{ .Code }}" +max_frequency = "5s" -# Configure Multi-factor-authentication via WebAuthn +# Configure MFA via WebAuthn # [auth.mfa.web_authn] # enroll_enabled = true # verify_enabled = true @@ -229,13 +270,23 @@ enabled = false # user_pool_id = "my-user-pool-id" # user_pool_region = "us-east-1" +# Use Clerk as a third-party provider alongside Supabase Auth. +[auth.third_party.clerk] +enabled = false +# Obtain from https://clerk.com/setup/supabase +# domain = "example.clerk.accounts.dev" + [edge_runtime] enabled = true # Configure one of the supported request policies: `oneshot`, `per_worker`. # Use `oneshot` for hot reload, or `per_worker` for load testing. policy = "oneshot" +# Port to attach the Chrome inspector for debugging edge functions. inspector_port = 8083 +# [edge_runtime.secrets] +# secret_key = "env(SECRET_VALUE)" + [analytics] enabled = true port = 54327 diff --git a/backend/backend/uv.lock b/backend/backend/uv.lock index 5a5ceab..f7204d1 100644 --- a/backend/backend/uv.lock +++ b/backend/backend/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.10" [[package]] @@ -144,11 +145,14 @@ version = "0.4.1" source = { editable = "." } dependencies = [ { name = "alembic" }, + { name = "coverage" }, + { name = "faker" }, { name = "fastapi", extra = ["standard"] }, { name = "psycopg" }, { name = "psycopg2-binary" }, { name = "pydantic", extra = ["email"] }, { name = "pydantic-settings" }, + { name = "pytest" }, { name = "python-multipart" }, { name = "sqlmodel" }, { name = "supabase" }, @@ -170,11 +174,14 @@ dev = [ [package.metadata] requires-dist = [ { name = "alembic", specifier = ">=1.14.0" }, + { name = "coverage", specifier = ">=7.6.10" }, + { name = "faker", specifier = ">=35.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.112.2" }, { name = "psycopg", specifier = ">=3.2.4" }, { name = "psycopg2-binary", specifier = ">=2.9.10" }, { name = "pydantic", extras = ["email"], specifier = ">=2.8.2" }, { name = "pydantic-settings", specifier = ">=2.4.0" }, + { name = "pytest", specifier = ">=8.3.4" }, { name = "python-multipart", specifier = ">=0.0.9" }, { name = "sqlmodel", specifier = ">=0.0.22" }, { name = "supabase", specifier = ">=2.7.4" }, diff --git a/backend/supabase/.gitignore b/backend/supabase/.gitignore deleted file mode 100644 index a3ad880..0000000 --- a/backend/supabase/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Supabase -.branches -.temp -.env diff --git a/backend/uv.lock b/backend/uv.lock index 3ea0063..1df0265 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 1 -requires-python = ">=3.12" +requires-python = ">=3.13" [[package]] name = "fastapi-supabase-template"