A content management system where authors, editors and publishers each have the right permissions across business units. Pages render in under 60ms and pass a full security audit.

Overview
What this is and why it matters, in plain English.
A content management system where authors, editors and publishers each have the right permissions across business units. Pages render in under 60ms and pass a full security audit.
A publishing system for large teams: clear approval steps, fast pages and a full record of every change.
The situation
What was going on before, and why it needed fixing.
Editorial teams across several business units published to multiple publications. Each needed its own approval chain, and changes had to be traceable after the fact.
Corporate editorial teams required granular publishing approval workflows with distinct permissions for authors, editors, and publishers across multiple publications.
What it needed to do
The outcomes the project had to deliver.
- Model author, editor and publisher permissions per business unit.
- Serve pages fast from cache while keeping published changes visible immediately.
- Make custom rich-text content safe to render.
What I did
My part of the work and who I worked with.
I architected the Laravel core and permission model, the Redis caching and invalidation strategy, the audit log, and the content sanitization, and worked on the Vue.js editor and workflow screens. The stack ran in Docker.
How it works
The main building blocks, from the screen people use to the data underneath.
Architected modular Laravel core with Vue.js frontend, multi-level Redis content caching, and automated audit logs tracking every content modification.
- 01
Vue.js editor and workflow
WYSIWYG editing, review queues per role, and a publishing panel that shows where each article sits in the chain.
- 02
Laravel modular core
Articles, publications, business units and roles as separate modules, with publishing done in a single database transaction.
- 03
Redis multi-level cache
Article pages and feeds cached with tags, so a publish can flush exactly the article and its category.
- 04
Audit log
Every create, update, publish and role change written alongside the content change in the same transaction.
Key choices and trade-offs
Every build involves trade-offs. These are the important ones and what each one cost.
| Decision | Trade-off |
|---|---|
| Tag-based cache invalidation. | Cache keys need careful tagging, but publishing flushes only what changed instead of the whole site. |
| Audit writes inside the publish transaction. | Slightly longer transactions, but there is never a publish without its audit record. |
| Sanitize on save, not on render. | Stored content is already clean, so every renderer is safe by default. |
Under the hood
Implementation details for technical readers, with a code sample.
- Nested permission hierarchies across business units.
- Surgical cache invalidation on publish with a 96.4% cache hit ratio.
- A full audit trail of content and role changes.
// Hierarchical Content Publishing Workflow with Automatic Cache Flush
public function publishArticle(Article $article, User $editor) {
DB::transaction(function () use ($article, $editor) {
$article->update([
'status' => 'published',
'published_at' => now(),
'approved_by' => $editor->id
]);
Redis::del("cache:articles:{$article->slug}");
Redis::tag(['articles_feed', "category:{$article->category_id}"])->flush();
AuditLog::create(['action' => 'PUBLISH', 'target' => $article->id, 'user_id' => $editor->id]);
});
}Problems solved
What got in the way, and how each problem was fixed.
- 01
Complex nested permission hierarchies across multiple corporate business units.
A role and unit hierarchy evaluated in policies, so a user can be an editor in one unit and an author in another.
- 02
Dynamic page asset caching with immediate surgical cache invalidation on publish.
Tagged Redis caching with targeted flushes for the article and its category inside the publish transaction.
- 03
Preventing XSS and SQL injection across custom WYSIWYG markup rendering.
Server-side sanitization of WYSIWYG markup and parameterized queries throughout, which kept the security audit at 100% pass.
Security, speed and growth
How data is protected, and how the system stays fast as usage grows.
Security
Role policies on every action, sanitized rich text to prevent XSS, parameterized queries against SQL injection, and an immutable audit log.
Speed & growth
Pages render in under 60ms thanks to multi-level Redis caching, while targeted invalidation keeps published content fresh.
Quality and releases
How changes were tested and shipped safely.
Policy tests cover each role in each unit. Sanitization is tested against known XSS payloads, and publish flows are tested to confirm the right cache tags are flushed.
Tech stack
The tools and technologies used, for recruiters and technical reviewers.
Results
Measured outcomes recorded for this project.
| Metric | Result |
|---|---|
| Page Render Time | <60 ms |
| Cache Hit Ratio | 96.4 % |
| Security Audit | 100 % pass |
Questions
Plain answers first, then the detail a technical reviewer would ask about.
Common questions
- Who is a system like this for?
- Larger organisations where many people publish content and each change needs the right approval and a clear record.
- Can my team publish without a developer?
- Yes. Authors, editors and publishers each have their own steps and permissions, and publishing updates the live site instantly.
For your tech lead
- How do approvals work?
- Authors write drafts, editors review and approve, and publishers put them live. Each step is permission-checked and logged.
- How is content kept fast and fresh?
- Pages are cached in Redis with tags; publishing flushes only the affected article and category.
- How is rich text made safe?
- Markup is sanitized on save, so stored content cannot carry scripts.
Key takeaways
- •A publishing system for large teams: clear approval steps, fast pages and a full record of every change.
- •Built with Laravel, Vue.js, MySQL, Redis, RBAC, Docker.