


WikiにはiGEMで行った活動を詳細に記す必要がある。しかし、1、2年間でプロジェクトを行わなければならないiGEMではWiki執筆を早い時期から始めることは困難である。また、執筆にはコーディングの過程が必要になるため、初学者にとっての難易度が高いといった課題もある。加えて、評価を受けるためにはiGEMの示す基準(e.g., 画像の形式やGitLabへのアップロードなど)を満たす必要があるが、要件の見落としなどのヒューマンエラーが起こることもある。そこで我々はこれらの執筆・提出における障害を取り除くために2つのシステムを構築した。EditorによってWiki執筆の難易度を下げ、Submission Systemによって要件を見落とすリスクを低減する。これらのシステムによってiGEM Memberはより簡単により確実にWikiを提出することが可能になり、クオリティを高めるための時間を確保することが可能となる。
iGEMのWiki提出には複数の複雑な要件があり、技術的・時間的な課題を伴います。基本的なHTMLファイルはGitLabのアーティファクトとして、それ以外のファイルは専用のCDNにアップロードする必要があるため、AstroやReactのようなモダンなビルドツールを使用する場合、提出プロセスはさらに困難になる。これは、iGEMが指定する形式に合わせてファイルを加工する作業が必要になるためである。
我々のチームは、高いパフォーマンスと安全性を確保するため、強力な静的サイトビルダーであるAstroを用いてWikiを構築した。Astroは画像やCSS、JavaScriptを最適化し、軽量かつ安全なサイトを生成する。これにより、レンダリングの問題を避け、あらゆる環境のユーザーにWikiを確実に表示できるという利点がある。WikiはiGEM大会の評価において非常に重要であるため、フロントエンドでのレンダリングトラブルを避けるために、基本的なコンテンツをHTMLに直接埋め込む手法を採用した。
しかし、このアプローチにはいくつかの問題があった。
手動アップロードの負担: Astroが生成したファイルを、GitLabやCDNに手動でアップロードする作業は非常に手間がかかります。チームの役割が細分化されており、Wikiは頻繁に更新されるため、この手作業は現実的ではなかった。
iGEM CDNの仕様: iGEMのCDNには、以下のような厄介な仕様が存在した。
画像が自動的にWebP形式に変換される。
SVGファイルのアップロードがうまくいかないことがある(XMLヘッダーを削除することで解決)。
ファイル名が強制的に小文字に変換される。
フォルダーのアップロードや削除ができない。
また、GitLabのアーティファクトから発行されるURLがhttps://2025.igem.wiki/{チーム名}という形式で、ルーティングが非常にしにくいという問題もあった。
これらの課題を解決するため、私たちはWikiを自動でビルドし、生成されたファイルを解析、CDNに最適な形に加工して自動アップロードする独自のツールを開発した。
このシステムは、エディター上のボタンをクリックすることで一連のプロセスが自動的に開始される。
function sanitizeMDX(text, slug) {
if (!text) return "";
// iframe/details/summary を先に保護
const safeTags = [];
text = text.replace(
/<(iframe|details|summary)([\s\S]*?)(?:<\/\1>|\/>)/gi,
(match) => {
// ✅ iframe内の src="" を src="https://..." に修正
if (/^]+)>["']/i,
(m, url) => ` src="${url}"`
);
}
safeTags.push(match);
return `__SAFE_TAG_${safeTags.length - 1}__`;
}
);
// HTMLエンティティをデコード
text = he.decode(text);
// "**Word:** Text" → "**Word:** Text" に補正
text = text.replace(/\*\*([^\*]+?):\s\*\*(\S)/g, "**$1:** $2");
// KaTeX 数式部分を分離して通常テキストのみエスケープ
const parts = text.split(/(\$\$[\s\S]+?\$\$|\$[^\$]+\$)/g);
const sanitized = parts
.map((part) => {
if (part.startsWith("$")) return part;
if (/__SAFE_TAG_\d+__/.test(part)) return part;
return part
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/{/g, "{")
.replace(/}/g, "}")
.replace(/~/g, "~"); // ← Escape tilde
})
.join("");
// 保護タグを復元
const restored = sanitized.replace(
/__SAFE_TAG_(\d+)__/g,
(_, idx) => safeTags[idx]
);
// 制御文字チェック
const dangerousPattern = /[\x00-\x08\x0B\x0C\x0E-\x1F]/;
if (dangerousPattern.test(restored)) {
console.warn(`⚠️ Dangerous characters detected in post slug="${slug}"`);
}
return restored;
}</code></pre>
Astroによるビルド: 次に、Astroでサイトをビルドします。この際、CDNでの読み込みトラブルを防ぐため、すべてのファイル名を小文字に変換して書き出す。
リンクのチェック: 不要な外部リンクがないかを確認する。iGEMのWikiは許可されたリンクのみを掲載する必要があるため、不許可なリンクが検出された場合はDiscordに警告が通知される。
ファイルの変換と解析: ビルドされたファイルを解析し、以下の処理を実行する。
HTMLからリンクされているファイルを解析し、CDNアップロード用フォルダーに格納。
ファイル名を数字に変更。
HTML内のファイル名を新しい名前に書き換え。
SVGファイルからXMLヘッダーを削除。
PNGやJPEGなどの画像ファイル名を.webpに変更(実際のファイル形式は変換せず、CDNの自動変換に任せるため)。
CDNへのアップロード: 変換したファイルをCDNにアップロードする。これにはアカウントセッションを取得し、フォルダーを作成してからファイルを順次アップロードする技術的な工夫が必要である。個々のAPI情報は、ブラウザの開発者ツールなどから取得した。
const baseHeaders = { Origin: "https://accounts.igem.org", Referer: "https://accounts.igem.org/", "User-Agent": "Mozilla/5.0", Accept: "/", };
これらの自動化されたサイクルはすべてGitHub Actions上で実行され、開発者や執筆者はAPIやUIを通じてこれらの機能を簡単に実行できる。この堅牢なシステムにより、私たちはWikiの提出プロセスを大幅に効率化し、安定した運用を実現した。
iGEM TSUKUBA Editor は、**「執筆から公開の一連の体験」**を提供するために設計したチーム向けのリッチテキストエディタである。Markdownの記法やツールの使い分けに不慣れなメンバーでも、画面で見たままで編集し、そのままプレビューから公開まで滑らかにつながる導線を用意した。リアルタイムな共同編集により、コメントの往復や差分のマージに伴う手間を減らし、「文章を整える前に仕組みでつまずく」という典型的なボトルネックを取り除く。
また、日本チームの課題にもあがる英語への対応を前提に、テキストだけを正確に抽出してAIによって翻訳するフローを組み込んだ。これにより、見出しや表などのレイアウトを壊さずに内容だけを確実に翻訳できうr。結果として、翻訳の作業の属人性を下げることで品質を担保することが可能になる。
さらに、また記事を1つのプラットフォームに集約することで**「誰が・いつ・どこを」**編集したかの追跡性と、公開前のチェックの確実性を確保しました。これにより、執筆から公開までの流れの分断をなくし、一気通貫で作業できることを狙っています。


