{
  "contract_id": "aclasa.portfolio_access.methodology.v2",
  "contract_version": 3,
  "projection_updated_on": "2026-10-17",
  "status": "backend_required_preview_fail_closed",
  "owned_by": "ACLASA portfolio",
  "aclasa_pro_mode": "static_public_portal_backend_required_not_deployed",
  "principle": "Browser state is never an authorization authority. Production access requires a server-verified OIDC session and an independent backend entitlement decision on every protected request.",
  "security_boundary": {
    "browser_role": "Presentation and navigation only; client-side gates are UX hints, not security controls.",
    "production_authority": "A future same-origin ACLASA backend session and protected-resource backend. The current static deployment has no production employer-editing authority.",
    "untrusted_authorization_inputs": [
      "window.ACLASA_PORTFOLIO_SESSION and every other window global",
      "localStorage and sessionStorage",
      "URL query and fragment values",
      "hidden form fields and DOM attributes",
      "self-asserted verified, role, grant, tenant, program or period flags"
    ],
    "fail_closed": "If the session endpoint is absent, unavailable, redirected, malformed, expired or denies access, the portal remains in public-preview mode.",
    "protected_content_rule": "Full JSON, PDF and any pack-specific format such as LT's legacy DOCX, Lithuania's private 10-page preview, employer records and exports must never be served from public static paths. Their endpoints must repeat server-side authorization and must not rely on the browser's decision."
  },
  "session_endpoint": {
    "method": "GET",
    "path": "/api/portfolio/session",
    "same_origin_only": true,
    "request_credentials": "same-origin HttpOnly session cookie",
    "redirect_policy": "Do not redirect API requests to a login page; return an unauthenticated status.",
    "success_status": 200,
    "unauthenticated_statuses": [
      204,
      401,
      403
    ],
    "response_content_type": "application/json",
    "response_cache_control": "no-store, private",
    "response_shape": {
      "authenticated": true,
      "session": {
        "sub": "OIDC subject",
        "email": "normalized user email",
        "company_tenant_id": "authorized tenant identifier",
        "company_user_id": "authorized company-user identifier",
        "company_name": "display-only company name",
        "roles": [
          "normalized role names; roles never substitute for product grants"
        ],
        "product_grants": [
          "server-computed ACLASA product grants"
        ],
        "paid_programs": [
          "server-computed active program codes"
        ],
        "effective_from": "YYYY-MM-DD",
        "effective_to": "YYYY-MM-DD",
        "issuer": "verified OIDC issuer",
        "program_period_id": "server-side program-period identifier",
        "session_expires_at": "RFC 3339 timestamp",
        "authorization_decision_id": "opaque backend audit-correlation identifier"
      }
    }
  },
  "oidc_verification": {
    "location": "backend_only",
    "flow": "OAuth 2.0 Authorization Code flow with PKCE; exchange the code on the backend",
    "issuer": "Require an exact match against a deployment-configured issuer allowlist.",
    "audience": "Require the deployment-configured ACLASA backend audience and, when issued, the expected authorized party.",
    "signature": "Verify the ID token signature with the issuer JWKS, allow only explicitly configured asymmetric algorithms, honor key rotation and reject unknown kid values.",
    "time_claims": "Validate exp, iat and nbf with a small bounded clock skew; reject expired, not-yet-valid and implausibly old tokens.",
    "request_binding": "Validate state, nonce, redirect_uri and PKCE verifier; consume each authorization response once.",
    "token_handling": "Keep ID, access and refresh tokens on the backend. Never expose them to JavaScript, URLs, localStorage or sessionStorage.",
    "session_cookie": "Use a rotated opaque host-only cookie with Secure, HttpOnly and SameSite=Lax or stricter attributes; never encode grants as unsigned browser-readable state."
  },
  "backend_entitlement_rules": [
    "Resolve the current user, company tenant and company-user membership from backend records on every protected request.",
    "Require the exact product grant for the requested operation; a role name alone never grants access.",
    "Require the exact active paid ACLASA methodology program mapped to the requested country pack and current program period; generic or portfolio-wide methodology program codes never unlock a country pack.",
    "Require effective_from <= server current time <= effective_to and reject missing, future, expired or revoked periods.",
    "Bind the requested company record to the authorized company_tenant_id; never accept a tenant identifier solely from the URL or request body.",
    "For edit and publish mutations, enforce CSRF protection, permitted content types, optimistic concurrency and audit logging server-side.",
    "Return only the authorized resource and use 401 for no valid session, 403 for insufficient entitlement, and 404 where tenant/resource existence must not be disclosed.",
    "Re-evaluate entitlement at download/export time; a prior session-summary response is not an authorization ticket."
  ],
  "required_session_claims": [
    "sub",
    "email",
    "company_tenant_id",
    "company_user_id",
    "company_name",
    "roles",
    "product_grants",
    "paid_programs",
    "effective_from",
    "effective_to",
    "issuer",
    "program_period_id",
    "session_expires_at",
    "authorization_decision_id"
  ],
  "required_product_grants": {
    "read": "aclasa.methodology.read",
    "download": "aclasa.methodology.download",
    "draft": "aclasa.methodology.draft",
    "review": "aclasa.methodology.review",
    "approve": "aclasa.methodology.approve",
    "publish": "aclasa.methodology.publish",
    "audit": "aclasa.methodology.audit"
  },
  "catalog_product_grants": {
    "query": "aclasa.catalog.query",
    "purchased_result_export": "aclasa.catalog.purchased_result.export",
    "company_workspace": "aclasa.catalog.workspace",
    "company_export": "aclasa.catalog.export",
    "portfolio_admin_export": "aclasa.catalog.admin.export",
    "audit": "aclasa.catalog.audit"
  },
  "accepted_roles": [
    "portfolio_break_glass_admin",
    "platform_security_admin",
    "portfolio_billing_admin",
    "portfolio_auditor",
    "methodology_author",
    "methodology_reviewer",
    "methodology_approver",
    "publisher",
    "org_owner",
    "org_admin",
    "pay_equity_analyst",
    "pay_equity_reviewer",
    "talent_recruiter",
    "supplier_admin",
    "case_manager",
    "viewer"
  ],
  "role_policy": "Accepted roles are descriptive context only. No accepted role implies a methodology product grant.",
  "program_entitlement_policy": {
    "portfolio_wide_program_enabled": false,
    "exact_selected_pack_match_required": true,
    "pack_program_codes": {
      "sk-en": "aclasa.methodology.sk",
      "it-en": "aclasa.methodology.it",
      "gr-en": "aclasa.methodology.gr",
      "es-en": "aclasa.methodology.es",
      "lt-en": "aclasa.methodology.lt"
    },
    "generic_program_codes_forbidden": [
      "aclasa.methodology",
      "aclasa.program.methodology"
    ],
    "rule": "A protected country-pack request is authorized only when paid_programs contains the one exact program code mapped to that requested pack. No other country code, generic code or portfolio-level flag substitutes for it."
  },
  "catalog_entitlement_policy": {
    "default": "deny",
    "anonymous_preview_profile_limit": 462,
    "anonymous_standard_reference_profile_limit": 462,
    "protected_multi_seniority_profile_count": 960,
    "anonymous_allowed": [
      "one_governed_base_profile_per_isco08_unit_plus_allowlisted_market_title_profiles",
      "individual_non_bulk_orientation"
    ],
    "anonymous_forbidden": [
      "full_position_catalog",
      "full_multi_seniority_scoring_payload",
      "catalog_xlsx",
      "catalog_csv",
      "bulk_json_export",
      "source_workbook"
    ],
    "candidate_scope": "own_purchased_or_entitled_results_only",
    "company_scope": "contracted_tenant_and_entitlement_only",
    "portfolio_superadmin_scope": "audited_operation_with_MFA_step_up",
    "rule": "Every query, workspace action and export repeats a fresh server-side identity, tenant, product-grant and commercial-entitlement decision. A UI link, role label, payment receipt or cockpit card is never authorization.",
    "base_reference_profile_count": 436,
    "allowlisted_market_profile_count": 26,
    "allowlisted_market_title_count": 28
  },
  "protected_routes": [
    {
      "path": "/api/portfolio/methodology/packs/{pack}/json",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.methodology.read",
      "requires_active_pack_program": true
    },
    {
      "path": "/api/portfolio/methodology/packs/{pack}/pdf",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.methodology.download",
      "requires_active_pack_program": true
    },
    {
      "path": "/api/portfolio/methodology/packs/{pack}/docx",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.methodology.download",
      "requires_active_pack_program": true,
      "available_for_packs": [
        "lt-en"
      ]
    },
    {
      "path": "/api/portfolio/methodology/packs/{pack}/evidence-workbook",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.methodology.download",
      "requires_active_pack_program": true,
      "response_file": "ACLASA_Employer_Adoption_Evidence_Workbook_SK_IT_v1_0.xlsx",
      "content_disposition": "attachment"
    },
    {
      "path": "/api/portfolio/methodology/company-layer/{company_tenant_id}/{pack}",
      "methods": [
        "GET",
        "PUT"
      ],
      "required_grants_by_method": {
        "GET": "aclasa.methodology.read",
        "PUT": "aclasa.methodology.draft"
      },
      "requires_active_pack_program": true,
      "tenant_binding_required": true
    },
    {
      "path": "/api/portfolio/catalog/search",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.catalog.query",
      "bulk_export": false,
      "server_entitlement_required": true
    },
    {
      "path": "/api/portfolio/catalog/purchased-results/{result_id}/export",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.catalog.purchased_result.export",
      "subject_binding_required": true,
      "server_entitlement_required": true
    },
    {
      "path": "/api/portfolio/catalog/company/{company_tenant_id}/export",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.catalog.export",
      "tenant_binding_required": true,
      "server_entitlement_required": true
    },
    {
      "path": "/api/portfolio/catalog/admin/export",
      "methods": [
        "GET"
      ],
      "required_grant": "aclasa.catalog.admin.export",
      "portfolio_superadmin_required": true,
      "mfa_step_up_required": true,
      "immutable_audit_required": true
    }
  ],
  "handoff_sources": [
    {
      "source": "talentaccess.pro",
      "expected_use": "Company workspace initiates the backend OIDC flow for an active employer user.",
      "server_requirement": "Use a short-lived one-time state-bound authorization handoff; verify it on the backend before creating the ACLASA session cookie."
    },
    {
      "source": "paygapanalyzer.pro",
      "expected_use": "Pay-gap admin or analyst initiates the same backend OIDC flow for the authorized company.",
      "server_requirement": "Resolve the provisioned user and tenant on the backend and compute product grants only for that tenant."
    }
  ],
  "storage_policy": {
    "aclasa_default": "Public static storage contains only the approved SK/EN, IT/EN, GR/EN and ES/EN preview JSON projections and direct 10-page preview PDFs. LT/EN private preview and every full pack stay outside public static storage.",
    "company_layer": "Future server-side employer wording keyed by stable section ID and company tenant; this persistence is not deployed in the current static portal.",
    "production_session": "Opaque backend session cookie only; no browser storage or window-global session claims.",
    "production_persistence": "Required server-side company record or approved document store; unavailable and fail-closed in the current static deployment.",
    "localhost_demo": "A clearly labelled local-only browser-storage fixture may be used on loopback hosts and has no production authority."
  },
  "local_demo_policy": {
    "allowed_hosts": [
      "localhost",
      "127.0.0.1",
      "::1"
    ],
    "allowed_protocols": [
      "http:",
      "https:"
    ],
    "forbidden_contexts": [
      "file: URLs",
      "public preview domains",
      "custom production domains"
    ],
    "fixture_role": "org_admin",
    "warning": "Local demo claims are test fixtures only and must never be accepted by a production backend."
  },
  "audit_events": [
    "portfolio_session_resolved",
    "portfolio_session_denied",
    "methodology_workspace_opened",
    "methodology_resource_denied",
    "company_wording_saved",
    "company_wording_exported_json",
    "company_wording_exported_pdf",
    "company_wording_submitted_for_review",
    "company_wording_approved",
    "catalog_query",
    "catalog_export_requested",
    "catalog_export_delivered",
    "catalog_export_denied"
  ],
  "paid_access_policy": {
    "public_preview": "SK/EN, IT/EN, GR/EN and ES/EN provide an online preview and direct 10-page PDF without login. LT/EN has no public preview; LV/EN has no document.",
    "full_methodology": "A backend-verified company user must have an active paid ACLASA methodology program whose exact country code matches the requested SK/EN, IT/EN, GR/EN, ES/EN or LT/EN pack, plus the required operation grant.",
    "electronic_download": "Available pack-specific formats require aclasa.methodology.download and are served only by protected backend routes after a fresh entitlement check. SK/IT/GR/ES provide full PDF; LT retains legacy PDF/DOCX.",
    "employer_editing": "Production employer editing is disabled in the current static deployment. It may become available only after the backend authorizes aclasa.methodology.draft for the active company tenant and the tenant-bound company-layer persistence endpoint is deployed.",
    "program_period": "Backend server time and backend program records determine validity; browser-provided dates do not unlock paid actions.",
    "position_catalog": "One governed ACLASA base reference profile is available anonymously for each of the 436 ISCO-08 units, together with 26 explicitly allowlisted market-title profiles needed for exact title results. The remaining 498 profiles in the protected 960-profile multi-seniority catalog and every bulk export remain unavailable anonymously. Candidates may export only purchased or entitled results; companies may use only their contracted tenant scope; portfolio-superadmin export requires MFA step-up and immutable audit.",
    "payment_quality_rule": "A successful payment does not unlock or settle a low-quality, failed or undelivered analysis. Product entitlement and quality-delivery evidence are separate server-side decisions.",
    "private_preview": "The LT/EN 10-page preview is delivered only through a server-verified protected channel for the exact active Lithuania program."
  },
  "public_read_only_tracker_exports": {
    "scope": "PUBLIC_READ_ONLY_EXISTING_COUNTRY_BRIEFS_AND_REVIEW_JOURNAL",
    "classification": "Public source-bound narrative snapshot only; no protected-resource or product entitlement is conferred.",
    "files": {
      "en": "ACLASA_Public_Country_Tracker_en_2026-10-30.xlsx",
      "sk": "ACLASA_Public_Country_Tracker_sk_2026-10-30.xlsx",
      "de": "ACLASA_Public_Country_Tracker_de_2026-10-30.xlsx",
      "fr": "ACLASA_Public_Country_Tracker_fr_2026-10-30.xlsx",
      "es": "ACLASA_Public_Country_Tracker_es_2026-10-30.xlsx",
      "pt": "ACLASA_Public_Country_Tracker_pt_2026-10-30.xlsx",
      "nl": "ACLASA_Public_Country_Tracker_nl_2026-10-30.xlsx",
      "cs": "ACLASA_Public_Country_Tracker_cs_2026-10-30.xlsx",
      "hu": "ACLASA_Public_Country_Tracker_hu_2026-10-30.xlsx",
      "ro": "ACLASA_Public_Country_Tracker_ro_2026-10-30.xlsx",
      "bg": "ACLASA_Public_Country_Tracker_bg_2026-10-30.xlsx",
      "hr": "ACLASA_Public_Country_Tracker_hr_2026-10-30.xlsx",
      "sl": "ACLASA_Public_Country_Tracker_sl_2026-10-30.xlsx",
      "da": "ACLASA_Public_Country_Tracker_da_2026-10-30.xlsx",
      "sv": "ACLASA_Public_Country_Tracker_sv_2026-10-30.xlsx",
      "fi": "ACLASA_Public_Country_Tracker_fi_2026-10-30.xlsx",
      "et": "ACLASA_Public_Country_Tracker_et_2026-10-30.xlsx",
      "lv": "ACLASA_Public_Country_Tracker_lv_2026-10-30.xlsx",
      "el": "ACLASA_Public_Country_Tracker_el_2026-10-30.xlsx",
      "ga": "ACLASA_Public_Country_Tracker_ga_2026-10-30.xlsx",
      "mt": "ACLASA_Public_Country_Tracker_mt_2026-10-30.xlsx",
      "ar": "ACLASA_Public_Country_Tracker_ar_2026-10-30.xlsx",
      "hi": "ACLASA_Public_Country_Tracker_hi_2026-10-30.xlsx",
      "id": "ACLASA_Public_Country_Tracker_id_2026-10-30.xlsx",
      "ja": "ACLASA_Public_Country_Tracker_ja_2026-10-30.xlsx",
      "ko": "ACLASA_Public_Country_Tracker_ko_2026-10-30.xlsx",
      "tr": "ACLASA_Public_Country_Tracker_tr_2026-10-30.xlsx",
      "zh": "ACLASA_Public_Country_Tracker_zh_2026-10-30.xlsx",
      "it": "ACLASA_Public_Country_Tracker_it_2026-10-30.xlsx",
      "lt": "ACLASA_Public_Country_Tracker_lt_2026-10-30.xlsx",
      "pl": "ACLASA_Public_Country_Tracker_pl_2026-10-30.xlsx",
      "ru": "ACLASA_Public_Country_Tracker_ru_2026-10-30.xlsx",
      "uk": "ACLASA_Public_Country_Tracker_uk_2026-10-30.xlsx",
      "sr": "ACLASA_Public_Country_Tracker_sr_2026-10-30.xlsx",
      "vi": "ACLASA_Public_Country_Tracker_vi_2026-10-30.xlsx"
    },
    "sourceSha256": "4da2d118dda5ba6a826c0d040ba90d1b970851d40f1fa8e39c2fe621f60577ed",
    "primaryClocks": {
      "lastSourceCheckAt": "2026-10-24T04:26:37Z",
      "operationalContentUpdatedAt": "2026-10-24T04:26:37Z",
      "contentUpdatedAt": "2026-10-24T04:26:37Z"
    },
    "excluded": [
      "private/employer/payroll/personal records",
      "systematic job scoring and catalog export",
      "paid country-intelligence and methodology packs",
      "country-cost/living/minimum/market/adequate wage calculations",
      "professional legal/language/methodology acceptance",
      "server/session/tenant/grant changes"
    ],
    "preserved_protected_rule": "Every paid methodology/catalog/country pack/employer export retains its existing independent server grant/tenant/program check.",
    "qualified_review": "NOT_PERFORMED; source/review/effective dates and unresolved verification remain explicit.",
    "native_manifest": "/data/tracker-full35-xlsx-manifest.json"
  },
  "country_pack_publication_policy": {
    "as_of": "2026-10-15",
    "public_preview_packs": [
      "sk-en",
      "it-en",
      "gr-en",
      "es-en"
    ],
    "private_preview_packs": [
      "lt-en"
    ],
    "excluded_packs": [
      "lv-en"
    ],
    "public_preview_data_routes": {
      "sk-en": "/data/aclasa-country-pack-sk-en-preview.json",
      "it-en": "/data/aclasa-country-pack-it-en-preview.json",
      "gr-en": "/data/aclasa-country-pack-gr-en-preview.json",
      "es-en": "/data/aclasa-country-pack-es-en-preview.json"
    },
    "public_preview_pdf_routes": {
      "sk-en": "/downloads/methodology/ACLASA_Country_Pack_SK_EN_v1_1_2026-10-15_Preview.pdf",
      "it-en": "/downloads/methodology/ACLASA_Country_Pack_IT_EN_v1_1_2026-10-15_Preview.pdf",
      "gr-en": "/downloads/methodology/ACLASA_Country_Pack_GR_EN_v1_0_2026-10-15_Preview.pdf",
      "es-en": "/downloads/methodology/ACLASA_Country_Pack_ES_EN_v1_0_2026-10-15_Preview.pdf"
    },
    "public_preview_pages": 10,
    "lithuania_rule": "LT/EN has a private 10-page preview and protected full files only. No public preview JSON or PDF route may be published.",
    "latvia_rule": "LV/EN remains excluded without a preview or full document because the enacted national legal basis is insufficient for a controlled pack.",
    "full_route_template": "/api/portfolio/methodology/packs/{pack}/{format}",
    "full_formats": [
      "json",
      "pdf"
    ],
    "full_routes_fail_closed": true,
    "source_review_completed_at": "2026-10-17T10:05:32+02:00",
    "source_review_status": "PASS_WITH_SCOPED_BLOCKERS",
    "full_formats_by_pack": {
      "sk-en": [
        "json",
        "pdf"
      ],
      "it-en": [
        "json",
        "pdf"
      ],
      "gr-en": [
        "json",
        "pdf"
      ],
      "es-en": [
        "json",
        "pdf"
      ],
      "lt-en": [
        "json",
        "pdf",
        "docx"
      ]
    },
    "docx_available_for_packs": [
      "lt-en"
    ],
    "wpcg_docx_status": "WITHHELD_NO_MATCHING_ACCEPTED_SOURCE_PARITY"
  }
}
