microCMSで職務経歴書をつくってみた
こちらは「microCMSでこんなことができた!あなたのユースケースを大募集 by microCMS Advent Calendar 2024」6日目の記事です。
初めての転職、初めての職務経歴書
今年初めて転職をしたのですが、恥ずかしながらこれまで職務経歴書という存在をよく知りませんでした…!調べてみると、職種によってフォーマットが多岐にわたっていて、何をどんな順番でどれくらい書けばいいのかわからず、試行錯誤しました。エンジニアはテクニカルスキルを記述するケースもあると思うので、特殊ですよね。
特にしっくりこなかったのが、どのアプリケーションを使って書くかでした。普段個人的なドキュメント作成にはNotionを使用していますが、ここで気づいたのはNotionにはテキストの右揃えスタイル設定がないこと!(職務経歴書では冒頭の日付や締めの「以上」は右揃えがお決まりらしい)
ではGoogleドキュメントか…?と思って作り始めたけれど何だか筆が進まない。とはいえアプリ選定にあまり時間を割くわけにもいかないので、そのままGoogleドキュメントで書き上げてしまいました。
提出した後まず思い立ったのが、「CMSでコンテンツ管理できる職務経歴書をつくろう!」ということでした。せっかくの個人開発なので、フレームワークは今まで使用したことがなかったRemixを採用。CMSは柔軟にAPI設計ができるmicroCMSにしました。
microCMSのAPIスキーマ設定
以下のようにmicroCMSのAPIスキーマを設定していきます。
使用するコンテンツAPIは一点のみ(オブジェクト形式)です。
コンテンツ
エンドポイント: contents
APIの型: オブジェクト形式
フィールド ID | 表示名 | 種類 |
---|---|---|
lastUpdate | 最終更新日 | 日時 |
name | 氏名 | テキストフィールド |
occupation | 職業 | テキストフィールド |
contacts | リンクURL | 繰り返しフィールド(contact) |
profileImage | プロフィール画像 | 画像 |
summary | 職務要約 | テキストエリア |
skills | 活かせる経験・知識・技術 | 繰り返しフィールド(skill) |
careers | 職務経歴 | 繰り返しフィールド(career) |
selfPresentations | 自己PR | 繰り返しフィールド(selfPresentation) |
backgroundColor | 背景色 | テキストフィールド |
textColor | 文字色 | テキストフィールド |
カスタムフィールド
カスタムフィールド名: 連絡先、SNSのURLなど
フィールドID: contact
フィールド ID | 表示名 | 種類 |
---|---|---|
name | 文字列 | テキストフィールド |
url | URL | テキストフィールド |
カスタムフィールド名: スキルセット
フィールドID: skill
フィールド ID | 表示名 | 種類 |
---|---|---|
name | スキル・資格 | テキストフィールド |
years | 経験年数 | 数字 |
level | 熟練度・説明 | テキストエリア |
カスタムフィールド名: 会社の概要
フィールドID: career
フィールド ID | 表示名 | 種類 |
---|---|---|
company | 会社名 | テキストフィールド |
period | 在席期間 | テキストフィールド |
business | 事業内容 | テキストフィールド |
stock | 資本金 | テキストフィールド |
employees | 従業員数 | 数字 |
projects | 担当したプロジェクト | 繰り返しフィールド(project) |
カスタムフィールド名: プロジェクトについて
フィールドID: project
フィールド ID | 表示名 | 種類 |
---|---|---|
name | プロジェクト名 | テキストフィールド |
period | 期間 | テキストフィールド |
content | プロジェクト概要や業務内容、実績、規模等 | リッチエディタ |
カスタムフィールド名: 自己PR
フィールドID: selfPresentation
フィールド ID | 表示名 | 種類 |
---|---|---|
headline | 見出し | テキストフィールド |
content | 内容 | テキストエリア |
参考にした記事
RemixとmicroCMSを連携させるために参考にしたのはこちら記事です。
実装
app/types/content.tsでコンテンツの型情報を定義します。
import type {
MicroCMSImage,
} from 'microcms-js-sdk';
export interface Content {
name: string;
occupation:string;
contacts: contact[];
backgroundColor:string;
textColor:string;
profileImage:MicroCMSImage;
summary:string;
lastUpdate:Date;
skills:skill[];
selfPresentations:selfPresentation[];
careers:career[];
}
// カスタムフィールド > contactの型定義
export type contact = {
id:string;
fieldId: 'contact';
name: string;
url: string;
};
// カスタムフィールド > skillの型定義
export type skill = {
id:string;
fieldId: 'skill';
name: string;
years: number;
level:string;
};
// カスタムフィールド > selfPresentationの型定義
export type selfPresentation = {
id:string;
fieldId: 'selfPresentation';
headline: string;
content:string;
};
// カスタムフィールド > careerの型定義
export type career = {
id:string;
fieldId: 'career';
company: string;
period:string;
business:string;
stock:string;
employees:number;
projects:project[];
};
// カスタムフィールド > projectの型定義
export type project = {
id:string;
fieldId: 'project';
name: string;
period:string;
content:string;
};
app/routes/_index.tsxでコンテンツを読み込んで、表示させています。
import type { MetaFunction, LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { client } from "~/libs/client.server";
import { formatDate } from "~/libs/util";
import type { Content } from "~/types/content";
export const meta: MetaFunction = ({data}) => {
return [
{ title: "職務経歴書" },
{ name: "description", content: data.name + "の職務経歴書です" },
];
};
export const loader: LoaderFunction = async () => {
const data = await client.get({ endpoint: "contents" });
return data;
};
export default function Index() {
const data = useLoaderData<Content>();
return (
<div className="min-h-screen p-10 font-MPLUS1p pt-16 pb-16">
<div className="w-full max-w-4xl m-auto">
<h1 className="text-center text-4xl mb-10 font-bold tracking-[.35em]">職務経歴書</h1>
<h3 className="text-right mb-10">{formatDate(data.lastUpdate)}</h3>
<div className="lg:flex mb-10">
{data.profileImage &&
<div className="lg:w-1/2 lg:mr-10 lg:mb-0 mb-6">
<img src={data.profileImage.url} alt="" />
</div>
}
<div className="lg:w-1/2 lg:flex lg:flex-col lg:justify-center">
<h1 className="text-4xl font-bold mb-4">
{data.name}
</h1>
<h2 className="text-2xl font-medium mb-4">
{data.occupation}
</h2>
<ul className="">
{data.contacts && data.contacts.map((contact,index) => (
<li key={index} className="mb-2 text-lg">
<a href={contact.url} target="_blank" rel="noreferrer">{contact.name}</a>
</li>
))}
</ul>
</div>
</div>
<div className="leading-loose mb-14">
<h3 className="text-2xl font-bold mb-4">職務要約</h3>
{data.summary}
</div>
<div className="leading-loose mb-14">
<h3 className="text-2xl font-bold mb-4">活かせる経験・知識・技術</h3>
{data.skills && data.skills.map((skill,index) => (
<div key={index} className="mb-6">
<h4 className="text-lg font-medium mb-1">{skill.name}
{skill.years &&
<span>(経験年数:{skill.years}年)</span>
}
</h4>
{skill.level}
</div>
))}
</div>
<div className="leading-loose mb-20">
<h3 className="text-2xl font-bold mb-4">職務経歴</h3>
{data.careers && data.careers.map((career,index) => (
<div key={index} className="mb-6">
<h4 className="text-xl font-medium mb-1">{career.company}
{career.period &&
<span>(在席期間:{career.period})</span>
}
</h4>
{career.business &&
<h5>事業内容:{career.business}</h5>
}
<div className="flex mb-5">
{career.stock &&
<h5 className="mr-5">資本金:{career.stock}</h5>
}
{career.employees &&
<h5>従業員数:{career.employees}名</h5>
}
</div>
{career.projects && career.projects.map((project,index) => (
<div key={index} className="mb-12 p-6" style={{ border: "1px solid #" + data.textColor }}>
<h4 className="text-xl font-medium mb-1">{project.name}</h4>
{project.period &&
<h5 className="mb-6">期間:{project.period}</h5>
}
<div className="project-detail" dangerouslySetInnerHTML={{ __html: project.content }} />
</div>
))}
</div>
))}
</div>
<div className="leading-loose mb-20">
<h3 className="text-2xl font-bold mb-4">自己PR</h3>
{data.selfPresentations && data.selfPresentations.map((selfPresentation,index) => (
<div key={index} className="mb-6">
<h4 className="text-lg font-medium mb-1">{selfPresentation.headline}</h4>
{selfPresentation.content}
</div>
))}
</div>
<p className="text-right mb-12">以上</p>
</div>
</div>
);
}
microCMS管理画面
職務要約、活かせる経験・知識・技術
各項目を設定可能、個数も制限ありません
職務経歴
所属していた会社の概要、担当したプロジェクトが繰り返しフィールド
完成したページ
pdfに書き出せば提出も可能。
GitHubリポジトリ
つくってみて
自分の思う通りに余白や行間、文字サイズ、文字間、フォントなどを設定でき、更新も簡単で結構いいのでは?と思っていたところにこちらのpostが流れてきました。履歴書まで…!?
しかも、サイズ調整機能があったり、PreviewURLを使用することで提出先ごとに内容を変更できるとのことで、こういう部分まで気が効いてこそだな〜!と思いました。素晴らしい👏
【後日談】 転職活動はどうなった?
8月よりマーケターとしてmicroCMSにジョインしました🙌
「microCMSでこんなことができた!あなたのユースケースを大募集 by microCMS Advent Calendar 2024」まだ参加可能ですので、ご興味ある方はぜひチェックしてみてください(プレゼント企画も行っております🎁)!
Discussion