以下のような技術スタックを採用している。
フロントエンド
Next.js
TypeScript
NextAuth
shadcn
BlockNote
バックエンド
Prisma
Neon
Cloudinary
PartyKit
OpenAI API
デプロイ
Vercel
GitHub Actions
フロントエンドは、Next.jsとTypeScriptを用いて作成した。認証には、NextAuthを採用し、メール認証およびGoogleログインを実装した。UIライブラリには、shadcnを採用し、モダンなデザインを意識している。リッチテキストエディタには、BlockNoteを採用し、WYSIWYG (What You See Is What You Get)を実現した。
バックエンドは、NeonとPrismaを用いて作成した。ストレージにはCloudinaryを採用し、低コストを実現した。リアルタイムな共同編集には、PartyKitを用いてWebSocketで通信することで実現した。また、OpenAI APIを用いて、執筆した内容を自動で翻訳を行う。
デプロイにはVercelを採用した。
以下のような機能を実装している。
記事エディタ
この機能は、執筆者にとって快適なリッチテキストエディタを提供する。
以下のような実装がある。
テキスト: 段落、見出し
リスト: 箇条書き、番号付きリスト、チェックリスト
ブロック: 引用、コード、表
装飾: 色、太字、斜体、下線、取り消し線、ハイライト、リンク、インデント
メディア: 画像、映像、オーディオ、ファイル
その他: 数式、絵文字
また、リアルタイムな共同編集に対応しており、複数の執筆者が同時に作業することができる。
以下は実際の記事エディタの画面である。


