* feat(org): add dynamic open graph images for school sites
Generate branded 1200x630 OG images for org public sites via GET /org/og/:siteName.png.
Paying cloud orgs include their landing-page tagline; free plans show a Powered by
ClassroomIO watermark. Dashboard org-site meta tags now point at the dynamic image.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* feat(org): enable custom favicon upload and org-site rendering
Allow org admins to upload a favicon from domain settings, persist it via
PUT /organization, and render it on public org sites with logo fallback.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* fix(org): scope custom favicon to public org-site routes only
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* refactor(api): inline org-site OG rendering, remove @cio/og-images package
Move template and render helpers into apps/api/src/utils/org-site-og.ts.
Certificates stay in a shared package because they support multiple templates;
org OG is a single API-only concern.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* chore: remove packages/og-images directory
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* refactor(api): mount org OG image under /org-site/og
Align with existing org-site public routes (/org-site/course) instead of a
top-level /org prefix.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* refactor(plans): consolidate isOrgOnFreePlan into options-based utility
Move orgId guard and self-hosted/plan checks into @cio/utils/plans.
Dashboard and API callers pass plans, isSelfHosted, and optional orgId
directly; remove the dashboard store wrapper.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* fix(org): require orgId for free-plan check and translate favicon strings
Treat missing orgId as not on free plan so nav gating matches prior
behavior when currentOrg is unset. Pass organization.id from OG service.
Add favicon settings translations for all non-English locales.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* refactor(dashboard): move meta tag helpers to metaTags.server.ts
Keep PRIVATE_SERVER_URL resolution in a server-only module so dynamic
private env imports cannot leak into universal or client bundles.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* fix(dashboard): allow File favicon in org update before upload
Skip favicon from pre-upload Zod validation when a File is provided,
matching how avatar uploads bypass ZUpdateOrganization until resolved.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* fix(dashboard): use public API URL for org OG meta tags
Never emit PRIVATE_SERVER_URL in og:image URLs. Prefer PUBLIC_SERVER_URL
for crawlers; fall back to same-origin /proxy when unset.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* fix(dashboard): use org landing copy and public OG URLs for org sites
Populate og:title, description, and site_name from org landing page hero
copy on cloud tenant sites. Build og:image from the tenant origin /proxy
path so crawlers never receive internal PRIVATE_SERVER_URL values.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
* feat(api): redesign org OG image with logo top-left
Replace the saturated gradient layout with a light theme-tinted card:
Academy label, org name, and tagline bottom-left; logo top-left;
decorative circle top-right; watermark on free plans.
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>