Projects

I have created my own markup language to publish my poems on a website.

With a single click, I inject them into a deployment pipeline: from my computer to GitHub, then to an S3 bucket, an EC2 instance, and finally into a MySQL database, from which a PHP website extracts and displays them.

Introduction

The site’s content is stored in an Excel file and injected into a MySQL database via Python. PHP then dynamically generates the HTML based on tags. Everything is multilingual, easily maintained, and published online with a single click.

Before diving into the full concept, let’s take a look at how this page is actually generated.

All the text content is stored in an Excel file, which includes a column for tags and two columns for languages: French and English.

A Python script injects this data into a MySQL database, and a bit of PHP code reads the database and generates the proper HTML based on the tags.

There’s no HTML written manually — making the content easy to maintain, multilingual by design, and fully dynamic.

This mechanism represents the core architecture of the entire website.

And the best part? I can send everything from my hard drive to the live server with a single click.

Feel free to explore more below.

Problematic

I need to publish my poems in various formats (PDF, LaTeX, EPUB, website), but Word is too messy and plain text too limited. I want a clean, consistent system that supports complex structure, avoids duplication, and stays elegant — Word and Markdown don’t cut it.

I have a collection of poems on my hard drive, and I want to publish them in several different formats:

  • I’d like a convenient file format, such as PDF, to easily share them.
  • I publish my books using LaTeX, so I want the poems to be easily convertible into LaTeX.
  • It would be useful to generate an EPUB version if needed.
  • Ideally, I’d like a clean and elegant webpage that gathers all my poems.
  • The easy solution: Word

    The easiest solution would be to use a Microsoft Word file. I can export it as PDF, HTML, and probably even LaTeX. With proper use of headings and formatting, it could provide a consistent and visually appealing result.

    It wouldn’t be a bad choice — in fact, I’m pretty sure this is what 95% of poetry writers are doing.

    Well, it turns out I belong to the other 5%, because Word simply isn’t convenient for me at all.

    Problem #1: Plain text files

    I write in plain text, using the old version of Windows Notepad.

    When inspiration strikes, I need my writing tool to appear in one second, with one click — nothing more.

    Once a poem is written, I just drop the text file in the right folder.

    It can stay there, untouched, waiting for years before someone reads it again.

    Problem #2: Too many copies

    In terms of workflow, I’d end up with several versions: the plain text file, the HTML version on the website, exported files, etc.

    If I make a correction — even just a comma — I have to apply it everywhere.

    And if I forget even once, everything becomes inconsistent. I lose track of the “most correct” version.

    Real nightmare.

    Problem #3: Complex poems

    Most of my poems are quite simple. But some include varied line breaks, indents, quotes…

    I also write songs, so I need structures like verse, chorus, bridge, etc.

    Using something like Markdown for that would be far too limited — and unnecessarily complicated.

    Problem #4: Not fluid at all

    Writing poems is nice. Coding little apps is nice too.

    But uploading via FTP, adding <code><p></p></code> manually to every line, and propagating corrections everywhere...

    That’s annoying and time-consuming.

    Problem #5: Dirty, dirty Word

    I have a kind of minimalist mindset. I like clean code — no useless lines. Clean CSS — no unnecessary classes.

    If you’ve ever exported a document from Word, you know that “clean” is the last word you’d use to describe the result.

    Of course, I could write a script to clean that up (actually, I did that for my screenplays — but that’s another story).

    But if you’re aiming for a clean workflow, Word should probably be kept out of it.

    The real solution

    To avoid the limitations of Word and Markdown, I created Lyra, my own markup language for poetry. It supports multilingual typography, LaTeX constraints, song structure, and custom formatting. A Python script processes the files and feeds them into a pipeline — from my PC to GitHub, S3, EC2, MySQL, and finally the PHP website — all in one click.

    After considering all of this, I came up with a more tailored solution: creating my own markup language and building a pipeline from my local hard drive to an AWS server.

    So yes — if I had to sum up the project in a more poetic or “tech-portfolio” way, it would go like this:

    I have created my own markup language to publish my poems on a website.

    With a single click, I inject them into a pipeline: from my computer → to GitHub → to an S3 bucket → to an EC2 instance → to a MySQL database, extracted by a PHP website.

    A shorter pipeline might be technically possible, but since I also need to upload the entire website — not just the poems — this approach makes more sense.

    Besides, while the website beautifully showcases the poetic part, GitHub is the right place to highlight the coding side.

    And speaking of poetry and code, let’s take a look at what my custom markup language actually looks like.

    Lyra, a mark-up language for poetry

    There are several challenges in creating such a language.

    Multilingual typography

    The main one is typography rules. I mainly write in French, but sometimes in English — and their punctuation and typographic conventions are very different.

    LaTeX handles this quite well, but HTML doesn’t.

    So my master text must remain as typographically neutral as possible.

    Then, the conversion script is in charge of flattening inconsistencies and applying the correct formatting according to the language.

    Here’s a short example to illustrate the challenge:

    Some would ask: “What is typography?” That’s a legit question—that I need to answer in French.

    Vous demandez donc: « qu’est-ce que la typographie ? » Je vous répondrais bien — mais plus tard.

    You can clearly see the differences: “ ” vs. « »; thin spaces vs. no spaces; em-dashes vs. hyphens…

    It needs to be handled carefully and automatically.

    LaTeX constraints

    I love publishing with LaTeX, but LaTeX has its own preferences.

    For instance, it doesn’t like “—” and expects you to write “<code>---</code>” instead.

    After years of using LaTeX, typing “<code>--</code>” and “<code>---</code>” has become second nature.

    Also, as mentioned earlier, LaTeX expects English-style spacing by default, and applies the correct rules depending on the language setting.

    I wouldn’t want to upset Mister LaTeX — so I comply.

    Songs & poetry

    As you already know, I write poetry — fine.

    But I also write songs, which means I need formatting for verses, choruses, bridges, and more.

    It’s not a big deal, but it’s something my markup language must be able to handle.

    The language

    Taking all these constraints into account, I came up with a custom markup language called Lyra — probably because I’m a bit too obsessed with Ancient Greek culture.

    You can see the full implementation in the code panel, but here are the key transformations it applies:

    text = text.replace('\u202f',' ').replace('\u00a0',' ').replace('\t',' ')

    text = re.sub(r'\s{2,}',' ', text)

    This first step removes all invisible characters like:

  • <code>\u202f</code> (narrow no-break space)
  • <code>\u00a0</code> (non-breaking space)
  • <code>\t</code> (tabulation)
  • All of them are replaced by a standard space.

    Then, <code>r'\s{2,}'</code> reduces multiple spaces to a single one, ensuring that the script processes a clean and consistent text.

    text = text.replace("<<","« ").replace(">>"," »")

    text = text.replace("+-+","—").replace("=+=","[…]")

    Same mechanism here: I replace specific markers by the expected typographic characters.

    if typographie=="fr":

    text = re.sub(r'(?<! )([!?;:])', '\u202f\\1', text)

    else:

    text = re.sub(r'\s+([!?;:])', r'\1', text)

    And here’s where it gets interesting: typographic rules change depending on the language.

    If the language is French, we add a narrow space before specific punctuation marks.

    If it's English, we follow classic English punctuation spacing.

    text = text.strip()

    text = re.sub(r'<!--.*?-->', '', text)

    text = re.sub(r'%.*$', '', text)

    return text

    Final cleanup: <code>strip()</code> removes leading and trailing spaces.

    The <code>re.sub</code> lines delete HTML-style comments and lines starting with <code>%</code>, both of which I use as internal notes.

    Punctuation

    ’, ‘, ‛&nbsp;&nbsp;→&nbsp;'

    ----, ---, --, –&nbsp;&nbsp;→&nbsp;—

    …&nbsp;&nbsp;→&nbsp;…

    <<&nbsp;&nbsp;→&nbsp;«

    >>&nbsp;&nbsp;→&nbsp;»

    +-+&nbsp;&nbsp;→&nbsp;—

    =+=&nbsp;&nbsp;→&nbsp;[…]

    Comments

    <!-- xxx -->&nbsp;&nbsp;→&nbsp;deleted

    %&nbsp;&nbsp;→&nbsp;deleted

    Font styling

    * xxx *&nbsp;&nbsp;→&nbsp;italic

    *µ xxx µ*&nbsp;&nbsp;→&nbsp;bold

    *µµ xxx µµ*&nbsp;&nbsp;→&nbsp;italic bold

    ££&nbsp;&nbsp;→&nbsp;acrostic

    Titles

    #&nbsp;&nbsp;→&nbsp;Title

    ##&nbsp;&nbsp;→&nbsp;Author

    ###&nbsp;&nbsp;→&nbsp;Compilation Title

    ####&nbsp;&nbsp;→&nbsp;Year

    #####&nbsp;&nbsp;→&nbsp;Sub-title

    >$&nbsp;&nbsp;→&nbsp;Part number

    Non verse

    <=+ xxx +=>&nbsp;&nbsp;→&nbsp;Non-verse text

    <+ xxx +>&nbsp;&nbsp;→&nbsp;Quotation

    <++ xxx ++>&nbsp;&nbsp;→&nbsp;Quotation’s Author

    Song structure

    ²cpl1&nbsp;&nbsp;→&nbsp;fr: [Couplet 1] en: [Verse 1]

    ²rfn1&nbsp;&nbsp;→&nbsp;fr: [Refrain 1] en: [Chorus 1]

    ²pnt&nbsp;&nbsp;→&nbsp;fr: [Pont] en: [Bridge]

    ²rnv&nbsp;&nbsp;→&nbsp;fr: [Renvoi]en: [Tag]

    ²itl&nbsp;&nbsp;→&nbsp;[Interlude]

    ²int&nbsp;&nbsp;→&nbsp;[Intro]

    ²out&nbsp;&nbsp;→&nbsp;[Outro]

    ²brp&nbsp;&nbsp;→&nbsp;(bis repetitas)

    Alignments

    <= xxx =>&nbsp;&nbsp;→&nbsp;Centered

    <== xxx ==>&nbsp;&nbsp;→&nbsp;Right-aligned

    Stanzas

    >=&nbsp;&nbsp;→&nbsp;Regular Line Jump

    >==&nbsp;&nbsp;→&nbsp;Medium Line Jump

    >===&nbsp;&nbsp;→&nbsp;Big Line Jump

    Indents

    >+&nbsp;&nbsp;→&nbsp;Regular Indent

    >++&nbsp;&nbsp;→&nbsp;Medium Indent

    >+++&nbsp;&nbsp;→&nbsp;Big Indent

    >++++&nbsp;&nbsp;→&nbsp;Right Shift

    Next step

    Once the markup language was defined and the Python conversion script was ready, it was time to move on to the next step:

    building the pipeline to publish the poems online.

    Building the project

    I built a full deployment pipeline to publish my poetry and website content in one click:
    From my PC → GitHub → S3 → Lambda → EC2 → Python scripts → MySQL.
    I created a custom markup language (Lyra) to handle multilingual formatting and designed the site with a clean structure and real AWS services: VPC, EC2, S3, Route 53, IAM, and more.
    Local dev runs on Windows with batch + shell scripts triggering GitHub Actions. It’s fully automated and dynamic.

    The pipeline

    The concept is simple: publish new poems online in a single click.

    Back in the day, we did that with a good old FTP server — you connected, dropped the files into the client, and the site was updated.

    It wasn’t exactly “one click,” but it was close enough.

    Unfortunately, that era is mostly gone (well, not entirely — I still see multinational companies working like that daily, but never mind).

    Now that we live in the Cloud era, and since I’m developing my skills on AWS, here’s how my pipeline works:

  • I write <code>.ryu</code> text files using my homemade markup language, Lyra. They’re stored in a Poetry subfolder inside my Writing directory.
  • A batch script copies them to my <code>scripts/website</code> folder, where they are grouped with all the PHP/HTML files.
  • From there, I push everything to GitHub — because my Big Beautiful code deserves to be seen, and GitHub is the place for that.
  • A GitHub Action zips the project and uploads it to my S3 bucket on AWS.
  • This S3 upload triggers a Lambda function that transfers the archive to my EC2 instance.
  • On the EC2 instance, a Python script unzips the file, converts all <code>.ryu</code> files into HTML, and uploads them to my MySQL database.
  • And just like that — my website is updated and all my poetry is online.

    In parallel, I also process an Excel file containing all French and English content for the website, convert some Word documents into HTML, and more.

    As you can see, it’s a fun pipeline. Stay tuned for more technical details.

    Account creation

    Creating all the accounts was actually the last step of the project — but it makes more sense to present it at the beginning of the story.

    So, I subscribed to an AWS account, created a VPC, launched an EC2 instance, opened an S3 bucket, and registered my domain name fdelancelot.com via Route 53.

    I also configured IAM accounts and security roles — but we’ll come back to that later.

    I also created a repository on GitHub, which allowed me to prepare the entire pipeline from local development to cloud deployment.

    Local development setup (Windows)

    I play and record music. For many years, most music production tools weren’t available on Linux — which is one of the reasons I still work on Windows today.

    On my computer, I have a Writing folder that contains all my creative work, organized into subfolders:

  • Novels
  • Short Novels
  • Poetry
  • Scripts (as in film scripts — not Python ?)
  • Articles
  • When a project is complete, I save it as a plain text file with a <code>.ryu</code> extension.

    From there, I can export it to LaTeX, PDF, or HTML.

    For more complex works, like novels and screenplays, I use specific Word templates that I’ve refined over time and rely on daily.

    So, the very first step of my pipeline is simply to retrieve the files I want to publish online.

    Batch file & sh file

    For poetry, I use a Batch file that copies all <code>.ryu</code> files — preserving the folder structure — into my local repository.

    The same script also copies <code>.ryu</code> files from the Short Novels folder, and <code>.docx</code> files from the Scripts folder, into their respective locations in the repository.

    Finally, the batch file launches a Shell script in Git Bash to synchronize the repository with GitHub.

    This push will later trigger a GitHub Action — but we’ll get to that in the next section.

    GitHub

    Since this website also serves as a portfolio, I obviously use GitHub as an integral part of the pipeline.

    It allows me to showcase my code and keep version control.

    When I push the repository using my shell script, it triggers a GitHub Action that automatically uploads a ZIP archive of the website to my S3 bucket.

    That was the easy part.

    Now comes the fun part — setting up the entire AWS architecture.

    AWS configuration

    I could easily write thousands of lines about how I configured my AWS architecture,

    but to keep things readable, here’s a summarized list of what’s been deployed.

    VPC

  • CIDR block: 10.0.0.0/16
  • Public subnet: 10.0.0.0/20 — for serving the website (Apache on ports 80/443)
  • Private subnet: 10.0.128.0/20 — reserved for future internal services (e.g. databases)
  • Internet Gateway: attached to allow internet access
  • Route Table: properly configured to manage traffic
  • Elastic IP: bound to ensure persistent domain resolution (13.48.51.102)
  • An EC2 instance is deployed inside this VPC and accessed via SSH using a <code>.pem</code> key.

    EC2 instance

  • Instance type: Amazon Linux t2.micro (Free Tier eligible)
  • Installed stack: LAMP (Apache, MariaDB, PHP) via <code>yum</code>
  • Apache configured with virtual hosts, PHP enabled, <code>.htaccess</code> supported
  • MariaDB set up with users and database creation
  • Python 3.9 installed with:
  • <code>mysql-connector-python</code>
  • <code>pandas</code>, <code>python-dotenv</code>, <code>sqlalchemy</code>, <code>unidecode</code>, etc.
  • Certbot installed with Let’s Encrypt:
  • Certificates issued for <code>fdelancelot.com</code> and <code>www.fdelancelot.com</code>
  • Cron job planned for auto-renewal
  • SSM Agent installed and configured for remote commands
  • Amazon S3

  • Bucket created to store the deployment archive <code>site.zip</code>
  • Bucket policy adjusted to allow EC2 access
  • Amazon Route 53

    Domain name fdelancelot.com purchased directly through Route 53.

    Lambda

    A Lambda function was created to transfer the <code>.zip</code> file from the S3 bucket to the EC2 instance.

    It is triggered automatically upon file upload (either manually or via GitHub Action).

    Other AWS setup

  • AWS Systems Manager (SSM): used to execute Lambda commands on EC2
  • Budget: monthly limit set to 5€
  • IAM

  • Admin user: for daily use (MFA enabled)
  • Automation user: for GitHub CI/CD, with policies:
  • AmazonS3FullAccess
  • AmazonSSMFullAccess
  • AmazonSSMManagedInstanceCore
  • EC2 instance role: with permissions for S3 and SSM
  • Lambda role: with <code>ssm:SendCommand</code> permission and access to the S3 archive
  • Security

  • MFA enabled on the root account and other critical users
  • Firewall (Security Groups) properly configured:
  • Port 22 (SSH): restricted to my own IP only
  • Ports 80 & 443 (HTTP/HTTPS): open for public web access
  • Python ecosystem & automation

    Little sum up

    Let’s go over the full deployment sequence from the top:

  • Batch script: copies all required creative files (poems, scripts, short novels) into the local repository
  • Bash script: launched by the batch file to push the repository to GitHub
  • GitHub Action: triggered by the push — it zips the project and uploads it to the S3 bucket
  • Lambda function: triggered by the new ZIP file in S3
  • Copies the ZIP to <code>/tmp</code> on the EC2 instance using SSM
  • Executes the deploy.py script
  • deploy.py

    The script deploy.py orchestrates the entire deployment process:

  • Unzips the archive and moves the content into the appropriate directory
  • Copies the <code>.env</code> file from a secure folder on the EC2 instance
  • Executes three key Python scripts in sequence:
  • poemstohtml.py

    This script converts <code>.ryu</code> poems into HTML.

    You’ve seen it before — it transforms the content written in my Lyra markup into HTML and uploads each poem into the <code>poems</code> table of the MySQL database.

    Each poem is stored on a single row.

    The database table uses lovely French column names:

    uid → A unique ID

    id_logique→ An identifier built from the initials of the compilation and poem

    titre → The title of the poem

    recueil → The compilation title

    type → The type (e.g. poem, song, etc.)

    fichier → The original file name

    contenu → The full HTML content

    date_import → I’ll let your French handle this one ;)

    The <code>id_logique</code> is all I need to retrieve a specific poem, call an entire compilation, or preserve the intended sorting based on filenames.

    screenplayconvert.py

    This script scans all <code>.docx</code> files from the Scripts folder and converts them into <code>.php</code> files ready to be included directly on the website.

    There are Python libraries that could do this out of the box — but writing it from scratch was more fun.

    Not the smartest move, maybe, but it was an interesting exercise in craftsmanship.

    translationxlsx.py

    This is the heart of the website.

    I maintain an Excel file that contains:

  • 4 key columns, which I concatenate into a unique identifier formatted like: <code>pagename.section.subsection.number</code>
  • 1 column for the English text
  • 1 column for the French text
  • The script uploads the combined key and both language strings into a 3-column MySQL table.

    On the website, a PHP function calls the correct string depending on the current page and selected language, using the key as an argument.

    File structure

  • A complete project structure with folders such as <code>site/</code>, <code>content/</code>, <code>scripts/</code>, etc.
  • A <code>.env.example</code> and <code>.gitignore</code> file to avoid committing secrets
  • A <code>deploy.ps1</code> PowerShell script to automate Git operations
  • Later replaced by a Bash script <code>deploy.sh</code> for better cross-platform compatibility
  • A <code>.bat</code> file created to launch it with a double-click on Windows
  • Additional logic added to:
  • Copy <code>.ryu</code> and <code>.docx</code> files from Poésie, Nouvelles, and Scripts folders into the GitHub repository
  • Add optional <code><meta name="keywords"></code> tags
  • Generate <code>sitemap.xml</code> and <code>robots.txt</code>
  • Use JSON-LD or microdata for semantic markup (profile, works, skills)
  • Main sections identified

  • Hero: a two-column layout with a title, description, call-to-action buttons, social icons, and an image
  • Resume: includes “About me” and a full résumé — multiple paragraphs followed by a structured CV (summary, skills, experience, education, certifications)
  • Skills: horizontal bars showing proficiency in front-end and back-end technologies
  • Contact: info boxes (location, phone, email) and a PHP-powered contact form
  • Footer: copyright notice and credits
  • Website architecture

    The website is both an artistic portfolio and a technical showcase.
    It uses PHP + MySQL to dynamically serve multilingual content from a translation table.
    Each page loads based on a clean index.php structure, with special handling for .ryu short novels and dynamic poetry listings.
    All content is fetched using a unified key system like page.section.subsection.number.

    The purpose of this website is twofold:

    To showcase both my artistic work (music, poetry, scripts) and my technical abilities with AWS technologies.

    Here’s how the site is structured:

  • Home page, including:
  • Short introduction
  • “About me” section
  • “Skills” section
  • “Résumé” section
  • “Contact” section
  • Projects page — the one you're reading now
  • Artworks page, with subsections:
  • Music
  • Poetry
  • Scripts
  • YouTube
  • Short Novels
  • Books
  • Poetry page — a complete dynamic compilation of all my poems
  • The entire website is multilingual (English/French).

    A simple PHP function reads the <code>$_GET['l']</code> variable to determine the page’s language and then retrieves the appropriate content from the MySQL database.

    function t(string $key): void {

    global $pdo, $l;

    $stmt = $pdo->prepare("SELECT content FROM translations WHERE lang = :lang AND `key` = :key LIMIT 1");

    $stmt->execute([':lang' => $l, ':key' => $key]);

    $text = $stmt->fetchColumn() ?: "[$key]";

    $text = allowtags($text);

    echo $text;

    }

    PHP architecture

    The website is built around a central file: <code>index.php</code>.

    This file loads the following components:

  • <code>var.php</code>
  • <code>function.php</code>
  • <code>header.php</code>
  • <code>nav.php</code>
  • <code>footer.php</code>
  • Between the navigation and the footer, one of the main content pages is included, depending on the route:

  • <code>home.php</code>
  • <code>artwork.php</code>
  • <code>poetry.php</code>
  • <code>projects.php</code>
  • There are also 6 <code>.ryu</code> short novel files, which are dynamically converted into PHP and included inside a collapsible area triggered by a button — more on that later.

    Additionally, two special PHP files — <code>mariup.php</code> and <code>souven.php</code> — each display either a theater play or a screenplay, while preserving the main layout and architecture of the site.

    Details of each page

    Most pages are generated using the same logic:

    A PHP function loops over a translation key formatted like <code>page.section.subsection.number</code>, and continues incrementing the number until there is no more text to fetch.

    The Poetry page follows this same principle but on a much larger scale — it displays the full contents of the <code>poems</code> table dynamically.

    The Short Novels section is slightly more advanced:

    It dynamically scans the <code>nouvelles</code> folder for all <code>.ryu</code> files, converts them into HTML, and pairs them with their corresponding summary from the translation table.

    Each short novel is then loaded into a collapse component, triggered by a button.

    This approach avoids overloading the page with too much content at once, keeping the layout clean and readable.

    Conclusion

    This project had two goals: showcase my poetry and demonstrate real AWS technical deployment.
    I built everything from scratch with PHP, Python, and MySQL, using a custom markup language and an automated CI/CD pipeline.
    The architecture runs on AWS (EC2, S3, Lambda, Route 53, etc.), and everything — from code to content — is modular, multilingual, and low-cost.
    I achieved almost all my goals and identified new areas for improvement like better SEO, Vue.js components, and a Lyra validator.

    Main goals

    When designing this website, I had several goals in mind:

  • Create an elegant and responsive website
  • Build a fully internationalized interface (i18n), easily scalable to other languages
  • Ensure fast loading times
  • Develop a one-click deployment pipeline
  • Publish my poetry using my Lyra markup language, without having to modify it
  • Showcase my artistic work (music, writings, etc.)
  • Keep the codebase minimalist and clean
  • Host everything on AWS, with real and professional infrastructure
  • Use it as a technical portfolio for job applications
  • Learn new skills through practical implementation
  • Use Python for core automation
  • Stick to a small budget (target: less than 5€/month)
  • Build a dynamic website with real-time content
  • Design a modular system that is easy to maintain
  • Keep URLs clean — without those ugly <code>$_GET[] ?var=name</code>
  • Use MySQL as the database engine
  • Use no CMS or heavy frameworks — build everything from scratch
  • Integrate cron jobs, structured JSON, and custom JavaScript widgets
  • Path of improvement

    I enjoy working with PHP, but perhaps it’s time to consider switching to a full Python framework like Flask.

    Since I prefer minimalist and lightweight websites, adopting Tailwind CSS would help eliminate the 98% of unused Bootstrap classes.

    Alternatively, I might explore more of Bootstrap’s built-in components — such as modals or carousels.

  • Some error messages are not multilingual yet — I should fix that.
  • The pipeline could use better logging, testing, and warnings for failures.
  • Lyra deserves its own dedicated documentation page — that’s definitely coming soon.
  • If I want to explore frontend frameworks, I could start migrating some components to Vue.js or React.
  • A web interface to export my texts in EPUB, PDF, or LaTeX could be very useful.
  • Creating a Lyra validator could help detect typos or formatting issues, even if the language is simple.
  • I could also significantly improve the SEO with structured data and a dynamic sitemap — that’s probably the next step.
  • Tools & syntax we used

    Local Development Environment

  • Notepad++ – Used primarily to edit my <code>.ryu</code> poetry files
  • Git Bash – Executes Bash scripts for Git operations
  • Batch (.bat) – Windows automation for file processing
  • Visual Studio Code (VS Code) – Main development environment
  • XAMPP – Local Apache + MariaDB stack for development and offline testing
  • Microsoft Excel – Manages the multilingual translation table
  • Microsoft Word – My primary writing tool for books and screenplays
  • Git – Version control
  • GitHub – Code hosting and CI/CD with GitHub Actions
  • Programming Languages

  • Python
  • Custom scripts: <code>poemstohtml.py</code>, <code>screenplayconvert.py</code>, <code>translationxlsx.py</code>
  • Conversion from Lyra to HTML and LaTeX
  • Upload to MySQL using <code>mysql-connector-python</code>
  • Used in EC2 deployment and orchestration
  • PHP
  • Dynamic content display
  • Multilingual functions
  • Contact form logic
  • HTML / CSS
  • Site structure
  • Minimalist, responsive design
  • JavaScript
  • Vanilla JS for interactions
  • Widgets: collapses, counters, triggers
  • SQL (MySQL / MariaDB)
  • Poem storage, translation database, metadata
  • Libraries & Frameworks

  • Bootstrap 5 (via CDN) – Responsive grid system and components (collapse, cards, etc.)
  • AOS.js – Scroll-triggered animations
  • PureCounter.js – Animated counters
  • Waypoints.js – Scroll position triggers
  • Google Fonts – Online typography
  • Certbot / Let’s Encrypt – HTTPS certificate generation and renewal
  • AWS Services

  • EC2 (Amazon Linux 2) – Web hosting
  • S3 – Storage for deployment archives
  • Lambda – Pipeline trigger upon file upload
  • Systems Manager (SSM) – Remote command execution on EC2
  • IAM – Role and permission management
  • Route 53 – Domain name management (<code>fdelancelot.com</code>)
  • VPC – Custom network architecture
  • Server Technologies

  • Apache (httpd) – Web server
  • MariaDB – Database engine
  • PHP 8.x – Dynamic page rendering
  • Python 3.9 – Execution of scripts on the EC2 server
  • SSM Agent – Enables remote SSM commands
  • YUM – Package manager for Amazon Linux
  • Custom Structure & Formats

  • Lyra – My personal markup language for poetry
  • <code>.ryu</code> – Custom file extension for poems
  • <code>.env</code> – Environment configuration
  • <code>.xlsx</code> – Centralized multilingual translation base
  • Automation & DevOps

  • GitHub Actions – CI/CD automation: ZIP → S3
  • Bash scripts – Git push and file deployment
  • Batch / PowerShell / Shell – Windows automation and cross-platform compatibility
  • Python scripts – File parsing, conversion, database injection
  • Cron – Automated SSL certificate renewal (Let’s Encrypt)
  • ZIP – Archiving the site before upload
  • Finale analysis

    I reached (almost) all my goals: fully responsive website, multilingual & dynamic, one-click deployment pipeline, clean code, modular, low-cost, hosted entirely on AWS, custom markup language for poetry, learned new technical skills.
    Some areas could be improved (UI richness, SEO, deeper Python/MySQL use), but overall, this project proves both my technical and artistic abilities.

    Did I reach all my goals?

    ?Create an elegant and responsive website — YES

    This portfolio is intended to showcase my AWS skills, so it's likely to be viewed by recruiters on desktop.

    That said, we live in a mobile-first world, so responsive design was essential.

    It’s not a full “mobile-first” approach, but it is still mobile-friendly.

    Aesthetically, I’m no professional designer, but I find the Black & Gold interface quite elegant — it matches the mood of my artistic universe.

    I’m especially proud of my custom buttons: transparent at rest, filled on click.

    ?i18n interface — YES

    The multilingual interface is easy to maintain — a single Excel file holds all the content.

    Adding a new language would be simple (as long as we ignore the time-consuming task of actual translation).

    ?Fast-loading web page — YES

    AWS seems to perform well, and I did my best to keep the site light: minimal images, CDN-hosted libraries and fonts.

    ?One-click deployment pipeline — YES

    This is the heart of the project — and it works beautifully.

    A single click on a batch file triggers the entire automated pipeline.

    ?Publishing poetry via my markup language without modifying it — YES

    I made a few minor adjustments to the markup for clarity, and tweaked the Python-to-LaTeX conversion script — it took less than 30 minutes.

    So yes, it's a complete success.

    ?Displaying my artistic work (music, writings, etc.) — Partly YES

    I had envisioned something more visually rich: photos of the bands, a music player, embedded videos, etc.

    While technically feasible, such additions might overwhelm the visitor.

    For now, there are clear links to the bands’ SoundCloud pages and YouTube channels.

    The result is simpler than I imagined, but also more readable — which is a success in itself.

    ?Keeping minimalist, clean code — YES

    The project includes many files and functions — which is normal given its scope.

    I made a serious effort to avoid redundancy, write clean logic, and add clear comments wherever needed.

    ?Hosted on AWS with real technical deployment — YES

    AWS deployment was far more challenging than expected.

    Studying for the Cloud Practitioner certification is one thing — but actually building and deploying something is something else entirely.

    From opening an SSH session to assigning roles to Lambda functions, it’s been a deep and rewarding learning experience.

    Clearly, an AWS certification alone wouldn’t be enough to be job-ready. Building this project made that very clear.

    ?Use as a portfolio for job prospection — YES (hopefully)

    I say "yes", but the honest answer is: hopefully yes.

    I believe this project reflects what I’m capable of — both technically and artistically.

    ?Learning new skills — YES

    I’ve definitely learned many new things — primarily on AWS, but also beyond:

    SSH connections, LAMP stack setup, Linux environments, Apache configuration, and custom VPC design.

    Studying for the CCNA certification helped a lot, especially with the networking side.

    I also refined my coding skills and even discovered a few unexpected tricks in CSS.

    ?Using Python — Partly YES

    I used Python extensively, but I stayed within a comfortable scope — no advanced algorithms or external APIs yet.

    ?Keeping a small budget (< 5€/month) — YES

    Aside from the domain name purchase, everything else runs at 0€/month thanks to AWS Free Tier. Perfect.

    ?Dynamic website — YES

    The site is fully dynamic.

    Almost everything is PHP-based: poems are generated on the fly, and most of the content comes from translation functions or database calls.

    ?Modular and easy to maintain — YES

    Storing all the text in an Excel file makes updates incredibly easy:

    just insert a new line with the right key, and the PHP function will display it.

    For poems, it’s even simpler: renaming or adding new <code>.ryu</code> files locally is enough — the structure is automatically reflected online.

    ?Clean URLs (no ugly <code>$_GET[]</code>) — YES

    Initially, I built the entire site around a single <code>index.php</code> file, which was elegant — but terrible for SEO.

    I later adjusted the URLs to be clean and indexable, and I’m happy with the final result.

    ?Using MySQL — Partly YES

    I used MySQL, but only for basic queries.

    The only new thing I had to learn was how to deploy MariaDB on my EC2 server.

    Still, it’s a solid starting point.

    ?No framework, built from scratch — YES (mostly)

    I didn’t use any heavy CMS like WordPress, and that was intentional.

    That said, I did rely on some JS libraries (PureCounter, Waypoints, etc.), and of course, Bootstrap.

    Writing my own JS widgets might have been a fun learning exercise, and maybe I’ll explore that later.

    But Bootstrap? It just makes sense.

    It’s lightweight enough, and being just CSS and JS, it doesn’t stop me from coding everything myself.

    Using a minimal CSS framework allowed me to focus on the real logic — and that was the right choice.

    And that will be the final word: using just enough CSS framework to stay efficient, without losing control.

    Thank you for reading this very long text.