diff --git a/.gitignore b/.gitignore index be16fd8..722d5e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ .vscode -.mypy_cache -poetry.lock diff --git a/cookiecutter.json b/cookiecutter.json deleted file mode 100644 index fc0e6fa..0000000 --- a/cookiecutter.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "project_name": "Base Project", - "project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '-') }}", - "domain_main": "{{cookiecutter.project_slug}}.com", - "domain_staging": "stag.{{cookiecutter.domain_main}}", - - "docker_swarm_stack_name_main": "{{cookiecutter.domain_main|replace('.', '-')}}", - "docker_swarm_stack_name_staging": "{{cookiecutter.domain_staging|replace('.', '-')}}", - - "secret_key": "changethis", - "first_superuser": "admin@{{cookiecutter.domain_main}}", - "first_superuser_password": "changethis", - "backend_cors_origins": "[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://dev.{{cookiecutter.domain_main}}\", \"https://{{cookiecutter.domain_staging}}\", \"https://{{cookiecutter.domain_main}}\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]", - "smtp_port": "587", - "smtp_host": "", - "smtp_user": "", - "smtp_password": "", - "smtp_emails_from_email": "info@{{cookiecutter.domain_main}}", - - "postgres_password": "changethis", - "pgadmin_default_user": "{{cookiecutter.first_superuser}}", - "pgadmin_default_user_password": "{{cookiecutter.first_superuser_password}}", - - "traefik_constraint_tag": "{{cookiecutter.domain_main}}", - "traefik_constraint_tag_staging": "{{cookiecutter.domain_staging}}", - "traefik_public_constraint_tag": "traefik-public", - - "flower_auth": "admin:{{cookiecutter.first_superuser_password}}", - - "sentry_dsn": "", - - "docker_image_prefix": "", - - "docker_image_backend": "{{cookiecutter.docker_image_prefix}}backend", - "docker_image_celeryworker": "{{cookiecutter.docker_image_prefix}}celeryworker", - "docker_image_frontend": "{{cookiecutter.docker_image_prefix}}frontend", - - "_copy_without_render": [ - "frontend/src/**/*.html", - "frontend/src/**/*.vue", - "frontend/node_modules/*", - "backend/app/app/email-templates/**" - ] -} diff --git a/src/.copier/.copier-answers.yml.jinja b/src/.copier/.copier-answers.yml.jinja new file mode 100644 index 0000000..0028a23 --- /dev/null +++ b/src/.copier/.copier-answers.yml.jinja @@ -0,0 +1 @@ +{{ _copier_answers|to_json -}} diff --git a/src/.copier/update_dotenv.py b/src/.copier/update_dotenv.py new file mode 100644 index 0000000..1eab4c8 --- /dev/null +++ b/src/.copier/update_dotenv.py @@ -0,0 +1,22 @@ +from pathlib import Path +import json + +# Update the .env file with the answers from the .copier-answers.yml file +# without using Jinja2 templates in the .env file, this way the code works as is +# without needing Copier, but if Copier is used, the .env file will be updated +root_path = Path(__file__).parent.parent +answers_path = Path(__file__).parent / ".copier-answers.yml" +answers = json.loads(answers_path.read_text()) +env_path = root_path / ".env" +env_content = env_path.read_text() +lines = [] +for line in env_content.splitlines(): + for key, value in answers.items(): + upper_key = key.upper() + if line.startswith(f"{upper_key}="): + new_line = line.replace(line, f"{upper_key}={value}") + lines.append(new_line) + break + else: + lines.append(line) +env_path.write_text("\n".join(lines)) diff --git a/src/.env b/src/.env index 78bf4c6..2cf8e64 100644 --- a/src/.env +++ b/src/.env @@ -2,8 +2,41 @@ DOMAIN=localhost # DOMAIN=localhost.tiangolo.com -STACK_NAME=full-stack-fastapi-postgresql +PROJECT_NAME="FastAPI Project" +STACK_NAME=fastapi-project + +# Backend +BACKEND_CORS_ORIGINS="[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]" +SECRET_KEY=changethis +FIRST_SUPERUSER=admin@example.com +FIRST_SUPERUSER_PASSWORD=changethis +SMTP_HOST= +SMTP_USER= +SMTP_PASSWORD= +EMAILS_FROM_EMAIL=info@example.com +SMTP_TLS=True +SMTP_PORT=587 + +USERS_OPEN_REGISTRATION=False + +# Postgres +POSTGRES_SERVER=db +POSTGRES_USER=postgres +POSTGRES_DB=app +POSTGRES_PASSWORD=changethis + +# PgAdmin +PGADMIN_DEFAULT_EMAIL=admin@example.com +PGADMIN_DEFAULT_PASSWORD=changethis +PGADMIN_LISTEN_PORT=5050 + +SENTRY_DSN= + +# Flower +FLOWER_BASIC_AUTH= + +# Traefik TRAEFIK_PUBLIC_NETWORK=traefik-public TRAEFIK_TAG=traefik TRAEFIK_PUBLIC_TAG=traefik-public @@ -13,34 +46,3 @@ DOCKER_IMAGE_BACKEND=backend DOCKER_IMAGE_CELERYWORKER=celery DOCKER_IMAGE_FRONTEND=frontend DOCKER_IMAGE_NEW_FRONTEND=new-frontend - -# Backend -BACKEND_CORS_ORIGINS="[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]" -PROJECT_NAME="FastAPI Project" -SECRET_KEY=changethis -FIRST_SUPERUSER=admin@example.com -FIRST_SUPERUSER_PASSWORD=changethis -SMTP_TLS=True -SMTP_PORT=587 -SMTP_HOST= -SMTP_USER= -SMTP_PASSWORD= -EMAILS_FROM_EMAIL=info@example.com - -USERS_OPEN_REGISTRATION=False - -SENTRY_DSN= - -# Flower -FLOWER_BASIC_AUTH= - -# Postgres -POSTGRES_SERVER=db -POSTGRES_USER=postgres -POSTGRES_PASSWORD=changethis -POSTGRES_DB=app - -# PgAdmin -PGADMIN_LISTEN_PORT=5050 -PGADMIN_DEFAULT_EMAIL=admin@example.com -PGADMIN_DEFAULT_PASSWORD=changethis diff --git a/src/backend/.gitignore b/src/backend/.gitignore index 8078a84..9660d71 100644 --- a/src/backend/.gitignore +++ b/src/backend/.gitignore @@ -4,3 +4,6 @@ app.egg-info .mypy_cache .coverage htmlcov +poetry.lock +.cache +.venv diff --git a/src/backend/app/tests/.gitignore b/src/backend/app/tests/.gitignore deleted file mode 100755 index 16d3c4d..0000000 --- a/src/backend/app/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.cache diff --git a/src/cookiecutter-config-file.yml b/src/cookiecutter-config-file.yml deleted file mode 100644 index b0e7dd2..0000000 --- a/src/cookiecutter-config-file.yml +++ /dev/null @@ -1,30 +0,0 @@ -default_context: - project_name: '{{ cookiecutter.project_name }}' - project_slug: '{{ cookiecutter.project_slug }}' - domain_main: '{{ cookiecutter.domain_main }}' - domain_staging: '{{ cookiecutter.domain_staging }}' - docker_swarm_stack_name_main: '{{ cookiecutter.docker_swarm_stack_name_main }}' - docker_swarm_stack_name_staging: '{{ cookiecutter.docker_swarm_stack_name_staging }}' - secret_key: '{{ cookiecutter.secret_key }}' - first_superuser: '{{ cookiecutter.first_superuser }}' - first_superuser_password: '{{ cookiecutter.first_superuser_password }}' - backend_cors_origins: '{{ cookiecutter.backend_cors_origins }}' - smtp_port: '{{ cookiecutter.smtp_port }}' - smtp_host: '{{ cookiecutter.smtp_host }}' - smtp_user: '{{ cookiecutter.smtp_user }}' - smtp_password: '{{ cookiecutter.smtp_password }}' - smtp_emails_from_email: '{{ cookiecutter.smtp_emails_from_email }}' - postgres_password: '{{ cookiecutter.postgres_password }}' - pgadmin_default_user: '{{ cookiecutter.pgadmin_default_user }}' - pgadmin_default_user_password: '{{ cookiecutter.pgadmin_default_user_password }}' - traefik_constraint_tag: '{{ cookiecutter.traefik_constraint_tag }}' - traefik_constraint_tag_staging: '{{ cookiecutter.traefik_constraint_tag_staging }}' - traefik_public_constraint_tag: '{{ cookiecutter.traefik_public_constraint_tag }}' - flower_auth: '{{ cookiecutter.flower_auth }}' - sentry_dsn: '{{ cookiecutter.sentry_dsn }}' - docker_image_prefix: '{{ cookiecutter.docker_image_prefix }}' - docker_image_backend: '{{ cookiecutter.docker_image_backend }}' - docker_image_celeryworker: '{{ cookiecutter.docker_image_celeryworker }}' - docker_image_frontend: '{{ cookiecutter.docker_image_frontend }}' - _copy_without_render: [frontend/src/**/*.html, frontend/src/**/*.vue, frontend/node_modules/*, backend/app/app/email-templates/**] - _template: ./ diff --git a/src/copier.yml b/src/copier.yml new file mode 100644 index 0000000..743b5ff --- /dev/null +++ b/src/copier.yml @@ -0,0 +1,119 @@ +domain: + type: str + help: | + Which domain name to use for the project, by default, + localhost, but you should change it later (in .env) + default: localhost + +project_name: + type: str + help: The name of the project, shown to API users (in .env) + default: FastAPI Project + +stack_name: + type: str + help: The name of the stack used for Docker Compose labels (no spaces) (in .env) + default: fastapi-project + +secret_key: + type: str + help: | + 'The secret key for the project, used for security, + stored in .env, you can generate one with: + python -c "import secrets; print(secrets.token_urlsafe(32))"' + default: changethis + +first_superuser: + type: str + help: The email of the first superuser (in .env) + default: admin@example.com + +first_superuser_password: + type: str + help: The password of the first superuser (in .env) + default: changethis + +smtp_host: + type: str + help: The SMTP server host to send emails, you can set it later in .env + default: "" + +smtp_user: + type: str + help: The SMTP server user to send emails, you can set it later in .env + default: "" + +smtp_password: + type: str + help: The SMTP server password to send emails, you can set it later in .env + default: "" + +emails_from_email: + type: str + help: The email account to send emails from, you can set it later in .env + default: info@example.com + +postgres_password: + type: str + help: | + 'The password for the PostgreSQL database, stored in .env, + you can generate one with: + python -c "import secrets; print(secrets.token_urlsafe(32))"' + default: changethis + +pgadmin_default_email: + type: str + help: The default user email for pgAdmin, you can set it later in .env + default: admin@example.com + +pgadmin_default_password: + type: str + help: The default user password for pgAdmin, stored in .env + default: changethis + +sentry_dsn: + type: str + help: The DSN for Sentry, if you are using it, you can set it later in .env + default: "" + +_exclude: + # Global + - .vscode + - .mypy_cache + - poetry.lock + # Python + - __pycache__ + - app.egg-info + - "*.pyc" + - .mypy_cache + - .coverage + - htmlcov + - poetry.lock + - .cache + - .venv + # Frontend + # Logs + - logs + - "*.log" + - npm-debug.log* + - yarn-debug.log* + - yarn-error.log* + - pnpm-debug.log* + - lerna-debug.log* + - node_modules + - dist + - dist-ssr + - "*.local" + # Editor directories and files + - .idea + - .DS_Store + - "*.suo" + - "*.ntvs*" + - "*.njsproj" + - "*.sln" + - "*.sw?" + +_answers_file: .copier/.copier-answers.yml + +_tasks: + - "python .copier/update_dotenv.py"