# academia.sh

> academia.sh is a learning platform with free, no-signup lessons that never separates a lesson's theory from a real problem from the field. It's presented through a curriculum-course-topic-lesson hierarchy, progress and quizzes are measured per lesson without splitting theory from problem, and full-text search runs on Postgres; the course-end exam, certificates and study assistant sit in a Pro tier. Content lives in a separate GitHub repo; the first field is computer science, and the model was designed multidisciplinary from the start.

- Role: Founder & Author
- Class: Side Publications
- Status: Ongoing
- Started: 2026-09-23
- Technologies: Laravel, PHP, Livewire, Blade, Tailwind, PostgreSQL, Redis, Filament, Pest
- Skills: Content Strategy, Curriculum Design, Full-Text Search, Database Design, Technical Writing, Static Content Architecture
- Website: https://academia.sh
- Source: https://muhammetsafak.com/portfolio/academia/
- Language: en-US
- Author: Muhammet Şafak

---
academia.sh is a learning platform with free, no-signup lessons that never separates a lesson's theory from a real problem from the field; it's presented through a curriculum-course-topic-lesson hierarchy. Lessons are free to read without an account; the course-end exam, verifiable certificate and study assistant sit in a Pro tier. The problem from the field isn't a separate exercise — it sits in the lesson's own text as a continuation of the theory, which is why progress percentage and quizzes are measured per "published, active lesson" without splitting theory from problem. The first content is computer science, but the model was designed multidisciplinary from the start: adding a new field means writing lessons, not changing the schema.

I built the stack on Laravel 13, Livewire and Tailwind, and full-text search on PostgreSQL's own engine (`ts_rank_cd` ranking, `ts_headline` snippets); `search_vector` can't be a generated column because the cast that turns `to_tsvector`'s dictionary argument into a `regconfig` isn't considered immutable, so a trigger produces the vector instead. Content isn't born in the application's database — it lives in a separate GitHub repo and the platform is fed from there; that's the only form in which it can genuinely open up to contribution. On a certificate, `holder_name` and `course_title` are frozen at the moment of issue; even if a lesson's mark is later revoked, the printed document keeps its validity.