記事一覧
この機能は、複数の執筆者が執筆した記事が一目でわかるテーブルを提供する。
以下のような実装がある。
記事の情報: 記事の名前、内容、作成日、更新日、編集者
記事の検索: 記事の名前による検索
記事の操作: 記事の追加や削除
また、それぞれの記事は、Wikiの各エンドポイントに対応している。
以下は実際の記事一覧の画面です。


記事翻訳
この機能は、執筆した記事をAIによる翻訳とその校正を行うエディターを提供する。
以下のような実装がある。
AIによる翻訳: OpenAI APIを用いた英語への翻訳
マークダウンの表示: 執筆した記事のマークダウンの表示
プレビューの表示: 執筆した記事のプレビューの表示
ここで、OpenAI APIを用いた翻訳の仕組みについて説明する。
そのままMarkdownをOpenAI APIにプロンプトとして投げると、レイアウトが崩れてしまう。
これには、Markdownが記号(#や*)を用いてテキストをマークアップするためである。
そのため、テキストのみを翻訳する必要がある。
以下は実際の翻訳の流れです。
Markdownの分解: Markdownを木構造であるAST (Abstract Syntax Tree)に変換
テキストの抽出: 変換したASTからテキストのみを順番を保持して抽出
テキストの翻訳: 抽出したテキストを順番にOpenAI APIを用いて翻訳
テキストの注入: 同じASTを辿ることで翻訳したテキストを注入
Markdownの組立: ASTをMarkdownに変換
以下は実際の記事翻訳の画面です。


ユーザー設定
この機能は、プロフィールや通知といった快適な利用のための設定を提供する。
以下のような実装がある。
プロフィール: アイコン、ユーザー名、テーマカラー
プッシュ通知: 記事の作成時、記事の更新時、記事の削除時
セキュリティ: ユーザーのロールの変更
以下は実際のプロフィール設定の画面である。


以下は実際のプッシュ通知の画面です。


エンジニアの少ない私たちのチームでは、Wiki の提出そのものが長らく心理的かつ運用的なハードルであった。記事のレビュー、記事のスタイル、記事の管理など、慣れていないメンバーにとってはどれもハードルが高く、**「内容を書く前に仕組みでつまずく」**ことが珍しくなかった。公開する直前にミスが見つかるたびに修正して提出する手戻りが発生し、時間がかかっていた。
iGEM TSUKUBA Editorを導入してからは、執筆・翻訳・プレビュー・公開までの導線が一つにつながり、エンジニアでないメンバーでも迷わず作業を進められるようになった。画面上でそのまま編集して即座にプレビューできるため、レイアウトに悩まされる時間が大幅に減りました。結果として、私たちは内容の質そのものに集中でき、レビューの回数や公開する前の手戻りも減少した。
このエディタは、Wikiを**「構築する」作業から「伝える」**活動へと重心を移す機能を果たした。締切前の混乱が抑えられ、各メンバーが自分の専門性を生かして執筆・校正・翻訳に参加しやすくなったことは、今回の大会の準備を通じて実際に体感した効果である。私たち iGEM TSUKUBA は本番運用でこのツールの有用性を確認できた。もし同じような課題を抱えているなら、本ドキュメントを足がかりに導入を検討してみることを推奨する。準備のストレスを減らし、コンテンツの質により多くの時間を割けるようになることが見込まれる。





© 2025 - Content on this site is licensed under a Creative Commons Attribution 4.0 International license
The repository used to create this website is available at gitlab.igem.org/2025/tsukuba.