> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dirtview.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Certifications and expiry tracking

> Uploading a card, how expiry dates get read, and where the expired or expiring-soon warning shows up.

export const Video = ({id, title, runtime, url}) => {
  const meta = VIDEOS[id] || ({});
  const label = title || meta.title || "Tutorial video";
  const length = runtime || meta.runtime || "";
  const track = meta.track || "";
  const src = toEmbedUrl(url || meta.url);
  const frame = {
    position: "relative",
    width: "100%",
    paddingTop: "56.25%",
    borderRadius: "10px",
    overflow: "hidden",
    background: "rgba(127,127,127,0.09)",
    border: src ? "1px solid rgba(127,127,127,0.24)" : "1px dashed rgba(127,127,127,0.42)"
  };
  const fill = {
    position: "absolute",
    inset: 0,
    width: "100%",
    height: "100%",
    border: 0
  };
  const center = {
    position: "absolute",
    inset: 0,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    gap: "10px",
    padding: "24px",
    textAlign: "center"
  };
  const idBadge = {
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
    fontSize: "12px",
    letterSpacing: "0.06em",
    padding: "2px 8px",
    borderRadius: "4px",
    background: "rgba(184,82,40,0.14)",
    color: "#B85228",
    fontWeight: 600
  };
  const caption = {
    display: "flex",
    flexWrap: "wrap",
    alignItems: "center",
    gap: "8px",
    marginTop: "8px",
    fontSize: "13px",
    opacity: 0.66,
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace"
  };
  return <div style={{
    margin: "0 0 28px"
  }}>
      <div style={frame}>
        {src ? <iframe style={fill} src={src} title={label} frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" allowFullScreen /> : <div style={center}>
            <svg width="44" height="44" viewBox="0 0 44 44" fill="none" aria-hidden="true">
              <circle cx="22" cy="22" r="20" stroke="currentColor" strokeOpacity="0.28" strokeWidth="2" />
              <path d="M18 15.5L29 22L18 28.5V15.5Z" fill="currentColor" fillOpacity="0.32" />
            </svg>
            <div style={{
    fontWeight: 600,
    fontSize: "15px",
    maxWidth: "36ch",
    lineHeight: 1.35
  }}>{label}</div>
            <div style={{
    fontSize: "13px",
    opacity: 0.6
  }}>
              Video coming soon{length ? " · " + length : ""}
            </div>
          </div>}
      </div>
      <div style={caption}>
        {id ? <span style={idBadge}>{id}</span> : null}
        {length ? <span>{length}</span> : null}
        {track ? <span>{track} track</span> : null}
      </div>
    </div>;
};

<Video id="80.3" />

<Note>
  **The short version.** Upload a photo of the card. DirtView reads the expiry date and warns you before it lapses.
</Note>

## Upload a card

<Steps>
  <Step title="Open the employee">
    Left menu → Employees → the person.
  </Step>

  <Step title="Add the certification and upload a photo of the card">
    A clear, flat photo. The expiry date gets read off the card.

    → How the extraction works: [Certifications Extract](/ai/extract-tools)
  </Step>

  <Step title="Check the date it read">
    Always check. A misread expiry date is worse than no date, because you stop watching for it.
  </Step>
</Steps>

## Expiring and expired

<Warning>
  Until the notification behaviour above is confirmed, don't rely on DirtView to be the only thing watching an expiry that can put someone off the job. Keep your existing check as well.
</Warning>

## Next

<CardGroup cols={2}>
  <Card title="The six roles" icon="shield-halved" href="/people/built-in-roles">
    Who to assign to whom.
  </Card>

  <Card title="Custom roles" icon="table-list" href="/people/custom-roles">
    Building your own.
  </Card>
</CardGroup>
