Initial build: Great Bear microbrewery site

- TanStack Start (React 19, Tailwind 4) frontend recreated from Stitch design
- PocketBase backend with schema migration + idempotent content seed
- Single Docker image running both services (non-root, healthchecked)
- deploy.sh to build & push to registry.tanshu.com
- Ansible playbook (roles: app, caddy) deploying to www.greatbear.in
  with Caddy TLS entries for the site and the PocketBase admin
This commit is contained in:
2026-09-03 08:51:47 +05:30
commit 7b070fde81
66 changed files with 8375 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
---
# Pull the image from the private registry and (re)create the app container.
- name: Log in to the private registry
community.docker.docker_login:
registry_url: "{{ registry_url }}"
username: "{{ registry_username }}"
password: "{{ registry_password }}"
- name: Pull the application image
community.docker.docker_image:
name: "{{ app_image }}"
tag: "{{ app_image_tag }}"
source: pull
force_source: true
- name: Run the application container
community.docker.docker_container:
name: "{{ app_container_name }}"
image: "{{ app_image }}:{{ app_image_tag }}"
state: started
recreate: true
restart_policy: unless-stopped
published_ports:
- "{{ app_site_publish }}"
- "{{ app_admin_publish }}"
volumes:
- "{{ app_volume_name }}:/data"
env:
PORT: "3000"
PB_URL: "http://127.0.0.1:8090"
PB_SUPERUSER_EMAIL: "{{ pb_superuser_email }}"
PB_SUPERUSER_PASSWORD: "{{ pb_superuser_password }}"
comparisons:
image: ignore # recreate: true already handles image updates
container_default_behavior: compatibility
- name: Wait for PocketBase to become healthy
ansible.builtin.uri:
url: http://127.0.0.1:8090/api/health
status_code: 200
register: pb_health
retries: 30
delay: 5
until: pb_health.status == 200
- name: Wait for the site to respond
ansible.builtin.uri:
url: http://127.0.0.1:3000/
status_code: 200
register: site_health
retries: 30
delay: 5
until: site_health.status == 200
- name: Log out of the private registry
community.docker.docker_login:
registry_url: "{{ registry_url }}"
state: absent
+5
View File
@@ -0,0 +1,5 @@
---
- name: Reload Caddy
ansible.builtin.systemd:
name: "{{ caddy_service }}"
state: reloaded
+47
View File
@@ -0,0 +1,47 @@
---
# Manage Caddy entries for the site and the PocketBase admin/API host.
- name: Ensure Caddy config include directory exists
ansible.builtin.file:
path: "{{ caddy_config_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Check whether the main Caddyfile exists
ansible.builtin.stat:
path: "{{ caddyfile_path }}"
register: caddyfile_stat
- name: Ensure the main Caddyfile imports conf.d entries
ansible.builtin.lineinfile:
path: "{{ caddyfile_path }}"
line: "import {{ caddy_config_dir }}/*.conf"
insertafter: EOF
state: present
when: caddyfile_stat.stat.exists
notify: Reload Caddy
- name: Install Great Bear Caddy entries
ansible.builtin.template:
src: greatbear.conf.j2
dest: "{{ caddy_config_dir }}/greatbear.conf"
owner: root
group: root
mode: "0644"
notify: Reload Caddy
- name: Validate Caddy configuration
ansible.builtin.command:
cmd: "caddy validate --config {{ caddyfile_path }} --adapter caddyfile"
changed_when: false
when: caddyfile_stat.stat.exists
- name: Flush handlers (reload Caddy now)
ansible.builtin.meta: flush_handlers
- name: Ensure Caddy is enabled and running
ansible.builtin.systemd:
name: "{{ caddy_service }}"
state: started
enabled: true
@@ -0,0 +1,12 @@
# The Great Bear — managed by Ansible. Changes will be overwritten.
# Frontend (TanStack Start)
{{ site_domain }} {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
# PocketBase API + admin UI (http://{{ admin_domain }}/_/)
{{ admin_domain }} {
encode zstd gzip
reverse_proxy 127.0.0.1:8090
}