Skip to content

Folder Structure

The website repo (ediky-website) at a glance. The app itself lives one level down in ediky/ — CI's working-directory is set accordingly, which matters when editing workflows.

ediky-website/
├── .github/workflows/
│   ├── deploy.yml            # workflow_dispatch → reusable CF Pages deploy (ci-infra)
│   └── ci.yml                # lint + build on push/PR
├── worker/                   # background OA judging Worker (own wrangler.toml)
│   └── src/index.js
├── worker-reminders/         # per-minute reminder cron Worker
│   └── src/index.js
├── firestore-rules/
│   ├── firestore.rules
│   └── storage.rules
└── ediky/                    # ← the app root
    ├── public/
    │   ├── content/          # generated question bodies + .tests.json sidecars
    │   ├── content-index/    # generated per-section index shards + manifest.json
    │   ├── favicon.svg  logo.png  …   # brand assets (shared with this docs site)
    │   └── _headers          # cache-control fix for stale SPA deploys
    ├── functions/            # Cloudflare Pages Functions (the API)
    │   ├── _ai-providers.js  # shared 9-provider fallback chain
    │   ├── ai-code-review.js # help / chat / ask / optimize modes
    │   ├── grade-concept.js  evaluate-aptitude.js  grade-sql-practice.js
    │   ├── run-code.js       # Judge0 proxy
    │   ├── get-notes.js  list-notes.js   # private-Docy proxy (GITHUB_TOKEN)
    │   └── cf-profile.js  cf-status.js   # Codeforces proxy
    ├── src/
    │   ├── App.jsx  main.jsx
    │   ├── components/
    │   │   ├── layout/       # MainLayout, Navbar, Sidebar, UserMenu
    │   │   ├── bank/ coding/ oa/ ide/ calendar/ learning/ revision/ dashboard/
    │   │   └── ui/           # primitives (buttons, dialogs, popovers)
    │   ├── pages/            # route components (+ bank/ cp/ oa/ subjects/ subdirs)
    │   ├── context/          # Auth / Theme / Sidebar / Submissions
    │   ├── hooks/            # 20 use* hooks
    │   ├── lib/              # all non-UI logic (questionBank, judgeRunner, oaEngine, …)
    │   ├── content/          # SOURCE question markdown (input to build-content)
    │   ├── data/             # static data (cpTests.js, companies, playlists)
    │   └── styles/theme.css  # the CSS-variable token system (light + dark)
    ├── tools/
    │   ├── build-content.mjs # the sharder — see Question Bank
    │   ├── lint-content.mjs  # wired into npm run build; bans bits/stdc++.h etc.
    │   ├── convert-sheet.mjs gen-cp-content.mjs
    │   └── copy-sql-wasm.mjs # ships sql.js WASM into public/
    ├── scripts/send-reminders.mjs  backfill-emails.mjs
    ├── .env.example          # VITE_FIREBASE_*, VITE_CLOUDINARY_*, VITE_DOCS_URL
    ├── vite.config.js  eslint.config.js  package.json
    └── index.html

Conventions that keep it navigable

  • src/content/ is input, public/content* is output. Never hand-edit anything under public/content — it's regenerated on every build. Authoring happens in the tools repo; the built shards are what ships.
  • Generated vs committed: public/content-index/ and public/content/ are build artifacts of build-content.mjs. The source of truth is src/content/ markdown.
  • lib/ has no JSX; components/ has no fetch calls. The seam between them is the hooks directory. This is what made the annotation-system rewrite and the judging rebuild possible without touching page markup.
  • One parser (contentParse.js), one AI client (aiService.js), one judging path (judgeRunner.js behind run-code). Duplicates of these have each caused a real bug historically; the singletons are load-bearing.
  • Workers are separate deployables. worker/ and worker-reminders/ have their own wrangler.toml and deploy lifecycle — a website deploy never touches them and vice versa.
  • Functions prefixed _ (like _ai-providers.js) are shared modules, not routes — Cloudflare skips underscore files when generating endpoints.

Ediky Workflow — internal engineering documentation.