[Verify+Complaints] Facility document review + facility complaints; card location line
CI/CD / CI · dotnet build (push) Successful in 1m27s
CI/CD / Deploy · hamkadr (push) Successful in 1m13s

Card: move location to its own line above the date in the shift card (job card already did). Verification workflow: employers upload documents (license/permit) on a new Employer/Verify page; uploading marks the facility Pending. Admins see pending facilities with their documents on Admin/Facilities, can download each doc, and approve (تأیید شد) or reject with a reason. Documents stored as bytea in the DB (survives deploys via the existing volume); served only to the owner or an admin via /facility-doc/{id}. Facility model gains Verification status enum + note + requested-at; IsVerified kept in sync. Complaints: registered users/visitors can file a شکایت about a facility from shift/job detail pages (targets ReportTargetType.Facility, surfaces in Admin/Reports as مرکز). Migration backfills existing verified facilities to Verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-04 16:26:15 +03:30
parent 962196d5cb
commit 1f34fd126f
16 changed files with 1632 additions and 24 deletions
@@ -337,6 +337,16 @@ namespace JobsMedical.Web.Migrations
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<int>("Verification")
.HasColumnType("integer");
b.Property<string>("VerificationNote")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<DateTime?>("VerificationRequestedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("CityId");
@@ -348,6 +358,44 @@ namespace JobsMedical.Web.Migrations
b.ToTable("Facilities");
});
modelBuilder.Entity("JobsMedical.Web.Models.FacilityDocument", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ContentType")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<byte[]>("Data")
.IsRequired()
.HasColumnType("bytea");
b.Property<int>("FacilityId")
.HasColumnType("integer");
b.Property<string>("FileName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<DateTime>("UploadedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("FacilityId");
b.ToTable("FacilityDocuments");
});
modelBuilder.Entity("JobsMedical.Web.Models.InterestEvent", b =>
{
b.Property<long>("Id")
@@ -902,6 +950,17 @@ namespace JobsMedical.Web.Migrations
b.Navigation("OwnerUser");
});
modelBuilder.Entity("JobsMedical.Web.Models.FacilityDocument", b =>
{
b.HasOne("JobsMedical.Web.Models.Facility", "Facility")
.WithMany("Documents")
.HasForeignKey("FacilityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Facility");
});
modelBuilder.Entity("JobsMedical.Web.Models.InterestEvent", b =>
{
b.HasOne("JobsMedical.Web.Models.JobOpening", "JobOpening")
@@ -1030,6 +1089,8 @@ namespace JobsMedical.Web.Migrations
modelBuilder.Entity("JobsMedical.Web.Models.Facility", b =>
{
b.Navigation("Documents");
b.Navigation("Shifts");
});