feat(db): Implement schema migrations and add Projects section
Introduces a custom migration system for SQLite, allowing incremental and safe schema evolution. Adds a new 'Projects' section to the CV, including database tables, public UI, and full management in the admin dashboard with live editing, drag-and-drop reordering, and collapsible forms. Updates: - and for schema management. - with script. - to use migrations. - to rely on migrations. - and for new project data operations. - and for Projects UI. - and to integrate the Projects section. Also updates: - to automatically import Keycloak realm on startup. - for the Elysia app build. - with refined print styles (omitting socials and about).
This commit is contained in:
@@ -56,6 +56,19 @@ interface Skill extends SkillTranslation {
|
||||
display_order: number;
|
||||
}
|
||||
|
||||
interface ProjectTranslation {
|
||||
name: string;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
interface Project extends ProjectTranslation {
|
||||
id: number;
|
||||
project_url: string | null;
|
||||
image_url: string | null;
|
||||
tech_stack: string | null;
|
||||
display_order: number;
|
||||
}
|
||||
|
||||
export function getProfile(lang: string): Profile | null {
|
||||
const profile = db.query(`
|
||||
SELECT p.email, p.phone, p.website, p.github_url, p.linkedin_url, p.avatar_url,
|
||||
@@ -91,6 +104,18 @@ export function getEducation(lang: string): Education[] {
|
||||
return education;
|
||||
}
|
||||
|
||||
export function getProjects(lang: string): Project[] {
|
||||
const projects = db.query(`
|
||||
SELECT p.id, p.project_url, p.image_url, p.tech_stack, p.display_order,
|
||||
pt.name, pt.description
|
||||
FROM projects p
|
||||
JOIN project_translations pt ON p.id = pt.project_id
|
||||
WHERE pt.language_code = $lang
|
||||
ORDER BY p.display_order ASC
|
||||
`).all({ $lang: lang }) as Project[];
|
||||
return projects;
|
||||
}
|
||||
|
||||
export function getSkills(lang: string): Skill[] {
|
||||
const skills = db.query(`
|
||||
SELECT s.category, s.icon, s.display_order,
|
||||
@@ -108,6 +133,7 @@ export function getAllData(lang: string) {
|
||||
profile: getProfile(lang),
|
||||
experience: getExperience(lang),
|
||||
education: getEducation(lang),
|
||||
projects: getProjects(lang),
|
||||
skills: getSkills(lang),
|
||||
};
|
||||
}
|
||||
@@ -180,3 +206,27 @@ export function getAdminEducationById(id: number) {
|
||||
});
|
||||
return e;
|
||||
}
|
||||
|
||||
export function getAdminProjects() {
|
||||
const projs = db.query(`SELECT p.*, MAX(p.display_order) OVER () AS max_order FROM projects p ORDER BY p.display_order ASC`).all() as any[];
|
||||
return projs.map(p => {
|
||||
const trans = db.query(`SELECT * FROM project_translations WHERE project_id = $id`).all({ $id: p.id }) as any[];
|
||||
trans.forEach(t => {
|
||||
p[`name_${t.language_code}`] = t.name;
|
||||
p[`description_${t.language_code}`] = t.description;
|
||||
});
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
export function getAdminProjectById(id: number) {
|
||||
const p = db.query(`SELECT * FROM projects WHERE id = $id`).get({ $id: id }) as any;
|
||||
if (!p) return null;
|
||||
|
||||
const trans = db.query(`SELECT * FROM project_translations WHERE project_id = $id`).all({ $id: id }) as any[];
|
||||
trans.forEach(t => {
|
||||
p[`name_${t.language_code}`] = t.name;
|
||||
p[`description_${t.language_code}`] = t.description;
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user