diff --git a/.claude/settings.json b/.claude/settings.json index a294224..dc9a94c 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -4,7 +4,7 @@ { "hooks": [ { - "command": "bun fix --skip=correctness/noUnusedImports", + "command": "cd frontend && bun run fix --skip=correctness/noUnusedImports", "type": "command" } ], diff --git a/.copier/backend.yml b/.copier/backend.yml new file mode 100644 index 0000000..ca85eb1 --- /dev/null +++ b/.copier/backend.yml @@ -0,0 +1,17 @@ +_commit: v0.3.2 +_src_path: https://git.kotikot.com/templates/backend-python.git +author_email: h@kotikot.com +author_name: h +backend_services: +- api +- kurigram_userbot +database: postgres +dynamic_config: false +install_deps: false +layout: part +project_description: A read-only Telegram client that keeps everything +project_name: beavergram +project_slug: beavergram +serve_spa: true +use_llm: false +use_redis: false diff --git a/.copier/caddy.yml b/.copier/caddy.yml new file mode 100644 index 0000000..680cbcd --- /dev/null +++ b/.copier/caddy.yml @@ -0,0 +1,5 @@ +_commit: v0.1.2 +_src_path: https://git.kotikot.com/templates/caddy.git +project_slug: beavergram +routes: +- api diff --git a/.copier/frontend.yml b/.copier/frontend.yml new file mode 100644 index 0000000..5fa1dc9 --- /dev/null +++ b/.copier/frontend.yml @@ -0,0 +1,9 @@ +_commit: v0.3.1 +_src_path: https://git.kotikot.com/templates/frontend-svelte.git +include_impeccable: false +install_deps: false +layout: part +project_name: beavergram +project_slug: beavergram +serve: api +ui_library: none diff --git a/.copier/infra.yml b/.copier/infra.yml new file mode 100644 index 0000000..210c996 --- /dev/null +++ b/.copier/infra.yml @@ -0,0 +1,9 @@ +_commit: v0.3.1 +_src_path: https://git.kotikot.com/templates/infra.git +init_git: false +layout: parts +parts: +- backend +- frontend +project_description: A read-only Telegram client that keeps everything +project_name: beavergram diff --git a/.env.example b/.env.example index e6d10ee..7643838 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,2 @@ -COMPOSE_PROFILES=db,userbot,api -RUN_ENVIRONMENT=prod - -# Leave empty for *.localhost. -FRONTEND_DEV_HOST= - -DB__HOST=postgres -DB__PORT=5432 -DB__USER=beavergram -DB__PASSWORD=beavergram -DB__DB_NAME=beavergram -DB__MIN_POOL_SIZE=5 -DB__MAX_POOL_SIZE=20 -DB__SCRIPTS_CONNECTION_URL=postgresql://beavergram:beavergram@localhost:5433/beavergram - -STORAGE__ROOT=./storage +COMPOSE_FILE=docker-compose.yml:backend/docker-compose.override.yml:frontend/docker-compose.override.yml +COMPOSE_PROFILES=external,services diff --git a/.gitignore b/.gitignore index f4c1d52..ca09c00 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ -.idea -docker-compose.override.yml .env +.env.* +!.env.example +docker-compose.override.yml +.DS_Store +.idea docs storage -backend/sessions diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eeefa53..e051dab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,31 +1,27 @@ repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.15 - hooks: - - id: ruff-check - types_or: [ python, pyi ] - args: [ --fix ] - - id: ruff-format - types_or: [ python, pyi ] - - repo: local hooks: - - id: ultracite - name: ultracite - entry: bash -c 'cd frontend && bun x ultracite fix' + - id: backend-fmt + name: backend fmt + entry: make -C backend fmt + language: system + files: ^backend/ + pass_filenames: false + - id: backend-check + name: backend check + entry: make -C backend check + language: system + files: ^backend/ + pass_filenames: false + - id: frontend-fmt + name: frontend fmt + entry: make -C frontend fmt language: system files: ^frontend/ pass_filenames: false - - - id: svelte-check - name: svelte check - entry: bash -c 'cd frontend && bun check' + - id: frontend-check + name: frontend check + entry: make -C frontend check language: system files: ^frontend/ pass_filenames: false - - - id: ty - name: ty check - entry: uvx ty check - language: python - types_or: [ python, pyi ] diff --git a/.claude/CLAUDE.md b/CLAUDE.md similarity index 88% rename from .claude/CLAUDE.md rename to CLAUDE.md index db134bb..9333590 100644 --- a/.claude/CLAUDE.md +++ b/CLAUDE.md @@ -6,10 +6,11 @@ - **Reusability**: Create reusable components and functions - **Less Code = Less Debt**: Minimize code footprint - **NEVER write comments** - code should be self-documenting +- **Docstrings ONLY if explicitly asked** ## Checking commands After writing code, always run: ```shell -bun check # svelte-check -bun fix # biome linter +make fmt +make check ``` diff --git a/Makefile b/Makefile index d2a32b8..59a9fb0 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,29 @@ -.PHONY: recreate down restart rebuild deploy migrate session-create frontend +PARTS := $(patsubst %/Makefile,%,$(wildcard */Makefile)) + +.PHONY: env recreate rebuild restart logs down deploy fmt check build pre-deploy post-deploy + +env: + @test -f .env || awk 'FNR == 1 && NR > 1 { print "" } 1' .env.example $(addsuffix /.env.example,$(PARTS)) > .env + @for part in $(PARTS); do test -f $$part/docker-compose.override.yml || cp $$part/docker-compose.override.yml.example $$part/docker-compose.override.yml; done recreate: docker compose up -d --force-recreate +rebuild: build + docker compose up -d + +restart: + docker compose restart + +logs: + docker compose logs -f --tail=100 + down: docker compose down -restart: - $(MAKE) recreate - -rebuild: - docker compose build +deploy: pre-deploy docker compose up -d + $(MAKE) post-deploy -frontend: - docker compose run --rm --no-deps frontend-dev sh -c "bun install && bun run build" - -deploy: - $(MAKE) frontend - $(MAKE) rebuild - -migrate: - docker compose --profile db --profile migrate run --rm migrator $(filter-out $@,$(MAKECMDGOALS)) - -session-create: - cd backend && uv run python scripts/session/create.py - -%: - @: +fmt check build pre-deploy post-deploy: + @for part in $(PARTS); do $(MAKE) -C $$part $@ || exit 1; done diff --git a/README.md b/README.md index c056d78..cf02618 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Nothing is ever deleted from the archive. - `backend/` - `userbot` (kurigram, the capture loop and jobs) and `api` (FastAPI: the web API, the MCP server, and the built frontend as static files). - `frontend/` - SvelteKit, `adapter-static`; a chat client over the archive: folders, chat list, thread with media, versions and the deleted messages inline, search, stories, presence graphs. -- `docker-compose.yml` - Postgres with TimescaleDB, `userbot`, `api`; profiles `db,userbot,api`. +- `docker-compose.yml` - includes `backend/` (Postgres with TimescaleDB, `userbot`, `api`) and `frontend/` (the dev server); profiles `external` and `services`. ## MCP @@ -28,18 +28,17 @@ Read-only: `search_messages_tool`, `list_chats`, `get_chat_history` (with delete ## Run ```sh -cp .env.example .env # DB__*, STORAGE__ROOT, profiles -cp backend/.env.example backend/.env # TG__*, API__*, AUTH__TOKEN -make session-create # log the account in once; the session file stays in backend/sessions -make migrate upgrade head -make deploy # build the frontend, build and start the containers +make env # .env and docker-compose.override.yml from the examples +make -C backend session # log the account in once; the session file stays in backend/sessions +make deploy # build what changed, migrate, start the containers ``` -The web client and the MCP endpoint are served by `api`; the bearer for both is `AUTH__TOKEN`. +`COMPOSE_PROFILES` in `.env` selects what runs on the machine, `docker-compose.override.yml` in each part holds the published ports and the `caddy` network aliases. The web client and the MCP endpoint are served by `api`; the bearer for both is `AUTH__TOKEN`. ## Develop ```sh -cd backend && uv sync && uv run ruff check && uvx ty check src -cd frontend && bun install && bun run dev && bun run check +make fmt +make check +make -C frontend dev ``` diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..fb3ff32 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,7 @@ +.venv +.env +__pycache__ +*.pyc +.ruff_cache +.pytest_cache +sessions diff --git a/backend/.env.example b/backend/.env.example index b4e765e..29b6fb7 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,14 +1,27 @@ +RUN_ENVIRONMENT=prod +TZ=UTC + +LOG__LEVEL=INFO +LOG__LEVEL_EXTERNAL=WARNING +LOG__SHOW_TIME=false +LOG__CONSOLE_WIDTH=150 + +DB__HOST=postgres +DB__PORT=5432 +DB__USER=beavergram +DB__PASSWORD=beavergram +DB__DB_NAME=beavergram +DB__MIN_POOL_SIZE=5 +DB__MAX_POOL_SIZE=20 +DB__SCRIPTS_CONNECTION_URL=postgresql://beavergram:beavergram@localhost:5432/beavergram + TG__SESSION_NAME=beavergram TG__SESSIONS_DIR=sessions API__HOST=0.0.0.0 API__PORT=8080 -AUTH__TOKEN= +AUTH__TOKEN= +STORAGE__ROOT=./storage STORAGE__SHARD_DEPTH=2 - -LOG__LEVEL=INFO -LOG__LEVEL_EXTERNAL=WARNING -LOG__SHOW_TIME=false -LOG__CONSOLE_WIDTH=150 diff --git a/backend/CLAUDE.md b/backend/CLAUDE.md new file mode 100644 index 0000000..2cabb83 --- /dev/null +++ b/backend/CLAUDE.md @@ -0,0 +1,7 @@ +## Checking commands +After writing code, always run from `backend/`: +```shell +ruff format +ruff check --fix +ty check +``` diff --git a/backend/Dockerfile b/backend/Dockerfile index 57c7cfa..89df132 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,5 +1,7 @@ FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +RUN apt-get update && apt-get install -y build-essential && rm -rf /var/lib/apt/lists/* + WORKDIR /app ENV PATH="/app/.venv/bin:$PATH" \ @@ -7,10 +9,6 @@ ENV PATH="/app/.venv/bin:$PATH" \ UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy -RUN apt-get update \ - && apt-get install -y --no-install-recommends build-essential \ - && rm -rf /var/lib/apt/lists/* - COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-install-project --no-dev @@ -20,4 +18,7 @@ RUN uv sync --frozen --no-dev COPY alembic.ini ./ COPY migrations ./migrations +COPY scripts ./scripts + ENTRYPOINT ["python", "-m"] +CMD ["api"] diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 0000000..3cb1fdb --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,47 @@ +COMPOSE := cd .. && docker compose +IMAGE := beavergram/backend +IMAGE_INPUTS := pyproject.toml uv.lock Dockerfile +CODE := src scripts ../frontend +SERVICES := api userbot +changed = ! git diff --quiet $(1) -- $(2) 2>/dev/null +stamp = { git update-ref $(1) HEAD 2>/dev/null || true; } + +.PHONY: fmt check build pre-deploy post-deploy migrate revision session + +fmt: + uv run ruff format + uv run ruff check --fix + +check: + uv run ruff format --check + uv run ruff check + uv run ty check + +build: + $(COMPOSE) build api + +pre-deploy: + @if $(call changed,refs/deploy/backend,$(IMAGE_INPUTS)) || ! docker image inspect $(IMAGE) >/dev/null 2>&1; then \ + $(MAKE) build && $(call stamp,refs/deploy/backend) && $(call stamp,refs/deploy/backend-code); \ + fi + @$(COMPOSE) config --services | grep -qx postgres && $(COMPOSE) up -d postgres || true + $(MAKE) migrate + +post-deploy: + @if $(call changed,refs/deploy/backend-code,$(CODE)); then \ + running=$$($(COMPOSE) ps --services --status running | grep -x $(addprefix -e ,$(SERVICES))); \ + [ -z "$$running" ] || $(COMPOSE) restart $$running; \ + $(call stamp,refs/deploy/backend-code); \ + fi + +migrate: + $(COMPOSE) run --rm migrator $(or $(filter-out $@,$(MAKECMDGOALS)),upgrade head) + +revision: + $(COMPOSE) run --rm migrator revision --autogenerate -m "$(m)" + +%: + @: + +session: + uv run python scripts/session/create.py diff --git a/backend/docker-compose.override.yml.example b/backend/docker-compose.override.yml.example new file mode 100644 index 0000000..d20b792 --- /dev/null +++ b/backend/docker-compose.override.yml.example @@ -0,0 +1,15 @@ +services: + api: + networks: + default: {} + caddy: + aliases: + - beavergram-api + + postgres: + ports: + - "127.0.0.1:${DB__PORT:-5432}:5432" + +networks: + caddy: + external: true diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml new file mode 100644 index 0000000..0df8efb --- /dev/null +++ b/backend/docker-compose.yml @@ -0,0 +1,107 @@ +services: + api: + build: backend + image: beavergram/backend + profiles: [api, services] + restart: unless-stopped + env_file: + - path: .env + required: false + - path: backend/.env + required: false + environment: + RUN_ENVIRONMENT: prod + TZ: ${TZ:-UTC} + STORAGE__ROOT: /app/storage + volumes: + - ./backend/src:/app/src + - ./backend/scripts:/app/scripts + - ./backend/sessions:/app/sessions + - ./frontend/build:/app/static:ro + - ${STORAGE__ROOT:-./storage}:/app/storage + command: [api] + depends_on: + postgres: + condition: service_healthy + required: false + networks: + default: + database: + + userbot: + build: backend + image: beavergram/backend + profiles: [userbot, services] + restart: unless-stopped + env_file: + - path: .env + required: false + - path: backend/.env + required: false + environment: + RUN_ENVIRONMENT: prod + TZ: ${TZ:-UTC} + STORAGE__ROOT: /app/storage + volumes: + - ./backend/src:/app/src + - ./backend/scripts:/app/scripts + - ./backend/sessions:/app/sessions + - ${STORAGE__ROOT:-./storage}:/app/storage + command: [userbot] + depends_on: + postgres: + condition: service_healthy + required: false + networks: + database: + + postgres: + image: timescale/timescaledb:2.27.1-pg17 + profiles: [postgres, external] + restart: unless-stopped + environment: + POSTGRES_USER: ${DB__USER:-beavergram} + POSTGRES_PASSWORD: ${DB__PASSWORD:-beavergram} + POSTGRES_DB: ${DB__DB_NAME:-beavergram} + volumes: + - pgdata:/var/lib/postgresql/data + - ./backend/migrations/init:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB__USER:-beavergram}"] + interval: 5s + timeout: 5s + retries: 10 + networks: + database: + aliases: + - ${DB__HOST:-postgres} + + migrator: + build: backend + image: beavergram/backend + profiles: [migrate] + env_file: + - path: .env + required: false + - path: backend/.env + required: false + environment: + RUN_ENVIRONMENT: prod + volumes: + - ./backend/src:/app/src + - ./backend/migrations:/app/migrations + - ./backend/alembic.ini:/app/alembic.ini + entrypoint: [alembic] + command: [upgrade, head] + depends_on: + postgres: + condition: service_healthy + required: false + networks: + database: + +volumes: + pgdata: + +networks: + database: diff --git a/caddy/.env.example b/caddy/.env.example index 1daac36..0759a77 100644 --- a/caddy/.env.example +++ b/caddy/.env.example @@ -1,4 +1,3 @@ BEAVERGRAM_DOMAIN=beavergram.localhost BEAVERGRAM_DEV_DOMAIN=dev.beavergram.localhost - CLOUDFLARE_API_TOKEN= diff --git a/caddy/.gitignore b/caddy/.gitignore index d0cf8ef..acd0b35 100644 --- a/caddy/.gitignore +++ b/caddy/.gitignore @@ -1,2 +1,2 @@ -Caddyfile .env +Caddyfile diff --git a/caddy/Caddyfile.example b/caddy/Caddyfile.example index ecaf90d..d38e81e 100644 --- a/caddy/Caddyfile.example +++ b/caddy/Caddyfile.example @@ -1,6 +1,5 @@ { - admin off - # acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN} + admin localhost:2019 log { format console @@ -12,8 +11,4 @@ } } -(compress) { - encode zstd gzip -} - -import /etc/caddy/projects.d/*.caddy +import /etc/caddy/projects.d/*/site.caddy diff --git a/caddy/README.md b/caddy/README.md new file mode 100644 index 0000000..aa765fc --- /dev/null +++ b/caddy/README.md @@ -0,0 +1,22 @@ +# caddy + +`site.caddy` routes `{$BEAVERGRAM_DOMAIN}` to the project's services over the external `caddy` docker network. It works standalone and inside a shared Caddy that fronts several projects. + +Standalone: + +```sh +docker network create caddy +cp Caddyfile.example Caddyfile +cp .env.example .env +docker compose up -d +``` + +Shared Caddy: mount this directory as `/etc/caddy/projects.d/beavergram:ro`, keep `import /etc/caddy/projects.d/*/site.caddy` in its Caddyfile and put `BEAVERGRAM_DOMAIN` in its environment. + +Rules that keep `site.caddy` portable: + +- the domain comes only from the environment variable +- no `tls` block, certificates are configured by the host Caddy (`acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}` in the global block) +- snippets are prefixed with the project slug because Caddy snippets are global +- mount the directory, not the file: a single-file bind mount goes stale when git replaces the inode +- keep `admin localhost:2019`, `admin off` makes `caddy reload` impossible diff --git a/caddy/docker-compose.yml b/caddy/docker-compose.yml index 033fb7a..cae97ea 100644 --- a/caddy/docker-compose.yml +++ b/caddy/docker-compose.yml @@ -12,7 +12,7 @@ services: - .env volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - - ./site.caddy:/etc/caddy/projects.d/beavergram.caddy:ro + - .:/etc/caddy/projects.d/beavergram:ro - caddy_data:/data networks: diff --git a/caddy/site.caddy b/caddy/site.caddy index b52457e..41bae40 100644 --- a/caddy/site.caddy +++ b/caddy/site.caddy @@ -5,5 +5,5 @@ {$BEAVERGRAM_DEV_DOMAIN} { encode zstd gzip - reverse_proxy beavergram-frontend:5173 + reverse_proxy beavergram-frontend:3000 } diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example deleted file mode 100644 index 520bc10..0000000 --- a/docker-compose.override.yml.example +++ /dev/null @@ -1,26 +0,0 @@ -services: -# postgres: -# ports: -# - "127.0.0.1:5432:5432" - - api: - # ports: - # - "127.0.0.1:8080:8080" - networks: - default: {} - caddy: - aliases: - - beavergram-api - - frontend-dev: -# ports: -# - "127.0.0.1:5173:5173" - networks: - default: { } - caddy: - aliases: - - beavergram-frontend - -networks: - caddy: - external: true diff --git a/docker-compose.yml b/docker-compose.yml index 933830b..7f9e2e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,98 +1,5 @@ -services: - postgres: - image: timescale/timescaledb:2.27.1-pg17 - profiles: [db] - environment: - POSTGRES_USER: ${DB__USER:-beavergram} - POSTGRES_PASSWORD: ${DB__PASSWORD:-beavergram} - POSTGRES_DB: ${DB__DB_NAME:-beavergram} - restart: unless-stopped - volumes: - - pgdata:/var/lib/postgresql/data - - ./backend/migrations/init:/docker-entrypoint-initdb.d:ro - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${DB__USER:-beavergram}"] - interval: 5s - timeout: 5s - retries: 10 - - userbot: - build: ./backend - profiles: [userbot] - command: [userbot] - env_file: - - path: backend/.env - required: false - - path: .env - required: false - environment: - RUN_ENVIRONMENT: prod - STORAGE__ROOT: /app/storage - restart: unless-stopped - volumes: - - ./backend/src:/app/src - - ./backend/sessions:/app/sessions - - ${STORAGE__ROOT:-./storage}:/app/storage - depends_on: - postgres: - condition: service_healthy - - api: - build: ./backend - profiles: [api] - command: [api] - env_file: - - path: backend/.env - required: false - - path: .env - required: false - environment: - RUN_ENVIRONMENT: prod - STORAGE__ROOT: /app/storage - restart: unless-stopped - volumes: - - ./backend/src:/app/src - - ./backend/sessions:/app/sessions - - ./frontend/build:/app/static:ro - - ${STORAGE__ROOT:-./storage}:/app/storage - depends_on: - postgres: - condition: service_healthy - - migrator: - build: ./backend - profiles: [migrate] - env_file: - - path: backend/.env - required: false - - path: .env - required: false - environment: - RUN_ENVIRONMENT: prod - volumes: - - ./backend/src:/app/src - - ./backend/migrations:/app/migrations - - ./backend/alembic.ini:/app/alembic.ini - depends_on: - postgres: - condition: service_healthy - entrypoint: [alembic] - command: [upgrade, head] - - frontend-dev: - image: oven/bun:1 - profiles: [frontend] - working_dir: /app - command: ["sh", "-c", "bun install && bun run dev --host 0.0.0.0 --port 5173"] - environment: - API_PROXY_TARGET: http://api:8080 - ALLOWED_HOSTS: ${FRONTEND_DEV_HOST:-} - volumes: - - ./frontend:/app - - frontend_node_modules:/app/node_modules - - frontend_svelte_kit:/app/.svelte-kit - -volumes: - pgdata: - frontend_node_modules: - frontend_svelte_kit: +include: + - path: backend/docker-compose.yml + project_directory: . + - path: frontend/docker-compose.yml + project_directory: . diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..1048241 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.svelte-kit +build +.env +.env.* diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..7023193 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,2 @@ +PUBLIC_API_BASE_URL=/api +ALLOWED_HOSTS= diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md new file mode 100644 index 0000000..94ac5a3 --- /dev/null +++ b/frontend/CLAUDE.md @@ -0,0 +1,6 @@ +## Checking commands +After writing code, always run from `frontend/`: +```shell +bun fix +bun check +``` diff --git a/frontend/Makefile b/frontend/Makefile new file mode 100644 index 0000000..0cef562 --- /dev/null +++ b/frontend/Makefile @@ -0,0 +1,26 @@ +COMPOSE := cd .. && docker compose +changed = ! git diff --quiet $(1) -- $(2) 2>/dev/null +stamp = { git update-ref $(1) HEAD 2>/dev/null || true; } + +.PHONY: fmt check build pre-deploy post-deploy dev + +fmt: + bun run fix + +check: + bun run check + bun run lint + +build: + $(COMPOSE) run --rm frontend-dev sh -c "bun install && bun run build" + +pre-deploy: + @if $(call changed,refs/deploy/frontend,.) || ! test -d build; then \ + $(MAKE) build && $(call stamp,refs/deploy/frontend); \ + fi + +post-deploy: + @: + +dev: + bun run dev diff --git a/frontend/docker-compose.override.yml.example b/frontend/docker-compose.override.yml.example new file mode 100644 index 0000000..e17d92f --- /dev/null +++ b/frontend/docker-compose.override.yml.example @@ -0,0 +1,11 @@ +services: + frontend-dev: + networks: + default: {} + caddy: + aliases: + - beavergram-frontend + +networks: + caddy: + external: true diff --git a/frontend/docker-compose.yml b/frontend/docker-compose.yml new file mode 100644 index 0000000..26ff1fb --- /dev/null +++ b/frontend/docker-compose.yml @@ -0,0 +1,22 @@ +services: + frontend-dev: + image: oven/bun:alpine + profiles: [frontend-dev] + restart: unless-stopped + working_dir: /app + env_file: + - path: .env + required: false + - path: frontend/.env + required: false + environment: + API_PROXY_TARGET: http://api:8080 + volumes: + - ./frontend:/app + - frontend_node_modules:/app/node_modules + - frontend_svelte_kit:/app/.svelte-kit + command: [sh, -c, "bun install && bun run dev --host 0.0.0.0 --port 3000"] + +volumes: + frontend_node_modules: + frontend_svelte_kit: diff --git a/ty.toml b/ty.toml index dbd3f8a..cc2f949 100644 --- a/ty.toml +++ b/ty.toml @@ -2,4 +2,4 @@ python = "backend/.venv" [src] -exclude = ["docs"] +exclude = ["backend/migrations", "docs"]