ccf-deadlines Documentation

Agenticly track ccf-ranked & worldwide conference deadlines (Website, Python Cli, Wechat Applet)

RAW Doc

Technical Documentation: ccfddl/ccf-deadlines

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

CCF-Deadlines

Helping researchers track worldwide conference ddls through (agentic) collaboration.



English | 简体中文

🌐 Website PortalMain Site 📱 Wechat AppletAvailable Now 🌐 Tabular PortalNo Ladder Required

Extensions

PyCli Tool Raycast Extension SwiftBar Plugin
iCal Subscription Chrome Extension TUI App

MCP

CCFDDL provides a read-only Model Context Protocol (MCP) server for AI clients to search conferences, check published deadlines and opening dates, and retrieve historical acceptance rates. It supports CCF/CORE/THCPL filters, pagination, and timezone conversion.

Connect using Streamable HTTP at https://ccfddl.com/mcp.

See the MCP README for details.

Community Activity

Add/Update a conference

Contributions are welcomed and greatly appreciated!

To add or update information:

  • Fork the repo
  • Add/Update the yml file of conference/conf_type/conf_name.yml
  • Send a pull request

Tips: check conferences recommended or review pdf

Conference Entry File

Example file: conference/DB/sigmod.yml

yaml
- title: SIGMOD
  description: ACM Conference on Management of Data
  sub: DB
  rank:
    ccf: A
    core: A*
    thcpl: A
  dblp: sigmod
  confs:
    - year: 2022
      id: sigmod22
      link: http://2022.sigmod.org/
      timeline:
        - deadline: '2021-07-02 17:00:00'
          comment: 'first round'
        - deadline: '2021-09-15 17:00:00'
          comment: 'second round'
      timezone: UTC-8
      date: June 12-17, 2022
      place: Philadelphia, PA, USA

Description of the fields:

Field name Description
title* Short conference name, without year, uppercase
description* Description, or long name, with no session
sub* The category that the conference is labeled by CCF. See the matching table below
rank* ccf* The level that the conference is ranked by CCF, e.g., A, B, C, N
core The level that the conference is ranked by CORE, e.g., A*, A, B, C, N
thcpl The level that the conference is ranked by TH-CPL, e.g., A, B, N
dblp* The suffix in dblp url, e.g., iccv in https://dblp.org/db/conf/iccv
confs year* Year the conference is happening
id* conference name & year, lowercase
link* URL to the conference home page
timeline* abstract_deadline Abstract deadline if applicable, optional
deadline* Submission Deadline, in the format of yyyy-mm-dd hh:mm:ss or TBD
rebuttal_deadline Rebuttal or author-response deadline for this round, optional
decision_deadline Final decision deadline for this round, optional
comment Some comments on the conference, optional
timezone* Timezone of deadline, currently support UTC-12 ~ UTC+12, AoE & PT (US Pacific Time, auto-adjusts for daylight saving)
date* When the main conference is happening, e.g., Mar 12-16, 2021
place* Where the main conference is happening, e.g., city, country

Fields marked with asterisk (*) are required.

Deadline defaults are repository conventions: when an official source gives a
calendar date but no clock time, use 23:59:59 on that date. When the source does
not specify a timezone, use AoE. Document these defaults in comments where
appropriate; do not present them as times or zones stated by the source. A truly
unpublished date remains TBD. Resolve explicit conflicting dates from reliable
official evidence rather than choosing one arbitrarily.

The matching table:

sub Category name
DS Computer Architecture/Parallel Programming/Storage Technology
NW Network System
SC Network and System Security
SE Software Engineering/Operating System/Programming Language Design
DB Database/Data Mining/Information Retrieval
CT Computing Theory
CG Graphics
AI Artificial Intelligence
HI Computer-Human Interaction
MX Interdiscipline/Mixture/Emerging

Contribution

Maintained by @ccfddl collaboration.

License


Overview (`worker/README.md`)

CCFDDL API

