{"id":50409620,"url":"https://github.com/robert197/baky","last_synced_at":"2026-05-31T03:02:04.424Z","repository":{"id":348240179,"uuid":"1197047791","full_name":"robert197/baky","owner":"robert197","description":"BAKY - Apartment Monitoring \u0026 Inspection Platform for Short-Term Rentals in Vienna. Django 5.x + HTMX + Alpine.js + Tailwind CSS","archived":false,"fork":false,"pushed_at":"2026-05-01T14:29:19.000Z","size":1053,"stargazers_count":0,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T15:32:51.215Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robert197.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T09:28:11.000Z","updated_at":"2026-05-01T14:29:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/robert197/baky","commit_stats":null,"previous_names":["robert197/baky"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/robert197/baky","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robert197%2Fbaky","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robert197%2Fbaky/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robert197%2Fbaky/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robert197%2Fbaky/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robert197","download_url":"https://codeload.github.com/robert197/baky/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robert197%2Fbaky/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33717419,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-31T03:02:03.405Z","updated_at":"2026-05-31T03:02:04.419Z","avatar_url":"https://github.com/robert197.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BAKY\n\n**Betreuung. Absicherung. Kontrolle. Your Home.**\n\nApartment monitoring and inspection platform for short-term rentals in Vienna.\n\n## What is BAKY?\n\nBAKY helps property owners maintain oversight of their short-term rental apartments between guest stays. We schedule professional inspections, execute checklist-based walkthroughs with photo documentation, and deliver instant reports.\n\n## Business Process\n\n### How It Works\n\n```mermaid\nflowchart LR\n    A[\"Owner signs up\"] --\u003e B[\"Apartment registered\\n+ checklist customized\"]\n    B --\u003e C[\"Admin schedules\\ninspection\"]\n    C --\u003e D[\"Inspector executes\\nchecklist on-site\"]\n    D --\u003e E[\"Photos captured\\nper checklist item\"]\n    E --\u003e F[\"Report auto-generated\\n+ emailed to owner\"]\n    F --\u003e G[\"Owner reviews\\non dashboard\"]\n```\n\n### User Roles and Access\n\n| Role | How they join | Login | Landing page | What they do |\n|------|--------------|-------|-------------|-------------|\n| **Owner** | Self-signup at `/accounts/signup/` | `/accounts/login/` → `/dashboard/` | Owner Dashboard | Registers apartments, customizes checklists, selects plan, views inspection reports |\n| **Inspector** | Created by Admin in Django Admin | `/accounts/login/` → `/inspector/` | Inspector Schedule | Views daily assignments, executes checklists on-site, captures photos, submits inspections |\n| **Admin** | `make createsuperuser` | `/accounts/login/` → `/admin/` | Django Admin | Manages users, schedules inspections, assigns inspectors, monitors platform |\n\nAll roles share a single login page. After login, users are redirected based on their role.\n\n### Owner Journey (Signup to Reports)\n\n```mermaid\nflowchart TD\n    S[\"/accounts/signup/\"] --\u003e|Create account| V[\"Email verification sent\\n48h token\"]\n    V --\u003e O1\n\n    subgraph onboarding [\"Onboarding Wizard\"]\n        O1[\"Step 1: Register Apartment\\nAddress via Google Maps autocomplete\\nAccess method + encrypted access code\"]\n        O2[\"Step 2: Customize Checklist\\nEnable/disable default items\\nAdd custom items\"]\n        O3[\"Step 3: Select Plan\\nBasis / Standard / Premium\"]\n        O4[\"Step 4: Confirmation\\nReview summary + welcome email\"]\n        O1 --\u003e O2 --\u003e O3 --\u003e O4\n    end\n\n    O4 --\u003e D[\"/dashboard/\\nOwner Dashboard\"]\n    D --\u003e D1[\"View apartments + details\"]\n    D --\u003e D2[\"Book inspections via calendar\"]\n    D --\u003e D3[\"View inspection reports\"]\n    D --\u003e D4[\"Manage subscription\"]\n    D --\u003e D5[\"Account settings + GDPR\"]\n```\n\n### Owner Dashboard Flows\n\n**Apartment Management**\n- View all apartments with status badges (Aktiv/Pausiert), last/next inspection dates and ratings\n- Click into apartment detail: address, access method, full checklist, recent inspections\n- Edit apartment: change address, access method/code, access notes, special instructions, status\n\n**Booking Calendar**\n- Select apartment from dropdown to see weekly calendar view\n- 3 time slots per day: 08:00-10:30, 10:30-13:00, 13:30-16:00\n- Color-coded slots: green (available), amber (your booking), grey (taken/past)\n- Book a slot with confirmation dialog; cancel booking with cancellation confirmation\n- 24-hour advance booking rule enforced; double-booking prevented\n- Subscription progress bar shows used/total inspections this month\n\n**Subscription Management**\n- Overview: plan, price, billing date, inspection usage\n- Change plan: request upgrade/downgrade (sends confirmation email)\n- Pause subscription: request pause (sends confirmation email)\n- Cancel subscription: request cancellation with optional reason (sends confirmation email)\n- Extra inspections: book additional inspections outside plan\n- Billing history\n\n**Account \u0026 GDPR**\n- Account deletion: password-confirmed, 30-day soft-delete grace period\n- Cancel deletion: recover account within 30 days via `/accounts/delete-cancel/`\n- GDPR data export: request ZIP export of all personal data (DSGVO Art. 15)\n\n### Inspector Mobile Flow\n\n```mermaid\nflowchart TD\n    L[\"/inspector/\"] --\u003e S[\"Today's schedule\\nGrouped by date\"]\n    S --\u003e|\"Tap access info\"| A[\"View access details\\nLockbox code, notes\"]\n    S --\u003e|\"Tap Start\"| E[\"/inspector/\u003cid\u003e/execute/\\nFull checklist UI\"]\n    E --\u003e|\"Mark each item\"| I[\"OK / Auffällig / N/A\\nPer checklist item\"]\n    I --\u003e|\"Add photos\"| P[\"Photo upload per item\\n+ general photos\"]\n    I --\u003e|\"Add notes\"| N[\"General notes field\"]\n    E --\u003e R[\"/inspector/\u003cid\u003e/review/\\nSummary: counts + flagged items\"]\n    R --\u003e|\"Select rating\"| G[\"OK / Achtung / Dringend\"]\n    G --\u003e|\"Submit\"| C[\"/inspector/\u003cid\u003e/submitted/\\nSuccess confirmation\"]\n    C --\u003e|\"Background\"| BG[\"Report generated\\n+ emailed to owner\"]\n```\n\n**Inspector checklist execution:**\n- 22 default checklist items across 8 categories (Allgemeiner Eindruck, Kuche, Badezimmer, Wohnbereiche, Gerate, Schlafzimmer, Zugang \u0026 Sicherheit, Nach der Reinigung)\n- Each item: OK / Auffällig (flagged) / N/A with optional photos and notes\n- Review page shows counts (OK/Auffällig/N/A), lists flagged items, requires overall rating\n- Submit button disabled until overall rating selected\n- On submission: inspection marked completed, report auto-generated as HTML, email sent to owner\n\n### Inspection Lifecycle\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Scheduled: Admin creates + assigns inspector\n    Scheduled --\u003e InProgress: Inspector taps Start\n    InProgress --\u003e Completed: Inspector submits all items\n    Completed --\u003e ReportGenerated: Background task via Django-Q2\n    ReportGenerated --\u003e EmailSent: Auto-email to owner\n    Scheduled --\u003e Cancelled: Admin or system cancels\n\n    state InProgress {\n        [*] --\u003e ChecklistItem\n        ChecklistItem --\u003e OK\n        ChecklistItem --\u003e Flagged\n        ChecklistItem --\u003e NA\n        Flagged --\u003e AddSeverity: Low / Medium / High / Urgent\n        AddSeverity --\u003e AddNotes\n        AddNotes --\u003e CapturePhoto\n        CapturePhoto --\u003e ChecklistItem: Next item\n        OK --\u003e ChecklistItem: Next item\n        NA --\u003e ChecklistItem: Next item\n    }\n```\n\n### Overall Rating\n\n| Rating | Meaning | Trigger |\n|--------|---------|---------|\n| **OK** | All good | All items OK or N/A |\n| **Attention** | Some issues | Any item flagged with low/medium severity |\n| **Urgent** | Critical issues | Any item flagged with high/urgent severity |\n\n## URL Map\n\n| Area | URL | Auth | Description |\n|------|-----|------|-------------|\n| **Public** | `/` | -- | Landing page (hero, features, FAQ, testimonials) |\n| | `/preise/` | -- | Pricing (3 tiers with FAQ) |\n| | `/impressum/` | -- | Legal notice |\n| | `/datenschutz/` | -- | Privacy policy |\n| | `/agb/` | -- | Terms of service |\n| **Auth** | `/accounts/login/` | -- | Login (email or username, all roles) |\n| | `/accounts/signup/` | -- | Owner self-signup (accepts `?plan=` from pricing) |\n| | `/accounts/verify/\u003ctoken\u003e/` | -- | Email verification |\n| | `/accounts/onboarding/*` | Owner | 4-step onboarding (apartment, checklist, plan, confirm) |\n| | `/accounts/password-reset/` | -- | Password reset (email link flow) |\n| | `/accounts/delete-cancel/` | -- | Cancel account deletion (within 30-day grace) |\n| **Dashboard** | `/dashboard/` | Owner | Apartment list with status/inspection overview |\n| | `/dashboard/apartments/\u003cid\u003e/` | Owner | Apartment detail (checklist, recent inspections) |\n| | `/dashboard/apartments/\u003cid\u003e/edit/` | Owner | Edit apartment (address, access, status) |\n| | `/dashboard/apartments/\u003cid\u003e/inspections/` | Owner | Inspection timeline with filters |\n| | `/dashboard/apartments/\u003cid\u003e/inspections/\u003cid\u003e/report/` | Owner | Full inspection report |\n| | `/dashboard/buchen/` | Owner | Booking calendar (weekly view, 3 slots/day) |\n| | `/dashboard/subscription/` | Owner | Subscription overview |\n| | `/dashboard/subscription/change/` | Owner | Request plan change |\n| | `/dashboard/subscription/pause/` | Owner | Request pause |\n| | `/dashboard/subscription/cancel/` | Owner | Request cancellation |\n| | `/dashboard/account/delete/` | Owner | Delete account (password-confirmed) |\n| | `/dashboard/account/export/` | Owner | GDPR data export request |\n| **Inspector** | `/inspector/` | Inspector | Today's schedule with access details |\n| | `/inspector/schedule/` | Inspector | Full schedule view |\n| | `/inspector/\u003cid\u003e/execute/` | Inspector | Checklist execution (OK/Flag/N.A. per item) |\n| | `/inspector/\u003cid\u003e/review/` | Inspector | Review summary + overall rating |\n| | `/inspector/\u003cid\u003e/submit/` | Inspector | Submit completed inspection |\n| **Admin** | `/admin/` | Admin | Full platform management (django-unfold) |\n\n## Plans and Pricing\n\n| Feature | Basis (€89/mo) | Standard (€149/mo) | Premium (€249/mo) |\n|---------|----------------|--------------------|--------------------|\n| Inspections per month | 2 | 4 | 8 |\n| Photo documentation | Yes | Yes | Yes |\n| Instant digital reports | Yes | Yes | Yes |\n| Custom checklist | Yes | Yes | Yes |\n| Immediate problem alerts | Yes | Yes | Yes |\n| Preferred scheduling | -- | Yes | Yes |\n| Priority scheduling | -- | -- | Yes |\n| Personal contact | -- | -- | Yes |\n\nAll plans are per apartment, monthly cancellable. Plan changes, pauses, and cancellations are requested through the dashboard and processed within 1-2 business days.\n\n## Email Notifications\n\nAll emails are sent via Resend (Mailpit in development at http://localhost:8026).\n\n| Trigger | Recipient | Subject |\n|---------|-----------|---------|\n| Account signup | New user | Willkommen bei BAKY! |\n| Email verification | New user | BAKY — E-Mail-Adresse bestatigen |\n| Password reset | User | BAKY — Passwort zurucksetzen |\n| Inspection completed | Owner | BAKY Inspektionsbericht — [Address] — [Date] |\n| Booking created | Admin | Neue Buchung — [Address] ([Slot]) |\n| Booking cancelled | Admin | Stornierung — [Address] ([Slot]) |\n| Plan change requested | Owner | Bestatigung: Ihre Plananderung wurde gesendet |\n| Pause requested | Owner | Bestatigung: Ihre Pausierung wurde angefragt |\n| Cancellation requested | Owner | Bestatigung: Ihre Kundigung wurde angefragt |\n\n## Authentication \u0026 Security\n\n- **Login accepts email**: Users register with email but login resolves email to username transparently\n- **Role-based access**: Owners see only their own apartments (404 for others); inspectors can't access owner pages; unauthenticated users get redirected to login\n- **CSRF protection**: All forms include CSRF tokens; logout is POST-only\n- **Encrypted fields**: Access codes and notes are stored encrypted (`EncryptedCharField`/`EncryptedTextField`)\n- **Account deletion**: Password-confirmed, 30-day soft-delete grace period with recovery option\n- **Password reset**: Email-based flow with time-limited tokens\n\n## Quick Start\n\n```bash\n# Prerequisites: Docker only\nmake up\nmake migrate\nmake seed\n# Visit http://localhost:8010\n# Mailpit UI: http://localhost:8026\n```\n\n## Development\n\nThis project is built with Claude Code. See [CLAUDE.md](CLAUDE.md) for conventions, architecture, and workflow.\n\n## Production Deployment\n\nProduction runs on the Devs Group server via Docker Compose. The server does not contain a Git checkout of this repository; it contains a Compose project that pulls the published GHCR image.\n\n### Deploy Steps\n\n```bash\n# 1. Commit and push to main. GitHub Actions builds and pushes:\n#    ghcr.io/robert197/baky:latest\ngit push origin main\n\n# 2. SSH into production\nssh devsgroup@45.83.105.86 -p 2222\n\n# 3. Pull the latest image and restart services\ncd ~/websites/baky\ndocker compose pull web worker\ndocker compose run --rm web python manage.py migrate --noinput\ndocker compose up -d web worker\n\n# 4. Verify\ndocker compose ps\ncurl -fsS https://baky.at/health/\n```\n\nProduction Compose path: `~/websites/baky/docker-compose.yml`.\n\nThe public production URL configured in Traefik is `https://baky.at`. `https://www.baky.at` redirects to the apex domain.\n\n### Key Make Targets\n\n```bash\nmake up              # Start all services\nmake down            # Stop all services\nmake test            # Run pytest suite\nmake lint            # Run ruff + djlint\nmake migrate         # Run migrations\nmake seed            # Load demo/seed data\nmake shell           # Django shell\nmake createsuperuser # Create admin user\n```\n\n### Custom Skills\n\n| Skill | Description |\n|-------|------------|\n| `/next-issue` | Pick the next issue from the roadmap |\n| `/done-issue` | Complete current issue (verify, commit, PR, close) |\n| `/baky-status` | Quick project status overview |\n| `/validate` | Run full validation suite (lint + tests + e2e) |\n| `/autopilot` | Start Ralph Loop for autonomous MVP development |\n\n### Roadmap\n\nSee [Issue #44](https://github.com/robert197/baky/issues/44) for the full build order with dependencies.\n\n**Build phases:**\n1. **Foundation** -- Django project, Docker, testing, design system (done)\n2. **Data Layer** -- Models, auth, checklists, storage, admin (done)\n3. **Public Website** -- Landing, pricing, legal, signup/onboarding (done)\n4. **Inspector App** -- Scheduling, daily view, checklist execution, photo capture, submission (done)\n5. **Reports** -- Auto-generation from inspection data, email delivery (done)\n6. **Owner Dashboard** -- Apartment list, inspection timeline, booking calendar, subscription management (done)\n7. **Compliance and Launch** -- GDPR (data export, account deletion), seed data, CI/CD, production deployment (in progress)\n\n## Tech Stack\n\nDjango 5.x + HTMX + Alpine.js + Tailwind CSS + PostgreSQL -- all running in Docker.\n\n| Layer | Technology |\n|-------|-----------|\n| Backend | Django 5.x (Python 3.12) |\n| Frontend | Django Templates + HTMX + Alpine.js |\n| Styling | Tailwind CSS |\n| Database | PostgreSQL 16 |\n| File Storage | AWS S3 / Cloudflare R2 |\n| Background Tasks | Django-Q2 |\n| Email | Resend |\n| Admin | Django Admin + django-unfold |\n| Hosting | Docker everywhere |\n\n## Deployment (SSH method)\n\nBAKY runs as a Docker Compose stack on a single Linux VPS. CI builds images and pushes them\nto **GitHub Container Registry** (`ghcr.io/robert197/baky`); the server pulls the latest image\nover SSH and recreates the stack with `docker-compose.prod.yml`.\n\n### One-time server setup\n\nRun on the production host as root (or sudo user):\n\n```bash\n# 1. Install Docker Engine + Compose plugin\ncurl -fsSL https://get.docker.com | sh\nsudo apt-get install -y docker-compose-plugin\n\n# 2. Create deploy user that can run docker\nsudo useradd -m -s /bin/bash baky\nsudo usermod -aG docker baky\n\n# 3. Add your SSH public key\nsudo mkdir -p /home/baky/.ssh\nsudo cp ~/.ssh/authorized_keys /home/baky/.ssh/authorized_keys\nsudo chown -R baky:baky /home/baky/.ssh\nsudo chmod 700 /home/baky/.ssh \u0026\u0026 sudo chmod 600 /home/baky/.ssh/authorized_keys\n\n# 4. App directory\nsudo -u baky mkdir -p /srv/baky /srv/baky/backups\n```\n\nPlace these files in `/srv/baky/` on the server:\n\n| File | Source | Notes |\n|------|--------|-------|\n| `docker-compose.prod.yml` | This repo | `scp` from your machine, or `curl` from a release tag |\n| `.env.production`         | Created on server | Use `.env.example` as template — never commit secrets |\n| `gunicorn.conf.py`        | Baked into image | Nothing to do |\n\nLog in to GHCR so the server can pull the image (one-time):\n\n```bash\necho \"$GHCR_PAT\" | docker login ghcr.io -u robert197 --password-stdin\n```\n`GHCR_PAT` is a GitHub Personal Access Token with `read:packages` scope.\n\n### TLS / reverse proxy\n\nPut **Caddy** (or **nginx + Certbot**) in front of the `web` container on `127.0.0.1:8000`.\nCaddy is the shortest path:\n\n```caddyfile\nbaky.at, www.baky.at {\n    reverse_proxy 127.0.0.1:8000\n    encode zstd gzip\n}\n```\n\nCaddy handles Let's Encrypt automatically. Make sure `ALLOWED_HOSTS` and\n`CSRF_TRUSTED_ORIGINS` in `.env.production` match `baky.at` and `www.baky.at`.\n\n### Deploy a new release\n\nCI pushes `ghcr.io/robert197/baky:latest` (and `:sha-\u003ccommit\u003e`) on every push to `main`. Roll\nout by pulling + recreating on the server:\n\n```bash\nssh baky@baky.at\ncd /srv/baky\n\n# 1. Pull latest image\ndocker compose -f docker-compose.prod.yml pull\n\n# 2. Recreate web + worker (db keeps running)\ndocker compose -f docker-compose.prod.yml up -d --remove-orphans\n\n# 3. Run migrations\ndocker compose -f docker-compose.prod.yml exec web python manage.py migrate --noinput\n\n# 4. Verify\ncurl -fsS https://baky.at/health/\n```\n\n### One-shot deploy from your machine\n\n```bash\nssh baky@baky.at '\n  cd /srv/baky \u0026\u0026\n  docker compose -f docker-compose.prod.yml pull \u0026\u0026\n  docker compose -f docker-compose.prod.yml up -d --remove-orphans \u0026\u0026\n  docker compose -f docker-compose.prod.yml exec -T web python manage.py migrate --noinput \u0026\u0026\n  curl -fsS http://localhost:8000/health/\n'\n```\n\nWrap that into `bin/deploy.sh` if you want a `make deploy` target later.\n\n### Rollback\n\n```bash\nssh baky@baky.at\ncd /srv/baky\nIMAGE_TAG=sha-\u003cprevious-commit\u003e docker compose -f docker-compose.prod.yml up -d\n```\n\n(For this to work, reference `image: ghcr.io/robert197/baky:${IMAGE_TAG:-latest}` in\n`docker-compose.prod.yml`.) If a migration is the problem, restore the database from the\nlatest dump in `/srv/baky/backups/` before rolling the image back.\n\n### Backups\n\nDaily `pg_dump` via host crontab:\n\n```cron\n0 3 * * * docker compose -f /srv/baky/docker-compose.prod.yml exec -T db \\\n  pg_dump -U $POSTGRES_USER $POSTGRES_DB | gzip \u003e /srv/baky/backups/baky-$(date +\\%F).sql.gz\n```\n\nKeep ~14 days locally; ship one offsite (S3/R2) weekly.\n\n### Required environment variables\n\nSee `.env.example` for the full list. Production needs at minimum: `SECRET_KEY`, `DEBUG=False`,\n`ALLOWED_HOSTS`, `CSRF_TRUSTED_ORIGINS`, `DATABASE_URL`, `FIELD_ENCRYPTION_KEY`,\n`RESEND_API_KEY`, AWS S3/R2 credentials, and `POSTGRES_DB` / `POSTGRES_USER` /\n`POSTGRES_PASSWORD` for the bundled `db` service.\n\n## License\n\nProprietary. All rights reserved.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobert197%2Fbaky","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobert197%2Fbaky","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobert197%2Fbaky/lists"}