Commit Graph

9 Commits

Author SHA1 Message Date
soroush.asadi 00a138fe46 feat(seo): complete OG/Twitter/structured-data coverage + clean encoding
CI/CD / CI · dotnet build (push) Successful in 2m1s
CI/CD / Deploy · drsousan (push) Successful in 35s
Blog list (/blog): add robots, full Open Graph + Twitter, Blog +
BreadcrumbList JSON-LD, per-page self-canonical, and rel=prev/next for
paginated pages.

Blog post: add robots, og:site_name, article:published_time /
modified_time / author / section, twitter:image, og:image:alt, and a
BreadcrumbList JSON-LD (Home → Blog → Category → Post).

Gallery (/gallery): add robots, full OG + Twitter (with first image as
og:image), ImageGallery + BreadcrumbList JSON-LD.

Encoding: register HtmlEncoder.Create(UnicodeRanges.All) so Persian text
in meta tags and JSON-LD renders literally instead of &#xXXXX; entities
(smaller, cleaner output; friendlier to SEO validators).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 13:44:37 +03:30
soroush.asadi 5a1f1a8ccb fix(seo): proper 500 handler + safe JSON-LD escaping
CI/CD / CI · dotnet build (push) Successful in 45s
CI/CD / Deploy · drsousan (push) Successful in 25s
Add UseExceptionHandler(/error) so unhandled exceptions return a
proper HTML 500 instead of a raw response Googlebot was logging as
a server error in Search Console.

Replace manual quote-only escaping in blog JSON-LD with a J() helper
that uses JsonSerializer so newlines, backslashes, and all other
control characters are safely escaped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 09:01:45 +03:30
soroush.asadi 9c93b4e51a feat(gallery+editor): dedicated /gallery page, homepage teaser, in-content images
CI/CD / CI · dotnet build (push) Successful in 21s
CI/CD / Deploy · drsousan (push) Successful in 28s
Homepage gallery:
- Show only 3 before/after samples as a teaser (was: all items)
- Add "مشاهده گالری کامل (N نمونه)" CTA when more than 3 exist
- Remove the now-pointless category tabs from the teaser

New /gallery page:
- Full before/after grid with category filter tabs (deduped from data)
- Responsive cards with قبل/بعد labels + captions, empty state
- Added to sitemap.xml (priority 0.8)

Blog content editor:
- New 🖼 تصویر toolbar button inserts an uploaded image at the cursor
  (direct upload, no forced crop) — for richer post bodies
- Responsive img styling on the public post page

Note: the filler-lab-soorat cover not showing is a data issue — that
post has an empty featuredImage in the DB (verified); re-upload + save
fixes it. The upload/save path itself is correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 01:26:35 +03:30
soroush.asadi 5ae6bb03a2 fix: resolve two build errors — siteBaseUrl self-reference + ForwardedHeaders
CI/CD / CI · dotnet build (push) Successful in 11m58s
CI/CD / Deploy · drsousan (push) Successful in 13s
- Index.cshtml: siteBaseUrl was referencing itself as fallback; replaced
  with literal default "https://draletaha.ir"
- Program.cs: removed UseForwardedHeaders call — ForwardedHeadersOptions
  unavailable in this SDK config; SITE_BASE_URL env var handles base URL

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-08 23:33:38 +03:30
soroush.asadi d02a5963cf fix: HTTPS URLs in sitemap, robots, canonical + og:image on homepage
CI/CD / CI · dotnet build (push) Failing after 5m22s
CI/CD / Deploy · drsousan (push) Has been skipped
- Add UseForwardedHeaders middleware so Request.Scheme = "https" behind nginx
- Add SITE_BASE_URL env var fallback for sitemap.xml, robots.txt, and all
  Razor page canonical/og URLs — set it to https://draletaha.ir in .env
- Add og:image to homepage using hero photo
- Add SITE_BASE_URL to docker-compose.yml environment block

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-08 22:30:55 +03:30
soroush.asadi 22d0ecb330 feat: doctor reply + diagnosis + tracking code per health request
CI/CD / CI · dotnet build (push) Successful in 45s
CI/CD / Deploy · drsousan (push) Successful in 28s
Backend:
- HealthRequest model: TrackingCode (DR-XXXXXX), Diagnosis,
  DoctorReply, RepliedAt fields
- Runtime migration: ALTER TABLE adds 4 new columns to existing DB
- POST /api/health-request: auto-generates tracking code, returns it
- PUT /api/health-requests/{id}/reply: doctor sets diagnosis + reply
- GET /api/health-request/track/{code}: public lookup by tracking code
- GET /api/health-requests?phone=: filter history by phone number

Admin panel:
- Request table shows tracking code column (gold badge)
- Detail modal (680px): tracking code header, patient info, full message
- Previous doctor reply shown in green box if exists
- Reply form: diagnosis input + textarea for doctor message
- History panel: all requests from same phone, click to switch
- 'پاسخ / مشاهده' button opens reply modal directly

Frontend:
- After form submit: shows tracking code in green box to user
  (format: DR-XXXXXX, stays visible 8 seconds)
- Box auto-hides and form resets after timeout

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-02 22:03:00 +03:30
soroush.asadi 5d6a4a630d fix: preserve original file type on upload — never convert PNG to JPG
CI/CD / CI · dotnet build (push) Successful in 53s
CI/CD / Deploy · drsousan (push) Successful in 28s
Problem: cropper always called out.toBlob(..., 'image/jpeg') regardless
of the original file type, silently converting PNGs to JPGs.

Fix:
- openCropper() now stores file.type and file.name on the cropper object
- applyCrop() uses the stored mime type for toBlob() and the filename
- Quality param only passed for lossy formats (jpeg/webp), not for PNG/GIF
- uploadImage() accept list expanded: svg, ico allowed
- Server-side: .svg and .ico added to allowed extensions

Result: PNG stays PNG, WebP stays WebP, ICO stays ICO.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-02 18:06:38 +03:30
soroush.asadi 3780dcccf2 feat: patient management system + health landing page
CI/CD / CI · dotnet build (push) Successful in 59s
CI/CD / Deploy · drsousan (push) Successful in 1m33s
Backend:
- Patient model: name, phone, email, age, weight, height, gender,
  blood type, disease history, allergies, medications, notes, category
- PatientVisit model: title, content, prescription, visit type,
  visit/next-visit dates, linked to patient (cascade delete)
- HealthRequest model: public form submissions for beauty/health care
- Runtime SQLite migrations for all 3 new tables
- Full CRUD API: /api/patients, /api/patients/{id}/visits,
  /api/health-requests (public POST + admin GET/PUT/DELETE)

Admin panel:
- 'پرونده بیماران' page: list, search, filter by category (beauty/health)
- Patient profile page: personal info + medical history + visits timeline
- Add/edit patient modal with all medical fields
- Add visit modal: type, date, clinical notes, prescription, next visit
- 'درخواست‌ها' page: manage public health requests, mark as handled
- Badge counter for unhandled requests in sidebar

Frontend (SEO):
- New #health-care section with Schema.org MedicalClinic markup
- Two category cards: زیبایی پوست and سلامت عمومی
- Feature lists with checkmarks per category
- Inline request form that submits to /api/health-request
- Mobile responsive (single column on small screens)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-02 12:27:16 +03:30
soroush.asadi 96e73bf633 first commit
CI/CD / CI · dotnet build (push) Failing after 0s
CI/CD / Deploy · drsousan (push) Has been skipped
2026-05-31 00:42:08 +03:30