Compare commits

...

24 Commits

Author SHA1 Message Date
Arik Chakma
0560cc930a fix: topic path 2025-08-20 20:00:03 +06:00
Arik Chakma
c903b76934 fix: remove title 2025-08-20 19:34:41 +06:00
Arik Chakma
4f586fd122 fix: sync content description 2025-08-20 19:31:17 +06:00
Kamran Ahmed
cb7c13fd1b Make sync to not run for github actions 2025-08-20 14:24:21 +01:00
github-actions[bot]
704657cb36 Add content to Machine Learning (#9054)
* chore: sync content to repo

* Update src/data/roadmaps/machine-learning/introduction@MEL6y3vwiqwAV6FQihF34.md

* Update src/data/roadmaps/machine-learning/what-is-an-ml-engineer@FgzPlLUfGdlZPvPku0-Xl.md

---------

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2025-08-20 14:21:03 +01:00
Kamran Ahmed
eba3a78c70 Update .github/workflows/sync-content-to-repo.yml 2025-08-20 13:49:19 +01:00
Kamran Ahmed
d6cf9eb66d Update .github/workflows/sync-content-to-repo.yml 2025-08-20 13:49:19 +01:00
Arik Chakma
885e95399e fix: sync repo to db 2025-08-20 13:49:19 +01:00
Arik Chakma
d70582411e chore: sync repo to database 2025-08-20 13:49:19 +01:00
Arik Chakma
07277708eb fix: replace the api endpoint 2025-08-20 13:49:19 +01:00
Arik Chakma
87280b4c9e chore: sync content to repo 2025-08-20 13:49:19 +01:00
Kamran Ahmed
91b0a232ab Fix typos 2025-08-20 13:02:32 +01:00
Kamran Ahmed
bbedfec17d Fix AI course generator issue 2025-08-19 18:38:50 +01:00
Kamran Ahmed
96b2eb2797 Add machine learning roadmap to readme 2025-08-19 17:39:31 +01:00
Kamran Ahmed
fc1f666daf Add machine learning roadmap links 2025-08-19 17:36:03 +01:00
Kamran Ahmed
8fb38ae944 Add machine learning roadmap 2025-08-19 17:33:28 +01:00
Kamran Ahmed
bfe340508c Add machine learning roadmap 2025-08-19 17:30:32 +01:00
Arik Chakma
fc260ec3f0 chore: add data engineer 2025-08-19 17:14:45 +01:00
Arik Chakma
cd18dbad95 chore: add data engineer roadmap 2025-08-19 17:14:45 +01:00
Arik Chakma
949ada2fda fix: ai roadmap url 2025-08-19 17:14:45 +01:00
Omprakash Rawat
2823038d79 add Distributed Systems topic with resources (#9050) 2025-08-19 15:31:35 +01:00
Arik Chakma
dbb25ca129 fix: guides pages (#9048) 2025-08-19 15:29:28 +01:00
Arik Chakma
467581bbf4 chore: remove old ai pages (#9049) 2025-08-19 15:28:59 +01:00
Kamran Ahmed
bd7cf6e4d7 Add kubernetes ci/cd tools 2025-08-19 15:25:14 +01:00
202 changed files with 7221 additions and 738 deletions

View File

@@ -0,0 +1,67 @@
name: Sync Content to Repo
on:
workflow_dispatch:
inputs:
roadmap_slug:
description: "The ID of the roadmap to sync"
required: true
default: "__default__"
jobs:
sync-content:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm@v9
uses: pnpm/action-setup@v4
with:
version: 9
run_install: false
- name: Setup Node.js Version 20 (LTS)
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install Dependencies and Sync Content
run: |
echo "Installing Dependencies"
pnpm install
echo "Syncing Content to Repo"
npm run sync:content-to-repo -- --roadmap-slug=${{ inputs.roadmap_slug }} --secret=${{ secrets.GH_SYNC_SECRET }}
- name: Check for changes
id: verify-changed-files
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
else
echo "changed=false" >> $GITHUB_OUTPUT
fi
- name: Create PR
if: steps.verify-changed-files.outputs.changed == 'true'
uses: peter-evans/create-pull-request@v7
with:
delete-branch: false
branch: "chore/sync-content-to-repo-${{ inputs.roadmap_slug }}"
base: "master"
labels: |
dependencies
automated pr
reviewers: arikchakma
commit-message: "chore: sync content to repo"
title: "chore: sync content to repository"
body: |
## Sync Content to Repo
> [!IMPORTANT]
> This PR Syncs the Content to the Repo for the Roadmap: ${{ inputs.roadmap_slug }}
>
> Commit: ${{ github.sha }}
> Workflow Path: ${{ github.workflow_ref }}
**Please Review the Changes and Merge the PR if everything is fine.**

View File

@@ -0,0 +1,67 @@
name: Sync on Roadmap Changes
on:
push:
branches:
- master
paths:
- 'src/data/roadmaps/**'
jobs:
sync-on-changes:
runs-on: ubuntu-latest
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2 # Fetch previous commit to compare changes
- name: Setup pnpm@v9
uses: pnpm/action-setup@v4
with:
version: 9
run_install: false
- name: Setup Node.js Version 20 (LTS)
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Get changed files
id: changed-files
run: |
echo "Getting changed files in /src/data/roadmaps/"
# Get changed files between HEAD and previous commit
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD -- src/data/roadmaps/)
if [ -z "$CHANGED_FILES" ]; then
echo "No changes found in roadmaps directory"
echo "has_changes=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "Changed files:"
echo "$CHANGED_FILES"
# Convert to space-separated list for the script
CHANGED_FILES_LIST=$(echo "$CHANGED_FILES" | tr '\n' ' ')
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "changed_files=$CHANGED_FILES_LIST" >> $GITHUB_OUTPUT
- name: Install Dependencies
if: steps.changed-files.outputs.has_changes == 'true'
run: |
echo "Installing Dependencies"
pnpm install
- name: Run sync script with changed files
if: steps.changed-files.outputs.has_changes == 'true'
run: |
echo "Running sync script for changed roadmap files"
echo "Changed files: ${{ steps.changed-files.outputs.changed_files }}"
# Run your script with the changed file paths
npm run sync:repo-to-database -- --files="${{ steps.changed-files.outputs.changed_files }}" --secret=${{ secrets.GH_SYNC_SECRET }}

View File

@@ -29,6 +29,8 @@
"compress:images": "tsx ./scripts/compress-images.ts",
"generate:roadmap-content-json": "tsx ./scripts/editor-roadmap-content-json.ts",
"migrate:editor-roadmaps": "tsx ./scripts/migrate-editor-roadmap.ts",
"sync:content-to-repo": "tsx ./scripts/sync-content-to-repo.ts",
"sync:repo-to-database": "tsx ./scripts/sync-repo-to-database.ts",
"test:e2e": "playwright test"
},
"dependencies": {

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

View File

@@ -48,6 +48,7 @@ Here is the list of available roadmaps with more being actively worked upon.
- [Terraform Roadmap](https://roadmap.sh/terraform)
- [Data Analyst Roadmap](https://roadmap.sh/data-analyst)
- [Data Engineer Roadmap](https://roadmap.sh/data-engineer)
- [Machine Learning Roadmap](https://roadmap.sh/machine-learning)
- [MLOps Roadmap](https://roadmap.sh/mlops)
- [Product Manager Roadmap](https://roadmap.sh/product-manager)
- [Engineering Manager Roadmap](https://roadmap.sh/engineering-manager)

View File

@@ -0,0 +1,142 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { slugify } from '../src/lib/slugger';
import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const args = process.argv.slice(2);
const roadmapSlug = args?.[0]?.replace('--roadmap-slug=', '');
const secret = args?.[1]?.replace('--secret=', '');
if (!secret) {
throw new Error('Secret is required');
}
if (!roadmapSlug || roadmapSlug === '__default__') {
throw new Error('Roadmap slug is required');
}
console.log(`🚀 Starting ${roadmapSlug}`);
export const allowedOfficialRoadmapTopicResourceType = [
'roadmap',
'official',
'opensource',
'article',
'course',
'podcast',
'video',
'book',
'feed',
] as const;
export type AllowedOfficialRoadmapTopicResourceType =
(typeof allowedOfficialRoadmapTopicResourceType)[number];
export type OfficialRoadmapTopicResource = {
_id?: string;
type: AllowedOfficialRoadmapTopicResourceType;
title: string;
url: string;
};
export interface OfficialRoadmapTopicContentDocument {
_id?: string;
roadmapSlug: string;
nodeId: string;
description: string;
resources: OfficialRoadmapTopicResource[];
createdAt: Date;
updatedAt: Date;
}
export async function roadmapTopics(
roadmapId: string,
secret: string,
): Promise<OfficialRoadmapTopicContentDocument[]> {
const path = `https://roadmap.sh/api/v1-list-official-roadmap-topics/${roadmapId}?secret=${secret}`;
const response = await fetch(path);
if (!response.ok) {
throw new Error(`Failed to fetch roadmap topics: ${response.statusText}`);
}
const data = await response.json();
if (data.error) {
throw new Error(`Failed to fetch roadmap topics: ${data.error}`);
}
return data;
}
export async function fetchRoadmapJson(
roadmapId: string,
): Promise<OfficialRoadmapDocument> {
const response = await fetch(
`https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`,
);
if (!response.ok) {
throw new Error(`Failed to fetch roadmap json: ${response.statusText}`);
}
const data = await response.json();
if (data.error) {
throw new Error(`Failed to fetch roadmap json: ${data.error}`);
}
return data;
}
// Directory containing the roadmaps
const ROADMAP_CONTENT_DIR = path.join(
__dirname,
'../src/data/roadmaps',
roadmapSlug,
);
const allTopics = await roadmapTopics(roadmapSlug, secret);
const roadmap = await fetchRoadmapJson(roadmapSlug);
const { nodes } = roadmap;
for (const topic of allTopics) {
const { nodeId } = topic;
const node = nodes.find((node) => node.id === nodeId);
if (!node) {
console.error(`Node not found: ${nodeId}`);
continue;
}
const label = node?.data?.label as string;
if (!label) {
console.error(`Label not found: ${nodeId}`);
continue;
}
const topicSlug = `${slugify(label)}@${nodeId}.md`;
const topicPath = path.join(ROADMAP_CONTENT_DIR, 'content', topicSlug);
const topicDir = path.dirname(topicPath);
const topicDirExists = await fs
.stat(topicDir)
.then(() => true)
.catch(() => false);
if (!topicDirExists) {
await fs.mkdir(topicDir, { recursive: true });
}
const topicContent = prepareTopicContent(topic);
await fs.writeFile(topicPath, topicContent);
console.log(`✅ Synced ${topicSlug}`);
}
function prepareTopicContent(topic: OfficialRoadmapTopicContentDocument) {
const { description, resources = [] } = topic;
let content = description;
if (resources.length > 0) {
content += `\n\nVisit the following resources to learn more:\n\n${resources.map((resource) => `- [@${resource.type}@${resource.title}](${resource.url})`).join('\n')}`;
}
return content;
}

View File

@@ -0,0 +1,215 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap';
import { parse } from 'node-html-parser';
import { markdownToHtml } from '../src/lib/markdown';
import { htmlToMarkdown } from '../src/lib/html';
import {
allowedOfficialRoadmapTopicResourceType,
type AllowedOfficialRoadmapTopicResourceType,
type OfficialRoadmapTopicContentDocument,
type OfficialRoadmapTopicResource,
} from './sync-content-to-repo';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const args = process.argv.slice(2);
const allFiles = args?.[0]?.replace('--files=', '');
const secret = args?.[1]?.replace('--secret=', '');
if (!secret) {
throw new Error('Secret is required');
}
let roadmapJsonCache: Map<string, OfficialRoadmapDocument> = new Map();
export async function fetchRoadmapJson(
roadmapId: string,
): Promise<OfficialRoadmapDocument> {
if (roadmapJsonCache.has(roadmapId)) {
return roadmapJsonCache.get(roadmapId)!;
}
const response = await fetch(
`https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`,
);
if (!response.ok) {
throw new Error(`Failed to fetch roadmap json: ${response.statusText}`);
}
const data = await response.json();
if (data.error) {
throw new Error(`Failed to fetch roadmap json: ${data.error}`);
}
roadmapJsonCache.set(roadmapId, data);
return data;
}
export async function syncContentToDatabase(
topics: Omit<
OfficialRoadmapTopicContentDocument,
'createdAt' | 'updatedAt' | '_id'
>[],
) {
const response = await fetch(
`https://roadmap.sh/api/v1-sync-official-roadmap-topics`,
{
method: 'POST',
body: JSON.stringify({
topics,
secret,
}),
},
);
if (!response.ok) {
throw new Error(
`Failed to sync content to database: ${response.statusText}`,
);
}
return response.json();
}
const files = allFiles.split(' ');
console.log(`🚀 Starting ${files.length} files`);
const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps');
try {
const topics: Omit<
OfficialRoadmapTopicContentDocument,
'createdAt' | 'updatedAt' | '_id'
>[] = [];
for (const file of files) {
const isContentFile = file.endsWith('.md') && file.includes('content/');
if (!isContentFile) {
console.log(`🚨 Skipping ${file} because it is not a content file`);
continue;
}
const pathParts = file.replace('src/data/roadmaps/', '').split('/');
const roadmapSlug = pathParts?.[0];
if (!roadmapSlug) {
console.error(`🚨 Roadmap slug is required: ${file}`);
continue;
}
const nodeSlug = pathParts?.[2]?.replace('.md', '');
if (!nodeSlug) {
console.error(`🚨 Node id is required: ${file}`);
continue;
}
const nodeId = nodeSlug.split('@')?.[1];
if (!nodeId) {
console.error(`🚨 Node id is required: ${file}`);
continue;
}
const roadmap = await fetchRoadmapJson(roadmapSlug);
const node = roadmap.nodes.find((node) => node.id === nodeId);
if (!node) {
console.error(`🚨 Node not found: ${file}`);
continue;
}
const filePath = path.join(
ROADMAP_CONTENT_DIR,
roadmapSlug,
'content',
`${nodeSlug}.md`,
);
const content = await fs.readFile(filePath, 'utf8');
const html = markdownToHtml(content, false);
const rootHtml = parse(html);
let ulWithLinks: HTMLElement | undefined;
rootHtml.querySelectorAll('ul').forEach((ul) => {
const listWithJustLinks = Array.from(ul.querySelectorAll('li')).filter(
(li) => {
const link = li.querySelector('a');
return link && link.textContent?.trim() === li.textContent?.trim();
},
);
if (listWithJustLinks.length > 0) {
// @ts-expect-error - TODO: fix this
ulWithLinks = ul;
}
});
const listLinks: Omit<OfficialRoadmapTopicResource, '_id'>[] =
ulWithLinks !== undefined
? Array.from(ulWithLinks.querySelectorAll('li > a'))
.map((link) => {
const typePattern = /@([a-z.]+)@/;
let linkText = link.textContent || '';
const linkHref = link.getAttribute('href') || '';
let linkType = linkText.match(typePattern)?.[1] || 'article';
linkType = allowedOfficialRoadmapTopicResourceType.includes(
linkType as any,
)
? linkType
: 'article';
linkText = linkText.replace(typePattern, '');
return {
title: linkText,
url: linkHref,
type: linkType as AllowedOfficialRoadmapTopicResourceType,
};
})
.sort((a, b) => {
const order = [
'official',
'opensource',
'article',
'video',
'feed',
];
return order.indexOf(a.type) - order.indexOf(b.type);
})
: [];
const title = rootHtml.querySelector('h1');
ulWithLinks?.remove();
title?.remove();
const allParagraphs = rootHtml.querySelectorAll('p');
if (listLinks.length > 0 && allParagraphs.length > 0) {
// to remove the view more see more from the description
const lastParagraph = allParagraphs[allParagraphs.length - 1];
lastParagraph?.remove();
}
const htmlStringWithoutLinks = rootHtml.toString();
const description = htmlToMarkdown(htmlStringWithoutLinks);
const updatedDescription =
`# ${title?.textContent}\n\n${description}`.trim();
const label = node?.data?.label as string;
if (!label) {
console.error(`🚨 Label is required: ${file}`);
continue;
}
topics.push({
roadmapSlug,
nodeId,
description: updatedDescription,
resources: listLinks,
});
}
await syncContentToDatabase(topics);
} catch (error) {
console.error(error);
process.exit(1);
}

View File

@@ -470,10 +470,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<div className="grid grid-cols-1 gap-5 bg-gray-50 px-4 py-5 sm:gap-16 sm:px-0 sm:py-16">
<FeaturedGuideList
heading="Guides"
guides={guides.slice(0, 7)}
guides={guides.slice(0, 15)}
questions={guides
.filter((guide) => guide.roadmapId === 'questions')
.slice(0, 7)}
.slice(0, 15)}
/>
<FeaturedVideoList heading="Videos" videos={videos} />
</div>

View File

@@ -25,7 +25,7 @@ export function ForkCourseAlert(props: ForkCourseAlertProps) {
)}
>
<p className="text-sm text-balance">
Fork the course to track progress and make changes to the course.
Fork the course to track you progress and make changes to the course.
</p>
<button

View File

@@ -1,182 +0,0 @@
---
import { getGuideTableOfContent, type HeadingGroupType } from '../../lib/guide';
import { markdownToHtml } from '../../lib/markdown';
import {
type QuestionGroupType,
type QuestionType,
} from '../../lib/question-group';
import { slugify } from '../../lib/slugger';
import { RelatedGuides } from '../Guide/RelatedGuides';
import MarkdownFile from '../MarkdownFile.astro';
import { TableOfContent } from '../TableOfContent/TableOfContent';
import { QuestionsList } from './QuestionsList';
interface Props {
questionGroup: QuestionGroupType;
}
const { questionGroup } = Astro.props;
const { frontmatter: guideFrontmatter, author } = questionGroup;
// Group questions by topics
const questionsGroupedByTopics = questionGroup.questions.reduce(
(acc, question) => {
question.topics?.forEach((topic) => {
acc[topic] = [...(acc[topic] || []), question];
});
return acc;
},
{} as Record<string, QuestionType[]>,
);
// Get all unique topics in the order they appear in the questions array
const topicsInOrder: string[] = [];
questionGroup.questions.forEach((question) => {
question.topics?.forEach((topic) => {
if (!topicsInOrder.includes(topic)) {
topicsInOrder.push(topic);
}
});
});
const allHeadings = questionGroup.getHeadings();
let tableOfContent: HeadingGroupType[] = [
...getGuideTableOfContent(allHeadings),
{
depth: 2,
children: [],
slug: 'test-with-flashcards',
text: 'Test yourself with Flashcards',
},
{
depth: 2,
children: topicsInOrder.map((topic) => {
let topicText = topic;
let topicSlug = slugify(topic);
if (topic.toLowerCase() === 'beginners') {
topicText = 'Beginner Level';
topicSlug = 'beginner-level';
} else if (topic.toLowerCase() === 'intermediate') {
topicText = 'Intermediate Level';
topicSlug = 'intermediate-level';
} else if (topic.toLowerCase() === 'advanced') {
topicText = 'Advanced Level';
topicSlug = 'advanced-level';
}
return {
depth: 2,
children: [],
slug: topicSlug,
text: topicText,
};
}),
slug: 'questions-list',
text: 'Questions List',
},
];
const showTableOfContent = tableOfContent.length > 0;
---
<article class='lg:grid lg:max-w-full lg:grid-cols-[1fr_minmax(0,700px)_1fr]'>
<!-- {
showTableOfContent && (
<div class='bg-linear-to-r from-gray-50 py-0 lg:col-start-3 lg:col-end-4 lg:row-start-1'>
<RelatedGuides
relatedTitle={guideFrontmatter?.relatedTitle}
relatedGuides={questionGroup?.relatedGuides || {}}
client:load
/>
<TableOfContent toc={tableOfContent} client:load />
</div>
)
} -->
<div
class:list={[
'col-start-2 col-end-3 row-start-1 mx-auto max-w-[700px] py-5 sm:py-10',
{
'lg:border-r': showTableOfContent,
},
]}
>
<MarkdownFile>
<h1 class='mb-3 text-4xl font-bold text-balance'>
{guideFrontmatter.title}
</h1>
{
author && (
<p class='my-0 flex items-center justify-start text-sm text-gray-400'>
<a
href={`/authors/${author?.id}`}
class='inline-flex items-center font-medium underline-offset-2 hover:text-gray-600 hover:underline'
>
<img
alt={author.frontmatter.name}
src={author.frontmatter.imageUrl}
class='mr-2 mb-0 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.name}
</a>
<span class='mx-2 hidden sm:inline'>&middot;</span>
<a
class='hidden underline-offset-2 hover:text-gray-600 sm:inline'
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/question-groups/${questionGroup.id}`}
target='_blank'
>
Improve this Guide
</a>
</p>
)
}
<questionGroup.Content />
<h2 id='test-with-flashcards'>Test yourself with Flashcards</h2>
<p>
You can either use these flashcards or jump to the questions list
section below to see them in a list format.
</p>
<!-- <div class='mx-0 sm:-mb-32'>
<QuestionsList
groupId={questionGroup.id}
questions={questionGroup.questions}
client:load
/>
</div> -->
<h2 id='questions-list'>Questions List</h2>
<p>
If you prefer to see the questions in a list format, you can find them
below.
</p>
{
topicsInOrder.map((questionLevel) => (
<div class='mb-5'>
<h3 id={slugify(questionLevel)} class='mb-0 capitalize'>
{questionLevel.toLowerCase() === 'beginners' ? 'Beginner Level' :
questionLevel.toLowerCase() === 'intermediate' ? 'Intermediate Level' :
questionLevel.toLowerCase() === 'advanced' ? 'Advanced Level' :
questionLevel}
</h3>
{questionsGroupedByTopics[questionLevel].map((q) => (
<div class='mb-5'>
<h4>{q.question}</h4>
<div set:html={markdownToHtml(q.answer, false)} />
</div>
))}
</div>
))
}
{
questionGroup.ending && (
<div class='mb-5'>
<div set:html={markdownToHtml(questionGroup.ending, false)} />
</div>
)
}
</MarkdownFile>
</div>
</article>

View File

@@ -378,6 +378,11 @@ const groups: GroupType[] = [
{
group: 'Machine Learning',
roadmaps: [
{
title: 'Machine Learning',
link: '/machine-learning',
type: 'role',
},
{
title: 'AI and Data Scientist',
link: '/ai-data-scientist',
@@ -403,6 +408,11 @@ const groups: GroupType[] = [
link: '/data-analyst',
type: 'role',
},
{
title: 'Data Engineer',
link: '/data-engineer',
type: 'role',
},
{
title: 'MLOps',
link: '/mlops',
@@ -597,7 +607,7 @@ export function RoadmapsPage() {
{isFilterOpen && <X size={13} className="mr-1" />}
Categories
</button>
<div className="container relative flex flex-col gap-4 sm:flex-row">
<div className="relative container flex flex-col gap-4 sm:flex-row">
<div
className={cn(
'hidden w-full flex-col from-gray-100 sm:w-[180px] sm:border-r sm:bg-linear-to-l sm:pt-6',
@@ -635,10 +645,10 @@ export function RoadmapsPage() {
</div>
</div>
</div>
<div className="flex grow flex-col gap-6 pb-20 pt-2 sm:pt-8">
<div className="flex grow flex-col gap-6 pt-2 pb-20 sm:pt-8">
{visibleGroups.map((group) => (
<div key={`${group.group}-${group.roadmaps.length}`}>
<h2 className="mb-2 text-xs uppercase tracking-wide text-gray-400">
<h2 className="mb-2 text-xs tracking-wide text-gray-400 uppercase">
{group.group}
</h2>

View File

@@ -17,7 +17,7 @@ const links = [
isHighlighted: true,
},
{
link: '/ai?format=roadmap',
link: '/ai/roadmap',
label: 'AI Roadmaps',
description: 'Generate roadmaps with AI',
Icon: Sparkles,

View File

@@ -208,6 +208,19 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
{roadmapTreeMapping?.subjects?.length === 0 && (
<a
target="_blank"
onClick={(e) => {
if (!isLoggedIn()) {
e.preventDefault();
onLogin();
return;
}
if (isLimitExceeded) {
e.preventDefault();
onUpgrade();
return;
}
}}
href={`/ai/course/search?term=${roadmapTreeMapping?.text}&difficulty=beginner&src=topic`}
className="flex items-center gap-1 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black [&>svg:last-child]:hidden"
>

View File

@@ -1,7 +1,7 @@
---
jsonUrl: '/jsons/roadmaps/ai-data-scientist.json'
pdfUrl: '/pdfs/roadmaps/ai-data-scientist.pdf'
order: 5
order: 4.5
renderer: 'editor'
briefTitle: 'AI and Data Scientist'
briefDescription: 'Step by step guide to becoming an AI and Data Scientist in 2025'

View File

@@ -8,7 +8,7 @@ briefDescription: 'Step by step guide to becoming an AI Engineer in 2025'
title: 'AI Engineer'
description: 'Step by step guide to becoming an AI Engineer in 2025'
hasTopics: true
isNew: true
isNew: false
dimensions:
width: 968
height: 3200

View File

@@ -1,7 +1,7 @@
---
pdfUrl: '/pdfs/roadmaps/android.pdf'
renderer: 'editor'
order: 5
order: 4.7
briefTitle: 'Android'
briefDescription: 'Step by step guide to becoming an Android Developer in 2025'
title: 'Android Developer'

View File

@@ -6,7 +6,7 @@ briefTitle: 'Cloudflare'
briefDescription: 'Learn to deploy your applications on Cloudflare'
title: 'Cloudflare'
description: 'Learn to deploy your applications on Cloudflare'
isNew: true
isNew: false
hasTopics: true
renderer: editor
dimensions:

View File

@@ -1 +1,9 @@
# Distributed Systems Basics
# Distributed Systems
A distributed system is a collection of independent computers that communicate and coordinate to appear as a single unified system. They are widely used for scalability, fault tolerance, and high availability in modern applications. However, they bring challenges such as synchronization, consistency trade-offs (CAP theorem), concurrency, and network latency.
Visit the following resources to learn more:
- [@video@Quick overview](https://www.youtube.com/watch?v=IJWwfMyPu1c)
- [@article@Introduction to Distributed Systems](https://www.freecodecamp.org/news/a-thorough-introduction-to-distributed-systems-3b91562c9b3c/)
- [@article@Distributed Systems Guide](https://www.baeldung.com/cs/distributed-systems-guide)

View File

@@ -1,12 +1,12 @@
---
jsonUrl: '/jsons/roadmaps/data-engineer.json'
pdfUrl: '/pdfs/roadmaps/data-engineer.pdf'
order: 4
order: 4.6
renderer: "editor"
briefTitle: 'Data Engineer'
briefDescription: 'Step by step guide to becoming an Data Engineer in 2025'
briefDescription: 'Step by step guide to becoming a Data Engineer in 2025'
title: 'Data Engineer Roadmap'
description: 'Step by step guide to becoming an Data Engineer in 2025'
description: 'Step by step guide to becoming a Data Engineer in 2025'
hasTopics: true
isNew: true
dimensions:
@@ -28,17 +28,17 @@ courses:
title: 'Founder - roadmap.sh'
schema:
headline: 'Data Engineer Roadmap'
description: 'Learn how to become an Data Engineer with this interactive step by step guide in 2025. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place.'
description: 'Learn how to become a Data Engineer with this interactive step by step guide in 2025. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place.'
imageUrl: 'https://roadmap.sh/roadmaps/data-engineer.png'
datePublished: '2025-08-13'
dateModified: '2025-08-13'
seo:
title: 'Data Engineer Roadmap'
description: 'Learn to become an Data Engineer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern data engineers.'
description: 'Learn to become a Data Engineer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern data engineers.'
keywords:
- 'data engineer roadmap 2025'
- 'data engineering roadmap 2025'
- 'guide to becoming an data engineer'
- 'guide to becoming a data engineer'
- 'easy data engineer roadmap'
- 'data engineer'
- 'data engineer roadmap'

View File

@@ -5,4 +5,4 @@ In CI/CD pattern, the build, test, and deployment of applications to Kubernetes
Learn more from the following resources:
- [@article@Kubernetes CI/CD Pipelines 8 Best Practices and Tools](https://spacelift.io/blog/kubernetes-ci-cd)
- [@article@Octopus - Deploying to Kubernetes](https://octopus.com/use-case/kubernetes)
- [@article@8 Kubernetes CI/CD tools every developer should know](https://octopus.com/devops/kubernetes-deployments/kubernetes-ci-cd-tools-for-developers/)

View File

@@ -0,0 +1 @@
# Accuracy

View File

@@ -0,0 +1 @@
# Activation Functions

View File

@@ -0,0 +1 @@
# Actor-Critic Methods

View File

@@ -0,0 +1 @@
# APIs

View File

@@ -0,0 +1 @@
# Applications of CNNs

View File

@@ -0,0 +1 @@
# Attention Mechanisms

View File

@@ -0,0 +1 @@
# Attention Models

View File

@@ -0,0 +1 @@
# Autoencoders

View File

@@ -0,0 +1 @@
# Autoencoders

View File

@@ -0,0 +1 @@
# Back Propagation

View File

@@ -0,0 +1 @@
# Basic concepts

View File

@@ -0,0 +1 @@
# Basic Syntax

View File

@@ -0,0 +1 @@
# Basics of Probability

View File

@@ -0,0 +1 @@
# Bayes Theorem

View File

@@ -0,0 +1 @@
# Calculus

View File

@@ -0,0 +1 @@
# Chain rule of derivation

View File

@@ -0,0 +1 @@
# Classification

View File

@@ -0,0 +1 @@
# Clustering

View File

@@ -0,0 +1 @@
# Conditionals

View File

@@ -0,0 +1 @@
# Confusion Matrix

View File

@@ -0,0 +1 @@
# Convolution

View File

@@ -0,0 +1 @@
# Convolutional Neural Network

View File

@@ -0,0 +1 @@
# Data Cleaning

View File

@@ -0,0 +1 @@
# Data Formats

View File

@@ -0,0 +1 @@
# Data Loading

View File

@@ -0,0 +1 @@
# Data Preparation

View File

@@ -0,0 +1 @@
# Data Sources

View File

@@ -0,0 +1 @@
# Data Structures

View File

@@ -0,0 +1 @@
# Databases (SQL, No-SQL)

View File

@@ -0,0 +1 @@
# Decision Trees, Random Forest

View File

@@ -0,0 +1 @@
# Deep Learning Architectures

View File

@@ -0,0 +1 @@
# Deep Learning Libraries

View File

@@ -0,0 +1 @@
# Deep-Q Networks

View File

@@ -0,0 +1 @@
# Derivatives, Partial Derivatives

View File

@@ -0,0 +1 @@
# Descriptive Statistics

View File

@@ -0,0 +1 @@
# Determinants, inverse of Matrix

View File

@@ -0,0 +1 @@
# Dimensionality Reduction

View File

@@ -0,0 +1 @@
# Dimensionality Reduction

View File

@@ -0,0 +1 @@
# Discrete Mathematics

View File

@@ -0,0 +1 @@
# Eigenvalues, Diagonalization

View File

@@ -0,0 +1 @@
# ElasticNet Regularization

View File

@@ -0,0 +1 @@
# Embeddings

View File

@@ -0,0 +1 @@
# Essential libraries

View File

@@ -0,0 +1 @@
# Excel

View File

@@ -0,0 +1 @@
# Exceptions

View File

@@ -0,0 +1 @@
# Exclusive

View File

@@ -0,0 +1 @@
# Explainable AI

View File

@@ -0,0 +1 @@
# F1-Score

View File

@@ -0,0 +1 @@
# Feature Engineering

View File

@@ -0,0 +1 @@
# Feature Scaling & Normalization

View File

@@ -0,0 +1 @@
# Feature Selection

View File

@@ -0,0 +1 @@
# Forward propagation

View File

@@ -0,0 +1 @@
# Functions, Builtin Functions

View File

@@ -0,0 +1 @@
# Generative Adversarial Networks

View File

@@ -0,0 +1 @@
# Gradient Boosting Machines

View File

@@ -0,0 +1 @@
# Gradient, Jacobian, Hessian

View File

@@ -0,0 +1 @@
# Graphs & Charts

View File

@@ -0,0 +1 @@
# Hierarchical

View File

@@ -0,0 +1 @@
# Image & Video Recognition

View File

@@ -0,0 +1 @@
# Image Classification

View File

@@ -0,0 +1 @@
# Image Segmentation

View File

@@ -0,0 +1 @@
# Inferential Statistics

View File

@@ -0,0 +1 @@
# Internet

View File

@@ -0,0 +1 @@
# Introduction

View File

@@ -0,0 +1 @@
# JSON

View File

@@ -0,0 +1 @@
# K-Fold Cross Validation

View File

@@ -0,0 +1 @@
# K-Nearest Neighbors (KNN)

View File

@@ -0,0 +1 @@
# Keras

View File

@@ -0,0 +1 @@
# Lasso

View File

@@ -0,0 +1 @@
# Lemmatization

View File

@@ -0,0 +1 @@
# Linear Algebra

View File

@@ -0,0 +1 @@
# Linear Algebra

View File

@@ -0,0 +1 @@
# Linear Regression

View File

@@ -0,0 +1 @@
# Log Loss

View File

@@ -0,0 +1 @@
# Logistic Regression

View File

@@ -0,0 +1 @@
# LOOCV

Some files were not shown because too many files have changed in this diff Show More