This Cloudflare Worker handles GitHub sign-in, per-edition conference favorites, the public message wall, email reminders, and the public read-only MCP service. The static site calls it through the same-origin /api/* route. MCP clients can connect to https://ccfddl.com/mcp; see the MCP README for tools and parameters. It also redirects existing /conference/deadlines_* calendar and RSS subscriptions to /conference/deadlines/.

1. Create the GitHub OAuth app

Create an OAuth app in GitHub with:

  • Homepage URL: https://ccfddl.com
  • Authorization callback URL: https://ccfddl.com/api/auth/github/callback
  • Application logo: upload assets/ccfddl-oauth-logo.png

Normal sign-in requests no OAuth scope. When a signed-in user explicitly enables email reminders, a separate GitHub authorization requests user:email to read their verified primary email address. The Worker does not store the GitHub access token.

GitHub setup references: creating an OAuth app and the web application flow.

2. Create and migrate D1

bash
cd worker
npm install
npx wrangler login
npx wrangler d1 create ccfddl

Copy the returned database ID into wrangler.jsonc, then run:

bash
npm run db:migrate:remote

Cloudflare references: D1 setup and bindings and D1 migrations.

3. Configure secrets

bash
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put SESSION_SECRET

Use a cryptographically random value of at least 32 bytes for SESSION_SECRET.

To enable email reminders, verify a sending domain with Resend and configure:

bash
npx wrangler secret put RESEND_API_KEY
npx wrangler secret put EMAIL_FROM

EMAIL_FROM is a verified sender, for example CCFDDL <[email protected]>. Keep both values in Worker secrets, not in the repository.

4. Deploy

The ccfddl.com DNS record must be proxied through Cloudflare so the Worker route can intercept /api/* while GitHub Pages continues to serve every other path.

bash
npm run check
npm run deploy

One deployment updates the API, email scheduler, and MCP service together. After deployment, verify https://ccfddl.com/api/health returns {"ok":true} before publishing the static frontend changes, then connect an MCP client and call search_conferences or get_acceptance_rates.

When a new migration is added, apply the migration before deploying the Worker version that uses it. The message wall requires migrations 0002 through 0006. Migration 0006 enforces posting limits atomically in D1; deploy it before this Worker version to keep message posting working. It preserves existing daily quotas in a separate counter, avoiding double-counting while the previous Worker is still running. Email reminders require migrations 0007 and 0008; migration 0008 adds the optional daily mode, off by default for existing users. Migration 0009 backfills favorite counts and keeps them current with database triggers; apply it before deploying the Worker that queries conference_star_counts. Migration 0010 indexes email send dates for daily retention cleanup. Deploy the static site with /conference/deadline_events.json before enabling the sender secrets and deploying this Worker version.

Security configuration

  • All cookie-authenticated writes require an Origin matching PUBLIC_ORIGIN; cross-site fetch metadata is rejected. CLI clients must also send this header.
  • OAuth state is signed and expires after 10 minutes on the server. PKCE remains enabled. Login return paths reject backslashes and control characters.
  • Sessions use random, hashed tokens and HttpOnly cookies with Secure and the __Host- prefix on HTTPS, preventing subdomain cookie injection. Local HTTP development uses unprefixed cookies. Existing users will need to sign in once after this cookie-name update. Expired sessions are removed during login; each account keeps at most 20 sessions.
  • Sessions use a rolling 30-day expiry. Authenticated website use renews both the D1 session expiry and the browser cookie at most once per day, setting each to 30 days from renewal. Active sessions have no fixed total lifetime limit; signing out immediately revokes the current session. No database migration is required for renewal.
  • JSON bodies are limited to 8 KiB while streaming. Messages retain their 500-character limit and are displayed as plain text.
  • Rate-limit bindings in wrangler.jsonc allow 10,000 API requests per minute per IP, 300 OAuth requests per minute per IP, and 600 authenticated writes per minute per account. The generous API limit allows shared networks; adjust the namespaces if they already belong to another Worker in your Cloudflare account. These edge limits apply per Cloudflare location, while the message quota is enforced globally in D1.
  • The database trigger enforces 10 posts per UTC day and a 30-second cooldown, including replies. Deleting a message cannot reset either limit. A failed insert does not consume quota.
  • API responses include nosniff, a restrictive CSP, and a no-referrer policy. Operational failures return a generic error rather than sensitive details.

The rate-limit bindings are deployed with the Worker configuration. No extra secret is required. See the Cloudflare rate-limit binding documentation.

Worker logs are enabled in wrangler.jsonc. After deployment, view diagnostic logs in Workers & Pages → ccfddl-api → Observability. Automatic invocation logs are disabled to avoid storing OAuth callback URLs containing authorization codes. Login failures include a safe stage-specific code in the JSON response; logs omit codes, tokens, cookies, secrets, and raw upstream error messages.

To test migration and concurrency behavior locally:

bash
python -m unittest discover -s ../scripts -p 'test_*.py'
npm test

Message wall

  • Anyone can read the latest 50 messages; signed-in users can page through all older messages.
  • A GitHub sign-in is required to post and to delete a message.
  • Users can only delete their own messages.
  • Signed-in users can like any message, including their own. The most-liked view ranks messages posted in the last 30 days.
  • Signed-in users can reply to top-level messages; replies are loaded in pages and support likes.
  • Messages are limited to 500 characters and eight lines.
  • Each account can post up to 10 messages per UTC day and must wait 30 seconds between messages.

Favorites calendar subscription

Favorite totals are read from conference_star_counts, maintained by triggers on conference_stars. Guest requests use a five-minute edge cache to avoid reading D1 on every page load and can show totals up to five minutes old. Signed-in requests read fresh totals from D1, as well as the user's own favorite state.

Signed-in users can select up to 100 starred conference editions from Batch Subscribe in the account menu. The resulting public webcal:///HTTPS link contains only the selected edition IDs and can be added once to a calendar app. The Worker filters the static /conference/deadlines/deadlines_en.ics or deadlines_zh.ics feed when the calendar app refreshes; the deployment workflow regenerates those files from conference YAML. No new D1 migration or secret is needed. Anyone with a subscription link can see its selected conference IDs. To change the selection, copy a new link and replace the old subscription.

Deploy the static site with the updated calendar generator before enabling this Worker endpoint: new calendar events carry an X-CCFDDL-ID field that the Worker uses to select editions. In conference details, Google Calendar provides a direct event link for each known deadline, while iCloud Calendar downloads a one-time ICS containing all known deadlines for that edition. Only the batch link is a refreshing feed. Google Calendar requires adding the subscription HTTPS link from Other calendars → From URL on a computer; iCloud/Apple Calendar can open the batch webcal:// link directly.

Email reminders

The account menu offers an optional Email Reminders setting. Enabling it starts a separate GitHub OAuth authorization for user:email. The Worker reads the verified primary address from GitHub, stores that address and the chosen time zone/language in D1, and discards the access token. Users can change the time zone/language, reauthorize to refresh the address, toggle daily reminders, or turn reminders off. Every email also includes a signed unsubscribe link.

The static deployment generates /conference/deadline_events.json from the same English ICS calendar used for subscriptions. A Cron Trigger runs every 15 minutes in UTC and sends at most one combined email per user's local date at or shortly after 09:00. By default, it includes starred-conference deadlines 7 or 1 local calendar days away. With daily reminders enabled, it instead includes every future deadline from starred conferences, and sends on each day that at least one future deadline remains. D1 records each daily send, and Resend receives an idempotency key so a retry cannot intentionally send a duplicate. If the sender secrets are absent, the job skips sending and the UI reports reminders unavailable. Monitor Worker logs for delivery errors and the Resend dashboard for accepted messages. Sender quota and verified-domain limits depend on the Resend account plan.

At 00:00 UTC each day, the Cron Trigger deletes email_digest_sends rows whose local date is more than seven days old, including any stale pending payloads. Recent rows preserve same-day retry and duplicate protection while limiting retained email content.

Stored data

D1 stores the GitHub numeric user ID, login, avatar/profile URLs, hashed site sessions, one row per user/conference-edition favorite, message wall content, likes, and timestamps. Email reminders additionally store the verified primary email, chosen time zone/language, daily-mode setting, and recent send records for about seven days. Each edition uses its existing unique conference id, such as iclr27, so different years have independent totals.


Overview (`extensions/chrome/README.md`)


Preview

The v2.0 popup focuses on density and speed: compact top cards, a persistent import panel, a floating conference picker, footer shortcuts, and a lightweight settings popover.


Install

Chrome Web Store

Install directly from the Chrome Web Store:

Load Unpacked

  1. Open Chrome and visit chrome://extensions/.
  2. Enable Developer mode.
  3. Click Load unpacked.
  4. Select the chrome/ directory in this repository.
  5. Pin CCF DDL Tracker to the toolbar and click the icon to use it.

Need more extension-specific details?

See chrome/README.md for the extension-only guide.


Highlights

  • Native popup experience: Clicking the extension icon opens a compact Chrome popup instead of a separate window.
  • Manual + imported deadlines: You can add custom deadlines or import recommended conferences from CCFDDL.
  • Official site shortcuts: Imported conferences retain homepage links, and added cards can open the conference website directly.
  • Bilingual UI: Switch between Chinese and English from the bottom toolbar.
  • Display preferences: Choose 24-hour or 12-hour time, and switch date order between YYYY/MM/DD and MM/DD/YYYY.
  • Local-only data: All data stays in chrome.storage.local, with no account or cloud sync.

Customization

  • Language: Toggle between Chinese and English from the popup footer.
  • Time format: Choose 24-hour or 12-hour (AM/PM) in the settings panel.
  • Date order: Choose YYYY/MM/DD or MM/DD/YYYY.
  • Imported conference cards: Imported items can be added to your own list and opened directly on the conference website.

Data Source & Privacy

  • Primary source: ccfddl/ccf-deadlines
  • Fallback: CCFDDL ICS feeds when GitHub data is unavailable
  • Storage: chrome.storage.local
  • Privacy: no account, no cloud sync, no telemetry

Development


Changelog

v2.0 - UI overhaul, import improvements, settings, and versioning

  • Reworked the popup into a denser layout with two entry cards and a bottom utility bar
  • Kept the import panel visible by default while moving recommendations into a floating search picker
  • Imported conferences now keep homepage links and added cards can open the official conference site
  • Added display settings for 24-hour / 12-hour time and year-month-day / month-day-year date order
  • Added a v2.0 version label in the popup header and bumped the extension version

v1.0.1 - Refresh and day-count fixes

  • Fixed automatic date refresh issues
  • Added a manual refresh button
  • Corrected same-day deadlines to display 0 days

License

MIT License


Overview (`extensions/cli/readme.md`)

ccfddl cli

CLI tool for CCFDDL - Conference Deadline Tracker

Install

bash
pip install -e ".[dev]"

Usage

bash
# Show help
ccfddl --help

# List all categories
ccfddl --list-categories

# Filter by conference, subcategory, rank
ccfddl --conf CVPR ICCV --sub AI --rank A

# JSON output
ccfddl --json --sub AI

# Show version
ccfddl --version

Arguments

| Argument | Type | Description | Example |
| -------- | ----- | -------------------------------- ----| ------------------ |
| --conf | str[] | A list of conference IDs to filter. | --conf CVPR ICCV |
| --sub | str[] | A list of subcategory IDs to filter. | --sub AI CG |
| --rank | str[] | A list of ranks to filter. | --rank A B |
| --json | flag | Output in JSON format. | --json |
| --list-categories | flag | List all categories. | --list-categories|
| --url | str | Custom URL for conference data. | --url https://...|
| --version | flag | Show version. | --version |

Generate iCal/RSS Feeds

bash
# Generate iCal files (requires xlin package)
python -m ccfddl.convert_to_ical

# Generate RSS files
python -m ccfddl.convert_to_rss

# From the repository root, declare self links for published feeds
python extensions/cli/ccfddl/convert_to_rss.py --output-dir feeds --feed-base-url https://example.com/feeds/

--feed-base-url adds an RSS atom:link rel="self" for each published feed,
including language and ranking/category variants. Omit it for local exports
whose public URL is unknown.

Project Structure

text
ccfddl/
├── __init__.py      # Package entry, exports public API
├── __main__.py      # CLI entry point
├── fetch.py         # Data fetching and processing
├── output.py        # Output formatting (table, JSON)
├── models.py        # Data models
├── utils.py         # Utility functions
├── convert_to_ical.py
├── convert_to_rss.py
└── tests/           # Test suite

Development

bash
# Install dev dependencies
pip install -e ".[dev]"

# Run tests
python -m pytest ccfddl/tests/ -v

# Run tests with coverage
python -m pytest ccfddl/tests/ --cov=ccfddl --cov-report=html

# Type checking
mypy ccfddl/

Python API

python
from ccfddl import (
    # Models
    Conference, ConferenceYear, Timeline, Rank, Category,
    CATEGORIES, VALID_SUBS,
    get_category_by_sub, get_all_subs, is_valid_sub,
    # Utils
    load_mapping, get_timezone, reverse_index,
    format_duration, parse_datetime_with_tz,
    # Fetch & Output
    fetch_conferences, process_conference_deadlines, filter_results,
    output_table, output_json, list_categories,
)

# Get category info
cat = get_category_by_sub("AI")
print(cat.name)  # 人工智能
print(cat.name_en)  # Artificial Intelligence

# Parse timezone
from datetime import datetime
tz = get_timezone("UTC+8")
dt = datetime(2025, 1, 15, 23, 59, 59, tzinfo=tz)

Overview (`extensions/ical/readme.md`)

iCal Subscription:

  • English: https://ccfddl.com/conference/deadlines/deadlines_en.ics
  • 简体中文: https://ccfddl.com/conference/deadlines/deadlines_zh.ics

Calendar (.ics) and RSS (.xml) feeds are published in /conference/deadlines/. Existing /conference/deadlines_*.ics and .xml subscriptions redirect to the new folder through the Cloudflare Worker.

The deployment generates files directly in that folder using --output-dir public/conference/deadlines. Without --output-dir, the CLI still writes to the current directory.

The filter is mapped to the name of iCal file in the following rules:

  • no filter: deadlines_en.ics and deadlines_zh.ics
  • one filter: deadlines_{lang}_{ccf_rank}.ics, deadlines_{lang}_{core_rank}.ics, deadlines_{lang}_{thcpl_rank}.ics, or deadlines_{lang}_{sub}.ics
  • two filters: any ordered pair among ccf_rank, core_rank, thcpl_rank, and sub
  • three filters: any ordered triple among ccf_rank, core_rank, thcpl_rank, and sub
  • four filters: deadlines_{lang}_{ccf_rank}_{core_rank}_{thcpl_rank}_{sub}.ics

For example, given filter: lang=en, core=A, thcpl=B, sub=SE, it will refer to deadlines_en_core_A_thcpl_B_SE.ics.

For A*, the generated filename uses Astar, for example deadlines_en_core_Astar_SE.ics.


Overview (`worker/mcp/README.md`)

CCFDDL MCP plugin

This is a public, read-only MCP server for conference search, published deadlines and historical acceptance statistics. It runs inside the same ccfddl-api Cloudflare Worker as the site's API, at https://ccfddl.com/mcp using Streamable HTTP. It reads https://ccfddl.com/conference/allconf.json and https://ccfddl.com/conference/allacc.json with independent 15-minute in-isolate caches. MCP tools do not use D1 or site sessions.

Source files are under worker/src/mcp/, tests are under worker/test/mcp_*.test.js, and the portable plugin package is under worker/mcp/plugin/ccfddl/. The shared dependencies and deployment configuration are in worker/package.json and worker/wrangler.jsonc.

Tools:

  • get_filter_options: subject codes with English/Chinese names, CCF/CORE/THCPL rankings, edition years, and supported event types.
  • search_conferences: name, description, conference key, subject, CCF/CORE/THCPL rank, and edition year search, with the latest known acceptance statistics up to that edition year.
  • get_conference: recent editions, known deadline nodes, derived conference openings, DBLP identifier, and historical acceptance statistics. Accepts a name, name plus year, edition ID, or returned conference key.
  • get_acceptance_rates: historical acceptance rates, submitted and accepted paper counts, percentages and sources, filtered by statistical year or inclusive year range and paginated newest first.
  • upcoming_deadlines: future nodes within a specified time window, filtered by ranking, subject, edition year, and node type, with the latest known historical acceptance statistics up to the edition year.

Search and upcoming results include total, offset, limit, and next_offset. Pass next_offset as the next request's offset; null means the final page. The default limit is 20 and the maximum is 50. Filters use the conference edition year, which can differ from the year of its submission deadline. Rank N selects unranked conferences, including entries without that ranking.

For namesakes such as FSE, get_conference returns ambiguous: true and candidate matches inside conference. Retry with a returned conference_key or a category instead of assuming the first result is correct. Named lookups return up to six editions by default; edition_limit can request up to 20. Conference details include editions_total, the number of catalog editions matching the requested name, year or edition ID before applying the limit. Compare it with editions.length to detect omitted history, then raise edition_limit or query a specific year or edition ID. The count describes listed records, not every edition ever held; ambiguous and not-found results have no count.

get_conference and upcoming_deadlines accept display_timezone (an IANA name such as Asia/Shanghai). Responses retain the source local_time, timezone, and utc_time, and add display_time and display_timezone for known dates. Unknown dates have no converted instant.

Conference results include series_url for a CCFDDL series history and venue_url for the corresponding annual page. In search results, venue_url matches latest_edition, respecting a requested year. Cite venue_url for year-specific deadline claims and retain website as the official conference source. Invalid identities or years do not produce guessed page URLs.

Conference opening values are countdown timestamps derived from the earliest announced first day in the edition's date text. The data builder assigns a default 08:00 hour in the edition's submission timezone. opening_utc and opening_display_time are conversions of this derived value, not verified local event start times. Cite the original date text for conference dates and consult the official conference website for actual start times and the event's local timezone. This distinction also applies to upcoming_deadlines results with deadline_types: ["opening"].

The builder marks generated openings with opening_is_derived: true. MCP copies an explicit boolean source flag when an opening exists, including in upcoming results. Missing openings and legacy records without a declared flag return null; provenance is not guessed from the clock hour. An explicit false reflects only the source declaration and does not verify the actual event start time. The original date text, including tentative-date qualifiers, remains available.

For upcoming nodes, deadline_types accepts abstract_deadline, deadline, rebuttal_deadline, decision_deadline, and opening. The default includes the four submission/review types and excludes openings. Examples:

json
{"days": 30, "category": "AI", "core_rank": "A*", "deadline_types": ["abstract_deadline", "deadline"], "display_timezone": "Asia/Shanghai"}
json
{"days": 90, "year": 2027, "deadline_types": ["opening"], "limit": 50}

The server retains source timezone labels and supplies UTC instants where the source identifies a unique instant. TBD, missing openings, and invalid calendar dates are not converted or predicted. Pacific (PT) clock times skipped or repeated during daylight-saving transitions also stay unconverted: details retain the original local_time and timezone, with null UTC/display values, and upcoming results omit those nodes. A published explicit offset such as UTC-7 or UTC-8 disambiguates a repeated hour; do not guess one. Each response includes the source dataset URL and fetch time. Conference links come from the source data.

Every successful tool response includes stale, referring to the conference catalog. It is true when the 15-minute cache expired and refreshing the source failed, so a cached snapshot was returned. The original fetched_at is preserved. A successful refresh clears the flag; callers share a pending refresh and failures do not extend the cache lifetime. false means the cache has not expired, not that individual deadlines were recently verified. Report stale data as cached and check consequential deadline claims against the official conference source.

Acceptance statistics

get_acceptance_rates requires name_or_id and accepts category, year, from_year, to_year, offset, and limit. Here year refers to the statistics year, independently of whether the deadline catalog contains that edition. A name with a year or an edition ID selects its year; a conflicting explicit year returns no matching statistics. Ranges are inclusive and from_year must not exceed to_year.

json
{"name_or_id": "ICLR", "from_year": 2022, "to_year": 2026, "limit": 20}

Each record contains year, submitted, accepted, rate (a fraction between 0 and 1), rate_percent (a percentage rounded to two decimal places), label, and source (the published record's provenance). A missing numeric rate is derived only from valid counts; labels are never parsed into numbers. Original labels, including the legacy srt field, are retained. Missing values remain null.

Responses distinguish available, missing, ambiguous, unavailable, and not_found statuses. A valid query with no statistics for its year returns missing. ambiguous can mean that the conference name needs disambiguation, or that a chosen conference cannot be safely associated with title-only statistics. If acceptance data has no key or subject metadata, it is joined by title only when that title identifies a single conference. This prevents FSE statistics from being attributed to the wrong conference. Contradictory source numbers are preserved and marked with data_issues (accepted_exceeds_submitted or rate_disagrees_with_counts); they must not be silently corrected or presented without that qualification.

Search and upcoming results add acceptance_status and a nullable latest_acceptance_rate with its own year and provenance. Conference details add acceptance_rates (the newest 10 historical records), acceptance_rates_total, and acceptance_status. Each edition has a nullable exact-year acceptance_rate and up to two recent_acceptance_rates from that year or earlier. The complete history is available through get_acceptance_rates. Historical statistics are not predictions for an upcoming edition or an individual paper.

Tools that read statistics include an acceptance_data envelope with the dataset source, fetched_at, feed status and stale. Acceptance data loads alongside conference data and reports its cache flag independently of the top-level conference-catalog flag. If its source is unavailable and no cached snapshot exists, deadline queries still succeed, statistics are empty or null, their status is unavailable, and acceptance_data.stale is null. A cached snapshot remains available during an outage with its original fetch timestamp and stale: true. A valid refresh clears that flag without changing historical-record or query statuses.

Local verification

From worker/:

bash
npm ci
npm run check
npm run dev

Use MCP Inspector with http://localhost:8787/mcp. Test initialize, tools/list, and each tool call, including empty results and timezone boundaries. /api/health checks the shared Worker; it does not check the data sources.

Deployment

Deploy from worker/ after the code and plugin metadata have been reviewed:

bash
npm run deploy

This single command deploys the site's API, email scheduler, and MCP service together as ccfddl-api. Cloudflare must be authorized in the deployment environment. Verify https://ccfddl.com/api/health, then connect https://ccfddl.com/mcp and call a tool; no separate MCP deployment is needed.

When OpenAI provides a domain-verification challenge for ccfddl.com, save its exact token as the ccfddl-api Worker secret OPENAI_DOMAIN_VERIFICATION_TOKEN and redeploy. The Worker returns that token at https://ccfddl.com/.well-known/openai-apps-challenge. Do not place the token in Git.

Public plugin submission

The portable plugin package is under worker/mcp/plugin/ccfddl/. After deployment, verify the public support, privacy, and terms pages, and review their wording with the publisher. From worker/mcp/, build the ZIP with:

bash
mkdir -p dist
cd plugin
zip -r ../dist/ccfddl-plugin.zip ccfddl

Upload the ZIP in the OpenAI Platform Plugins portal, connect the MCP URL, complete domain verification, and run the tool scan. The manifest contains acceptance-history and missing-statistics cases alongside deadline queries. Record a demonstration video and add its URL in the portal. Select the verified publisher identity and review the public listing before submitting; approval and publishing are separate actions.

The manifest's publisher identity, privacy terms, and policy URLs must be confirmed by the account owner before public submission. The plugin does not include payment or user authentication.


Overview (`extensions/chrome/chrome/README.md`)

CCF DDL Tracker (Chrome Extension)

使用方法 / Usage

  1. 打开 Chrome,进入 chrome://extensions/。/ Open Chrome and go to chrome://extensions/.
  2. 打开右上角的“开发者模式”。/ Enable “Developer mode”.
  3. 点击“加载已解压的扩展程序”,选择本仓库的 chrome/ 目录。/ Click “Load unpacked” and select chrome/.
  4. 安装完成后,点击浏览器工具栏的“CCF DDL Tracker”图标。/ Click the toolbar icon.

功能说明 / Features

  • 当前版本:扩展版本已更新为 v2.0,弹窗右上角会显示版本标记。/ The extension is now v2.0, and the popup header shows the current version.
  • 添加 DDL:填写标题、日期、时间,点击“添加”。/ Add title/date/time and click “Add”.
  • 查看详情:弹窗中会按时间排序展示多个 DDL,并显示剩余天数。/ Sorted list with remaining days.
  • 徽标提示:工具栏图标会显示最近一个 DDL 的剩余天数。/ Badge shows the nearest days left.
  • 删除 DDL:在条目右侧点击“删除”。/ Delete from the list.
  • 双入口卡片:新增截止日期和从 CCFDDL 导入改为一行两个入口卡片,点击后切换下方面板。/ Add DDL and Import from CCFDDL now appear as two side-by-side entry cards that switch the panel below.
  • 导入推荐会议:导入面板默认常驻显示,会优先显示已缓存会议,并在点击搜索框时获取最新推荐。/ The import panel stays visible by default, shows cached conferences first, and refreshes recommendations when the search field is focused.
  • 官网直达:从 CCFDDL 导入的会议会保留官网链接,加入“我的截止日期”后可直接点击卡片打开会议官网。/ Imported CCFDDL conferences retain their homepage links, and once added to "My DDLs" the card can be clicked to open the conference website.
  • 底部工具栏:中英切换和 CCFDDL 官网入口已移动到底部工具栏,右上角不再放操作项。/ Language switching and the CCFDDL website shortcut now live in the bottom toolbar instead of the top-right corner.
  • 协作入口:底部工具栏新增 GitHub 仓库链接,可直接打开项目主页参与开发。/ The bottom toolbar now includes a GitHub repository link so you can open the project page and contribute directly.
  • 显示设置:底部新增设置入口,可切换时间显示为 24 小时制或上午/下午 12 小时制。/ A new settings entry in the bottom bar lets you switch time display between 24-hour and 12-hour formats.
  • 日期顺序:设置面板新增日期顺序选项,可在“年月日”和“月日年”之间切换。/ The settings panel now includes a date-order option for switching between year/month/day and month/day/year.
  • 底部贴边:底部工具栏已固定贴到底边,去掉其下方的空白区域。/ The bottom utility bar is now anchored to the popup edge, removing the empty area beneath it.
  • 底部更轻量:底部工具栏进一步压缩为接近单行文字的样式,语言切换不再保留按钮感。/ The bottom utility bar is further compressed into a near single-line text-style row, and the language toggle no longer looks like a button.
  • 启动误触保护:弹窗刚打开时会短暂忽略导入入口的误触,避免工具栏点击把“从 CCFDDL 导入”意外点开。/ When the popup first opens, the import entry briefly ignores accidental clicks so the toolbar click does not unintentionally open "Import from CCFDDL".
  • 原生弹窗:点击工具栏图标会打开 Chrome 原生 popup,而不是独立窗口。/ Clicking the toolbar icon opens the native Chrome popup instead of a separate window.
  • 原生日期选择器:中英文界面都使用 Chrome 原生日期选择器,日期显示格式遵循浏览器或系统本地化设置。/ Both languages use Chrome's native date picker, and the displayed format follows browser or system localization.
  • 界面微调:压缩了顶栏高度,并优化了导入区的搜索与提示布局。/ The header is more compact, and the import panel now uses a cleaner search-and-hint layout.
  • DDL 标题行调整:数量显示在标题右侧,刷新按钮保持右对齐。/ The DDL header keeps the count beside the title while the Refresh button stays right-aligned.
  • 弹窗图标更新:弹窗顶部图标改为 chrome/icons/logo.png。/ The popup header icon now uses chrome/icons/logo.png.
  • 整体更紧凑:统一压缩了表单、卡片、列表项和按钮的纵向间距。/ The form, cards, list rows, and buttons now use tighter vertical spacing overall.
  • 操作更轻量:新增表单提交成功后会自动收起,导入面板默认常驻,而推荐会议只在点击搜索框时自动加载。/ The add form closes after a successful submission, the import panel stays visible by default, and recommendations only auto-load when the search field is focused.
  • 内部滚动优先:尽量避免外层弹窗滚动,“我的 DDL”和推荐会议列表各自在内部滚动。/ The popup avoids outer scrolling as much as possible, with "My DDLs" and recommendations scrolling inside their own areas.
  • 入口卡片稳定切换:导入面板默认展开,再次点击导入卡片会收起它,点击新增卡片会先关闭导入面板。/ The import panel starts expanded, clicking the import card again collapses it, and clicking the add card closes the import panel first.
  • 悬浮搜索选择器:点击搜索会议输入框时,会自动加载并弹出悬浮的推荐会议列表。/ Clicking the conference search input auto-loads and opens a floating recommendation picker.
  • 入口文案更紧凑:顶部两个入口卡片的标题和说明文字现在居中显示,并进一步压缩了行高。/ The two top entry cards now center their title and helper text with tighter line height.
  • 入口角标图标:顶部两个入口卡片的图标移动到左上角,不再额外占用行高。/ The two top entry card icons now sit in the top-left corner without adding extra line height.
  • 导入图标优化:从 CCFDDL 导入入口的角标改为更简洁的搜索图标。/ The CCFDDL import entry badge now uses a cleaner search icon.
  • 英文文案微调:英文入口卡片的标题和说明文字做了缩短,减少不自然换行。/ The English entry-card title and helper copy were shortened to reduce awkward wrapping.
  • 中文标题调整:中文界面的“我的 DDL”改为“我的截止日期”。/ The Chinese "My DDLs" title was renamed to "我的截止日期".
  • 导入提示文案:搜索框下方增加了一行小字,提示点击搜索框可获取最新会议列表。/ A small helper line below the import search field explains that clicking it loads the latest conference list.
  • 提示与刷新按钮微调:导入区提示文字改为居中显示,“我的截止日期”的刷新按钮改为图标按钮。/ The import helper text is now centered, and the "My DDLs" refresh control now uses an icon button.
  • 刷新图标与动效:刷新按钮改为更常见的无底框 SVG 图标,并增加旋转动效表示已触发刷新。/ The refresh control now uses a more standard frameless SVG icon and spins briefly to indicate that refresh was triggered.

数据存储 / Data

所有数据保存在 chrome.storage.local 中,仅在本机可见。/ Stored locally in chrome.storage.local.


--- METRICS ---