Learn how to plan and build a web app for marketing agencies to manage campaigns, assets, and client approvals, with roles, workflows, and audit-ready history.

Before you sketch screens or pick a tech stack, get clear on the core problem: marketing campaigns and approvals are scattered across email, chat, and shared drives. A campaign web app should pull briefs, assets, feedback, and sign-off into one place so everyone can see what’s next—without chasing threads.
Most agency approval workflows involve four groups, each with different needs:
Email-based approvals create predictable problems: missed deadlines because no one sees the latest request, unclear feedback like “make it pop” without specifics, multiple versions floating around, and rework cycles caused by late or conflicting input.
Define measurable outcomes so you can judge whether the product works:
For v1, focus on the smallest set that keeps campaigns and approvals together:
Save nice-to-haves for later: advanced reporting, deep integrations, automation rules, and custom approval paths.
Before you think about screens or tech, write down how work actually moves through your agency. A clear workflow turns “Where is this at?” into a predictable set of steps your app can enforce, automate, and report on.
Most campaign approval apps can be described with a small set of building blocks:
Document the relationships: a campaign contains projects; projects contain tasks; tasks produce assets; assets go through approvals.
A simple, agency-friendly flow is:
Draft → Internal review → Client review → Approved
Make each state mean something operationally. For example, “Internal review” might require a creative lead and account manager sign-off before a client ever sees it.
Decide what feedback looks like in your product:
The key is tying feedback to an asset version, so you don’t argue about which file the client reviewed.
Common slowdowns: waiting for reviewers, unclear next steps, and repeated setup. Automation that helps most:
Real approvals aren’t always clean. Plan for:
If you can describe these rules in plain language, you’re ready to turn them into screens and data models.
Great UX for a campaign app starts with a simple information hierarchy that mirrors how agencies already think: Client → Campaign → Deliverables (assets). If users can always answer “Where am I?” and “What happens next?”, approvals move faster and fewer things slip through.
Use the client as the top-level anchor, then show campaigns underneath, and finally the deliverables (ads, emails, landing pages, social posts). Keep the same structure in navigation, breadcrumbs, and search so people don’t have to relearn the app on every screen.
A practical rule: every deliverable should always show its client, campaign, due date, status, and owner at a glance.
Dashboard: The agency home base. Focus on what needs attention today: upcoming due dates, items waiting for internal review, and items waiting on client approval.
Campaign timeline: A calendar-like or phase-based view that makes dependencies obvious (e.g., “Copy approved” before “Design final”). Keep it readable—people should understand progress in seconds.
Asset review view: Where time is won or lost. Make the preview large, comments easy to find, and the next action clear.
Inbox: A single place for “things I need to respond to” (new feedback, approval requests, mentions). This reduces ping-pong across email and chat.
Quick filters should answer common agency queries:
The primary call to action should be obvious: Approve / Request changes. Keep it fixed in the review view (sticky footer/header) so clients don’t hunt for it after scrolling comments.
Clients often review between meetings. Prioritize mobile readability: a clean preview, large buttons, and short forms for feedback. If one tap can open the asset and another can approve it, you’ll see faster turnaround times.
A campaign approval app lives or dies by trust: clients must feel confident they’re only seeing what they should, and your team needs clear boundaries so work doesn’t get overwritten or approved by the wrong person.
Most agencies can cover most needs with five roles:
Instead of global permissions only, define actions per object type (campaign, deliverable, asset, comment). Typical actions include view, comment, upload, approve, edit, and delete.
A practical default is “least privilege”: contributors can upload and edit their own assets, but deleting or changing campaign settings is restricted to account managers/admins.
Clients should only see their campaigns, assets, and discussions. Avoid shared “client folders” that accidentally expose other accounts. This is easiest when every campaign is tied to a client account, and access checks are enforced consistently across pages, downloads, and notifications.
Support two approval modes per deliverable:
Offer share links for convenience, but keep them private by default: time-limited tokens, optional password, and the ability to revoke.
A good rule: sharing should never bypass the client boundary—it should only grant access to items that user could normally see.
A client-approval feature lives or dies by clarity. If your team and your clients can’t tell what’s waiting on whom, approvals stall, and “approved” becomes debatable.
Start with a small set of states that everyone recognizes:
Avoid adding a new status for every edge case. If you need more nuance, use tags (e.g., “legal review”) rather than exploding the workflow.
Treat each upload as a new immutable version. Don’t replace files in place—create v1, v2, v3… tied to the same asset.
This supports clean conversations (“Please update v3”) and prevents accidental loss. In your UI, make the current version obvious, while still allowing reviewers to open prior versions for comparison.
Free-form comments alone are messy. Add structure:
If you support timecodes (video) or page/region pins (PDF/images), feedback becomes dramatically more actionable.
When someone approves, record:
After approval, define the rules: typically lock edits on the approved version, but allow creating a minor revision as a new version (which resets status to In Review). This keeps approvals defensible without blocking legitimate last-minute tweaks.
Creative approvals live or die on how easily people can access the right file at the right time. Asset management is where many campaign apps quietly become frustrating—slow downloads, confusing file names, and endless “which version is final?” loops.
A clean pattern is: object storage for the actual files (fast, scalable, inexpensive) and a database for metadata (searchable and structured).
Your database should track things like: asset name, type, campaign, current version, who uploaded it, timestamps, approval state, and preview URLs. The storage layer holds the binary file and optionally derived items like thumbnails.
Aim for a small set that covers most workflows:
Be explicit in the UI about what’s uploadable vs. link-only. That reduces failed uploads and support tickets.
Previews make review faster and more client-friendly. Generate:
This lets stakeholders skim a dashboard of deliverables without pulling down full-resolution files.
Define file limits early (max size, max count per campaign, supported extensions). Validate both file type and content (don’t trust extensions). If you work with enterprise clients or accept large files, consider virus/malware scanning as part of the upload pipeline.
Approvals often need traceability. Decide what “delete” means:
Pair this with retention policies (e.g., keep assets for 12–24 months after campaign end) so storage costs don’t grow without a plan.
A campaign app with client approvals doesn’t need exotic infrastructure. It needs clear boundaries: a friendly interface for humans, an API that enforces rules, storage for files and data, and background workers to handle time-based work like reminders.
Start with what your team can build and operate confidently. If you already know React + Node, or Rails, or Django, that’s usually the right choice for v1. Hosting preferences matter too: if you want “push to deploy” simplicity, pick a platform that supports your stack well and makes logs, scaling, and secrets straightforward.
If you want to move faster without committing to a heavy build-from-scratch cycle, a vibe-coding platform like Koder.ai can help you prototype and iterate on the workflow (campaigns, assets, approvals, roles) through a chat-driven interface—then export the source code when you’re ready to take ownership.
Frontend (web app): Dashboards, campaign timelines, and review screens. It talks to the API and handles real-time UX details (loading states, upload progress, comment threads).
Backend API: The source of truth for business rules—who can approve, when an asset is locked, what state transitions are allowed. Keep it boring and predictable.
Database: Stores campaigns, tasks, approvals, comments, and audit events.
File storage + previewing: Store uploads in object storage (e.g., S3-compatible). Generate thumbnails/previews so clients can review without downloading huge files.
Background jobs: Anything that shouldn’t block the user: sending emails, generating previews, scheduled reminders, nightly reports.
For most agencies, a modular monolith is ideal: one backend codebase with well-separated modules (assets, approvals, notifications). You can still add services where they truly help (like a dedicated worker process for jobs) without splitting into many deploys.
Treat notifications as a first-class feature: in-app + email, with opt-outs and clear threading. A job queue (BullMQ, Sidekiq, Celery, etc.) lets you send reminders reliably, retry failures, and avoid slowing down uploads and approvals.
Plan three environments from the start:
If you want to dive deeper into the data side next, continue with /blog/data-model-and-database-design.
A clean data model is what keeps your campaign app feeling simple even as it grows. The goal is to make the common screens—campaign lists, asset queues, approval pages—fast and predictable, while still capturing the history you’ll need later.
Start with a small set of tables that match how agencies actually work:
Keep IDs consistent (UUIDs or numeric IDs—either is fine). The important part is that every child record (clients, campaigns, assets) carries an organization_id so you can enforce data isolation.
Statuses alone don’t explain what happened. Add tables like:
This makes audit trails and accountability straightforward without bloating your core tables.
Most screens filter by client, status, and due date. Add indexes such as:
Also consider a compound index for “what needs review now,” e.g. (organization_id, status, updated_at).
Treat your schema like product code: use migrations for every change. Seed a few campaign templates (default stages, sample statuses, standard approval steps) so new agencies can start quickly and your test environments have realistic data.
A client-approval app lives or dies on trust: clients need a simple login, and your team needs confidence that only the right people can see the right work. Start with the smallest set of auth features that still feel agency-ready, then expand.
If your users are mostly clients who log in occasionally, email + password is usually the smoothest path. For larger organizations (or enterprise clients), consider SSO (Google/Microsoft) so they can use existing company accounts. You can support both later—just avoid making SSO mandatory unless your audience expects it.
Invites should be fast, role-aware, and forgiving:
A good pattern is a magic link to set a password, so new users don’t have to remember anything up front.
Use secure session handling (short-lived access tokens, rotating refresh tokens, httpOnly cookies where possible). Add a standard password reset flow with expiring, single-use tokens and clear confirmation screens.
Authentication answers “who are you?” Authorization answers “what can you do?” Protect every endpoint with permission checks—especially for campaign assets, comments, and approvals. Don’t rely on hiding UI elements alone.
Keep audit-friendly logs (login attempts, invite acceptance, role changes, suspicious activity), but avoid storing secrets. Log identifiers, timestamps, IP/device hints, and outcomes—never raw passwords, full file contents, or private client notes.
Notifications are where campaign apps either feel helpful—or exhausting. The goal is simple: keep work moving without turning every comment into an inbox fire.
Start with a small, high-signal set of triggers and keep them consistent across email and in-app:
Make each notification include the “what” and the next action with a direct link to the right view (for example, an asset review page or the client inbox).
Different roles want different levels of detail. Give control at the user level:
Use smart defaults: clients typically want fewer emails than internal teams, and they usually only care about items awaiting their decision.
Batch similar updates (e.g., “3 new comments on Homepage Banner”) instead of sending one email per comment. Add guardrails:
A dedicated Approval Inbox page reduces back-and-forth by showing only what the client needs to do now: items “Waiting for you,” due dates, and a one-click path into the correct review screen. Keep it clean and accessible, and link to it from every review email (e.g., /approvals).
Email isn’t guaranteed. Store delivery status (sent, bounced, failed) and retry intelligently. If an email fails, surface it to admins in an activity view and fall back to in-app notifications so the workflow doesn’t stall quietly.
When clients approve creative, they’re not just clicking a button—they’re taking responsibility for a decision. Your app should make that decision trail easy to find, easy to understand, and hard to dispute later.
Implement an activity feed at two levels:
Keep entries readable for non-technical users with a consistent format: Who did what, when, and where. For example: “Jordan (Agency) uploaded Homepage Hero v3 — Dec 12, 2:14 PM” and “Sam (Client) approved Homepage Hero v3 — Dec 13, 9:03 AM.”
For accountability, store an audit trail for:
A practical rule: if an event affects deliverables, timing, or client sign-off, it belongs in the audit trail.
Audit events should generally be immutable. If something needs correction, record a new event (e.g., “Approval re-opened by Agency”) rather than rewriting history. Allow edits for display-only fields (like a typo in an asset title) but still log that the edit happened.
Support exporting a simple summary (PDF or CSV) for handoff: final approved versions, approval timestamps, key feedback, and links to assets. This is especially useful at project closeout or when a client changes teams.
Done well, this section reduces confusion, protects both parties, and makes your campaign management software feel trustworthy—not complicated.
Reporting and integrations can easily balloon the scope of a campaign approval app. The trick is to ship the smallest set that helps teams run work day-to-day, then expand based on real usage.
Begin with a simple reporting view (or dashboard widgets) that supports weekly status checks and daily triage:
Then add lightweight campaign health indicators that are easy to understand at a glance:
These don’t need perfect forecasting—just clear signals and consistent rules.
Integrations should reduce manual follow-up, not create new failure modes. Prioritize based on your users’ daily habits:
Even if you don’t ship a public API immediately, define a clear extension strategy:
Phase 1: core dashboards + pending/overdue lists.
Phase 2: health indicators + cycle-time trends.
Phase 3: 1–2 high-impact integrations (usually email + Slack).
Phase 4: webhooks and a partner-ready API.
If you’re considering packaging tiers for reporting and integrations, keep it simple and transparent (see /pricing). If you want a faster path to an initial MVP, Koder.ai can also be useful here: you can iterate on the approval workflow in “planning mode,” deploy a hosted build for feedback, and roll back via snapshots as you refine requirements.
For deeper workflow patterns, you can also link related guidance from /blog.
Start by defining the core problem: approvals and feedback are scattered across email/chat/files. Your v1 should centralize briefs, assets, feedback, and sign-off so every stakeholder can quickly answer:
Use measurable outcomes like approval turnaround time and revision cycles to keep scope grounded.
Design around four common groups:
If you optimize only for internal users, client adoption (and approval speed) usually suffers.
Pick a small set of success metrics tied to real workflow friction:
Instrument these early so you can validate improvements after launching v1.
A practical v1 includes:
Defer advanced reporting, deep integrations, automation rules, and custom approval paths until you see consistent usage.
Model the workflow with a few core objects:
Then define an approval lifecycle (e.g., Draft → Internal review → Client review → Approved) where each state has an operational meaning (who can move it, what must be true, what happens next).
Always tie feedback to an asset version to avoid “which file?” disputes. Good options include:
Structure reduces rework by making feedback actionable and accountable.
Keep navigation consistent around a simple hierarchy: Client → Campaign → Deliverables (assets). Key “daily driver” screens are:
Add filters that match real questions: client, due date, status, assignee.
Start simple with roles most agencies need:
Then define permissions per object (campaign, asset, comment, approval) such as view/comment/upload/approve/edit/delete. Use “least privilege,” and enforce checks on the backend—not just by hiding UI.
Treat each upload as a new, immutable version (v1, v2, v3…). Don’t overwrite files in place.
Record approval metadata:
Typically, lock the approved version but allow a new version to be created (which resets status back to In Review) when changes are needed.
A straightforward architecture is:
For v1, a modular monolith with a job worker is usually easier to ship and operate than many services.