EnoughStack

The EnoughStack handbook

One workspace.
Learn the whole stack.

A practical tutorial for the business behind your software. Set up your workspace, reach customers, organize the work and share what ships.

Download guide
20 step-by-step lessonsAbout 3 hours with practiceBeginner to developer

This guide describes the current build. Look for the notes in each lesson: real delivery depends on configured providers, and some tools still use simulations. Use your own workspace for business data.

Follow the lessons in order, or jump to what you need.

Getting started3 min

Find your way around

Choose the demo or your own workspace, then get familiar with the tools you will use.

Access: Everyone can read this guide. Available tools depend on your workspace access.

Start with the right workspace

  1. Explore the demo

    Open the dashboard without signing in to browse Framecast, the sample business. Its customers, campaigns, boards and revenue illustrate how the tools fit together. Demo data is shared; use your own workspace for business records.

  2. Create your account

    When sign-in is enabled, choose Sign in. Use Continue with Google or the email and password form, depending on the options offered. First time here? Choose Create one. A new account becomes the owner of its own workspace; an invited email can join the inviting workspace.

  3. Check the workspace card

    The name near the top of the sidebar tells you which workspace you are using. After signing in, open that card to switch workspaces or choose New workspace. Each workspace has separate data, teammates and API keys.

Know where things live

  • Overview: arrange widgets for the work and numbers you check most.
  • Customers: consult the shared customer directory. Email Contacts is a separate audience list.
  • Email: manage contacts, segments, templates and campaigns.
  • Inbox: review customer conversations, store replies and add team notes.
  • Feedback: collect requests, organize a public roadmap and publish a changelog.
  • Tasks: organize boards and cards. Its page addresses use /app/kanban.
  • Revenue: inspect Stripe revenue, payments and subscriptions.
  • Settings and Developers: configure the workspace, team, API keys and webhook records.

Your checkpoint

You can identify the current workspace and find Email, Feedback and Tasks in the sidebar. On a small screen, open the menu to see the same navigation.

Getting started5 min

Set up your workspace and team

Give the workspace your identity, choose a time zone and grant teammates the access they need.

Access: Settings Edit for project and branding changes; workspace owner or admin for team management.

Make it yours

  1. Set your project details

    Open Settings → General. Under Project, enter the Project name, Website and Time zone, then Save changes. This stores a workspace preference. Check each scheduling screen's displayed time zone separately: campaign schedules have their own zone, changelog scheduling uses your browser's zone, and revenue reporting boundaries use UTC.

  2. Add workspace branding

    In Branding, upload your logo or use an HTTPS image URL, choose a brand color and save. Changing the workspace name, logo or color updates the matching feedback portal setting too. You can still customize the portal in Feedback → Settings → Portal. Email → Brand has its own settings.

  3. Invite a teammate

    Open Settings → Team and choose Invite teammate. Enter their name and email, choose Admin or Member, and review feature access before saving. Use a preset such as Support, Marketing, Developer or Finance as a starting point.

  4. Review access

    No access prevents opening a feature, View lets a teammate read it, and Edit allows changes. Owners and admins have full access. Members get the feature permissions you grant; a task board can also impose its own membership and role rules.

A practical starting point

For a support teammate, grant Inbox Edit and Feedback Edit, plus Customers View for context. Grant Email View if they should inspect campaigns. Keep Revenue and Developers access restricted to the people who need them. A disabled control or View only badge usually reflects access, rather than a broken feature.

Your checkpoint

Your project details are saved, and you can explain what each invited teammate may read or change.

Getting started3 min

Build a useful Overview

Turn the dashboard into a small daily checklist with the widgets that matter to you.

Access: Overview View to browse; Overview Edit to change the shared dashboard layout.

Arrange your dashboard

  1. Enter edit mode

    Open Overview and choose Edit. Widgets become movable. Drag them into your preferred order; with a keyboard, focus a widget's move handle, press Space and use the arrow keys.

  2. Choose the right detail

    Use a widget's size control to cycle through its supported sizes. Bigger widgets can show more detail. The minus button removes a widget from the layout.

  3. Add what you need

    Choose Add widget and browse the live previews. Start with revenue, open conversations and your upcoming work, using the choices available to your role. Add a widget, then choose Done.

  4. Check the save status

    Layout changes save automatically through the API. Wait for the save indicator; if an error appears, check your connection before leaving. Reset restores the default layout, so use it when you want to start over.

Read the numbers in context

The revenue period selector changes historical figures across the dashboard. It supports 30 days, 90 days, 6 months and 12 months. Current MRR, active subscriptions and ARPU describe today, while trend charts cover the selected period. Only data you have permission to see is included. A Stripe first read can show progress before its figures are ready.

Your checkpoint

You have a short, readable dashboard, and its layout shows a successful save.

Customers & email4 min

Understand the customer directory

Read customer context and know where to manage email contacts and feedback users.

Access: Customers: View or Edit to open the directory. This screen has no editing controls.

Read a customer's context

Customers gives you a workspace directory with a row for each stored customer. In the demo, these are the people behind the sample business. Use it to understand who someone is before reading their conversation or reviewing their feedback.

  1. Open Customers in the sidebar

    Find the customer's name and email address in the Customer column. The page is a table; rows do not open a separate customer profile.

  2. Read company, plan and paying amount

    Company and Plan give business context. Paying shows the stored monthly recurring amount, or a dash when there is no amount.

  3. Check email status and recent activity

    Email list shows the stored contact status. Location and Last seen add context for a support response.

Use the right screen for changes

  • Email → Contacts manages your email audience, including contact fields, tags and subscription status.
  • Feedback → Users manages portal users, their participation and feedback email preferences.
  • Inbox conversations show their associated customer's details in a side panel on wide screens.
  • Revenue → Payments and Subscriptions show the Stripe records read by the revenue connection.

Your checkpoint

You can explain the Customer, Paying and Email list columns, and choose Contacts or Feedback Users when you need to manage those records.

Customers & email9 min

Build an audience with contacts, tags and segments

Add a contact, store useful details and create an audience that updates itself.

Access: Email view access to browse; Email edit access to add or change data.

Add your first launch subscriber

A list holds contacts. Fields hold details such as a first name or company; tags are labels you apply; segments select contacts through saved rules. A new workspace starts with an empty Audience list. Demo workspaces already contain sample contacts and lists.

  1. Choose a list

    Open Email → Contacts and choose Audience, or the list you want to use, in the List selector. Your contact, fields, tags and segments belong to this list.

  2. Add a contact

    Choose Add contact. Use an address you control, enter a first name, choose Subscribed, and add the tag launch. Choose Add contact again to save. Subscribed contacts can receive campaigns; other statuses are excluded.

  3. Store an extra detail

    Switch to Fields. Enter Company under New field, choose Text and select Add field. Return to Contacts, open your contact, enter the company and choose Save fields. Number and Date fields are also available.

Make a reusable launch audience

  1. Create a segment

    Open Segments, choose the same list and select Create segment. Name it Launch subscribers. Set the condition to Tag → has tag → launch, then choose Save segment. The live preview shows matching subscribed contacts.

  2. Check membership

    Return to Contacts and filter by your segment. Add or remove launch on a contact to change membership automatically. New subscribers, Engaged and Disengaged are ready-made starting points for other segments.

  • Condition groups support All of these, Any of these and None of these. Multiple groups must all match. Rules can use fields, dates, source, tags, other segments and email activity.
  • Search and filter contacts by status, tag or segment. Export all matches downloads the filtered audience as CSV; selecting rows enables bulk tag, unsubscribe and delete actions.

Your checkpoint

Your list contains your subscribed contact with the launch tag, and Launch subscribers includes that contact.

Customers & email9 min

Create a branded email template

Set the email brand kit, customize a reusable design and preview personal details.

Access: Email View to browse the gallery; Email Edit for rendered template previews, branding and template changes.

Set the brand that appears in emails

Email → Brand controls the business details and design used in emails. This is separate from the dashboard branding in workspace Settings. Use it before creating your launch update so the reusable design starts with the right identity.

  1. Fill in Business

    Enter Company or project name, Website and your Postal address. Add a Footer note explaining why people receive your emails. The company details appear in the footer; use your actual sender details before a real send.

  2. Choose a style

    Set the primary colour, secondary colours, heading and body fonts, and social links. Logo takes an HTTPS address of an image you host. Choose Save brand and wait for Saved.

Save a launch update design

  1. Choose a starting point

    Open Templates → Create template → Start from a design. Browse Branded or Inspirational and copy a suitable design. Blank design starts an empty block layout; Code your own starts an HTML document.

  2. Customize your copy

    Rename it Launch update. Edit the heading, paragraph and button blocks. Set the button link to your actual release page. Use the block controls to move, duplicate or remove content. In Design, choose Use my brand styles to apply your saved colours and fonts.

  3. Check the result

    Wait for the save indicator, then open Preview & test. Compare Desktop and Mobile, and HTML and Plain text. A template preview uses sample personal details. Choose Use in a campaign to create a draft from the saved design.

  • Templates are reusable starting points. Campaigns keep their own content, so later template edits or deletion do not rewrite campaigns already created from them.
  • The built-in designs can be copied; edit your own copy. Yours contains your saved templates. A campaign can also be saved as a template from its actions menu.
  • Coded designs need the required system merge tags, including {{UnsubscribeURL}}. Keep the supplied footer and replace all placeholder links and text.

A greeting with a fallback

Hi {{FirstName|there}},
Our latest update is ready.

Your checkpoint

Launch update is saved under Yours, has a real destination link and looks readable in both desktop and mobile previews.

Customers & email12 min

Write, review and send a campaign

Follow Setup → Content → Send and understand the resulting report.

Access: Email edit access to create, test, schedule or send; Email view access to read campaigns and reports.

Prepare the launch update

  1. Complete Setup

    Choose Create campaign. Enter Campaign name, From name, From address, Subject and Preview text. Choose your list, then Tags → launch or Segments → Launch subscribers. Everyone and Advanced filter are also available. Check the subscribed-contact count and tracking switches in Advanced settings. Choose Save & next.

  2. Write Content

    Choose your Launch update design, or Start blank. Replace placeholder copy and links, add a greeting such as {{FirstName|there}}, and adjust Design if needed. Content autosaves; wait for All changes saved. Change design replaces existing content after confirmation.

  3. Preview and test

    Open Preview & test. Check Desktop, Mobile and Plain text. Search Preview as a contact to inspect your subscriber's actual values. Under Send a test, enter up to ten comma-separated addresses, optionally add a Personal message, and choose Send test. Then choose Save & next.

Review before choosing Send

  1. Resolve checks

    Review the audience, sender, subject and content. Follow Fix for blocking errors such as no subject, no recipients, empty content or a button without a link. Review warnings about placeholder links, missing preview text, unknown merge tags and the postal address too.

  2. Check delivery mode

    Read the delivery panel. Sends are simulated in this build means no messages leave the application, including tests. Real delivery requires an administrator to configure Resend or SMTP. A Resend sender domain must be verified; sender errors block sending.

  3. Choose timing

    Select Send immediately or At a specific time. For scheduling, set a future Date and time and the intended Time zone. Choose All at once or Gradual sending with a duration. Select Send to the displayed count or Schedule, then confirm Send now or Schedule only when ready.

Read the result and reuse your work

Sending and sent campaigns open their report. Review sent, opened, clicked, unsubscribed, bounced and complained counts, the first 48 hours of opens and clicks, link performance and recent activity. Simulated engagement appears over time; real engagement depends on tracking and provider events.

Only drafts can be edited. Use Unschedule before a scheduled send starts; use Duplicate to reuse a sent campaign. Failed campaigns offer Back to draft. Selecting several tags or segments includes contacts matching any selected item, while sending still excludes contacts who are not subscribed.

Your checkpoint

You can explain exactly who would receive the campaign, which delivery mode is active and when it would send. Your reviewed draft is ready, or your intentionally sent campaign has a report.

Customers & email4 min

Understand what Email Automations supports

Inspect the available automation cards without mistaking them for live customer journeys.

Access: Email view access to inspect cards; Email edit access to change their enabled state.

Read the automation cards

  1. Inspect the examples

    Open Email → Automations. The predefined cards are Welcome series, Trial ending, Failed payment recovery and Win-back. Each shows its description, When trigger, Emails, In progress and Open rate.

  2. Understand the switch

    With edit access, you can switch a card between Enabled and Disabled. This saves that setting. New workspaces start with these cards switched off; the public demo contains sample settings and metrics.

Use an explicit campaign for today's work

For a launch follow-up, create a saved segment such as contacts with the launch tag who were added in the last seven days. Create a campaign, review its live audience count and schedule it using the ordinary Setup → Content → Send workflow. That is one campaign, not an automatically repeating series.

For a recurring or event-triggered journey, arrange the scheduling and trigger handling outside this screen. The Automations tab currently helps you inspect the intended examples and record their enabled state; it is not evidence of delivery. Use campaign reports and the configured delivery provider to verify sends that you explicitly initiate.

Your checkpoint

You know that an Enabled automation card records a setting and does not prove that any automated email is running.

Product & support7 min

Work through the support inbox

Read conversations, practice replies and internal notes, and preview the messenger.

Access: Inbox: View to read; Edit to add messages, change conversation status or save messenger settings.

Choose a conversation

Inbox has Conversations and Messenger tabs. Conversations is a shared queue with Open, Snoozed and Closed filters. Select a conversation to read its subject, channel and message history. On a phone, use the back arrow to return to the list; on wide screens, a customer panel shows company, plan, paying amount, email status and tags.

With Edit access, viewing an unread thread marks it read and updates the sidebar's unread count. A priority flag can appear in the list, but this screen does not offer a priority editor.

Reply, leave context and resolve

  1. Write a reply

    Choose Reply, type your response and select Send. Ctrl+Enter or ⌘+Enter also submits. Replying to a snoozed or closed conversation puts it back into Open.

  2. Add an internal note

    Choose Note, describe the next step for a teammate and select Add note. The note is marked as team-only and does not change the conversation's status.

  3. Manage the queue

    Choose Snooze to move an open conversation to Snoozed, Close to move it to Closed, or Reopen to bring it back. Snooze is a status change here; there is no wake-up time picker.

Preview your messenger appearance

  1. Open Messenger

    Set Team name, Greeting and Expected reply time. Choose an accent Color and Bottom left or Bottom right Position while checking the live preview.

  2. Save the appearance

    Select Save changes and wait for All changes saved. These settings are persisted, but they do not install a functioning messenger.

Your checkpoint

You have added a sample team note, closed and reopened a conversation, and saved a messenger preview without expecting customer delivery.

Product & support8 min

Create and share a project board

Start a release board, choose who can see it and give teammates the right role.

Access: Tasks edit access to create boards. Board admins manage sharing; workspace owners and admins can manage every board.

Create a board for your next release

The sidebar calls this module Tasks. A board contains lists, and each list contains cards. Use one board for a project such as a release, then move cards between lists as the work progresses.

  1. Create the board

    Open Tasks → Boards → Create board. Name it Launch release, choose a colour and select Kanban under Start from. This gives you To do, Doing and Done lists with Bug, Feature and Improvement labels.

  2. Choose visibility and members

    Review Members, set Who can see it to Private for a project restricted to board members, and choose Create board. You become its admin. The default is Workspace visibility with active teammates selected, so review those choices before saving.

  3. Find it again

    Star the board to place it in Starred. The board tile shows open and overdue cards and the completed share. Other starting points include Sprint, Bug tracking, Content calendar and Blank.

Share with a teammate

  1. Choose a role

    Open the board's Share dialog, enter a teammate's email and select Member before choosing Share. Admin runs settings, members and sharing; Member works on lists, cards and comments; Observer can look but cannot change the board. Module-level edit access is also required for edits.

  2. Understand links

    Create link makes a join link for teammates in the same workspace, with Member or Observer access. Public visibility exposes a read-only board and its card details at the Public link without sign-in. Review the content before making it public. Disable link revokes the join link.

  • Workspace boards are visible to teammates with Tasks access; they need board membership to edit. Let teammates join on their own makes joining available for non-private boards.
  • Only workspace owners and admins can invite someone new to the workspace from Share. An invite record is created, but automatic workspace invite email delivery is not implemented; share sign-in instructions separately.
  • Make template saves a board as a reusable starting point. Copy board includes its cards. Close board is reversible through the Closed section; Delete board permanently removes its lists, cards and comments.
  • A board must retain an admin. Promote another person before its only admin leaves or changes role.

Your checkpoint

Launch release has three lists, the intended visibility and at least one admin. You can distinguish a teammate join link from a public read-only link.

Product & support12 min

Manage cards, automate lists and review progress

Turn a release task into assigned, dated work and follow it across board, table and calendar views.

Access: Tasks edit access and a Member or Admin board role to change work. Workspace owners and admins manage shared statuses.

Make a release task actionable

  1. Add and open a card

    In Launch release, choose Add a card in To do and enter Write the launch email. Choose Add card or press Enter. Open it to add a description. Quick-add also recognizes existing #label and @name references.

  2. Assign and date it

    Choose Members to assign yourself, Labels to add Feature, and Dates to set a due date. Choose Checklist, give it a title and add items such as Write copy, Check mobile preview and Review recipients. Checklist items can have their own assignee and due date.

  3. Add context

    Attachment adds a link, not an uploaded file. Estimate stores planned hours; Log time records hours, date and an optional note. Add a comment for your team, use Watch to track the card in Watched by, or Copy link to return directly to it.

Move work and simplify repeated changes

  1. Move the card

    Drag it to Doing, or use Move inside the card. In the list's actions menu, When a card enters… can set a status, add an assignee or labels, set a due date, complete or archive arriving cards. A due-date rule applies only when the card has no due date.

  2. Complete the work

    Finish the checklist, then move the card to the built-in Done list, whose arrival rule completes it. Mark card complete also sets the shared Done status but leaves the card in its current list. Choosing a non-done status reopens it.

  • Set list limit… shows a red counter when exceeded; it does not prevent adding cards. List actions also sort, copy, collapse, move or archive cards.
  • Lists describe placement; workspace-wide statuses describe state, so a card in Doing can be Blocked. Menu → Custom fields adds text, number, date, dropdown or checkbox details; fields can appear on card fronts.

Review across your projects

Switch Board, Table or Calendar to inspect the same cards. Filter by title, members, labels, status, due date and completion. On the board, f opens Filter, x clears it, q toggles your assigned cards and w opens Menu.

My tasks combines accessible boards by Assigned to, Created by, Watched by or Everyone's and groups work by due date. Show completed reveals finished work. Reports shows created/completed cards, cycle time from creation to completion, logged hours and workload. Menu → Archived items lets you recover archived work.

Your checkpoint

Your card has an assignee, due date and checklist; appears in My tasks; and becomes complete through the Done list's rule or the completion control.

Product & support12 min

Collect and moderate customer feedback

Create a feedback board, capture a useful request, and review what customers submit.

Access: Feedback Edit to manage posts and moderation. Workspace owner or admin to configure boards and settings.

Give requests a home

A feedback board groups one kind of customer request. Start with Feature requests; add Bugs or Integrations when separate submission forms would help.

  1. Create a board

    Open Settings → Boards → New board. Enter a name, address, description and icon, then Create board. Public boards appear on the portal; Unlisted hides a board from the home page while keeping its link usable; Private limits it to team members.

  2. Shape the form

    Open the board and choose Submission form. Set the heading, title and details labels, placeholders and button text. Decide whether to Require details, Accept new submissions and Allow comments, then Save changes. Closing submissions keeps existing posts available for voting.

  3. Choose the default

    Use the board's action menu → Set as default. New dashboard posts use it unless you choose another board. The default board cannot be deleted until another takes its place.

Capture a request with enough context

  1. Create an example post

    Open Posts → New post. Choose the board and status; title it “Export filtered results as CSV”. Add Markdown details explaining the problem, workaround and expected result. Optionally add tags, an owner and a monthly ETA; choose whether the ETA is public. Select Create post.

  2. Record a customer's request

    Enable Submit on behalf of a customer, pick a user or enter their email, and confirm permission to add their details. They become the author. From Voters you can also add a customer vote with a private note.

  3. Keep discussion clear

    In Comments, choose Public for a customer reply or Internal note for team discussion. Activity shows changes. Search or filter Posts by board, status, tag, owner or date. Export CSV preserves the current list filters.

Review submissions

Settings → Moderation controls post/comment approval, team and identified-user auto-approval, moderated words and anonymous actions. A moderated word can hold a submission even when approval is off. Global required details still apply when a board does not require them.

  • In Moderation, switch between Posts, Comments and Spam. Select Approve to publish, Reject… to keep content out and optionally explain why, Mark spam to flag it, or Not spam to restore it from the spam queue.
  • Use j and k to move through the queue and a to approve. Rejection messages can be emailed; delivery depends on the configured mail provider.

Your checkpoint

Your board has a clear submission form, your example post has useful context, and you can explain which submissions enter moderation.

Product & support10 min

Turn feedback into a roadmap

Triage requests, combine duplicates, and show customers what is being considered or built.

Access: Feedback Edit to triage and move posts. Workspace owner or admin to configure statuses.

Define the stages

Default statuses are Open, Under review, Planned, In progress, Complete and Closed. Their types are Initial for new requests, Active for consideration/work, Complete for shipped work in reports, and Closed for requests you will not do.

  1. Choose visible columns

    In Settings → Statuses, edit a status or Add status to set its name, colour and type. Enable Show on roadmap for each desired column. Reorder statuses within their type using the arrows.

  2. Decide when discussion ends

    Locked prevents customers from voting or commenting on posts in that status. Check the setting before using a status for active work. Only an Initial status can become the default for new requests.

Triage before you commit

  1. Find requests worth investigating

    Compare Trending, Top, New, Old, Status changed and MRR sorts. Filter by board, status, tag or owner. Voters shows customer context and private notes. MRR comes from customers matched by email; missing revenue does not imply low value.

  2. Combine duplicates

    Open the less complete duplicate, select Post actions → Merge into…, search for the main post and confirm the target. Votes, comments and followers move to it, and the old public link redirects. Use Unmerge if the requests should remain separate.

  3. Assign the next action

    Set an owner, tags and an optional ETA. Move “Export filtered results as CSV” to Under review while clarifying the workflow. In Change status, add a public comment and select Notify voters to explain the decision.

Maintain the public plan

  1. Move work forward

    Drag the request to Planned or In progress. Drag within a column to order it, or use the card's menu → Move to a status. New post starts a request in that column's stage.

  2. Check the customer's view

    Enable Roadmap in Settings → Portal, then View portal. A private board or hidden/unapproved post stays out of the public roadmap, even if its status has a column.

Review the signal

  • Users shows posts, votes, comments and available customer plan/MRR. Segments group people with rules over profile, activity and attributes.
  • Reports compares created/completed requests, status/board/tag totals, top posts, stale requests and revenue behind feedback.

Your checkpoint

Your example request appears in the intended roadmap column, duplicates point to one main post, and you know when a status change sends email.

Product & support16 min

Launch your portal and website widget

Configure public access, share useful links, embed the widget, and connect your own subdomain.

Access: Workspace owner or admin for portal, widget and domain settings. Feedback Edit for invites; Email Edit too for campaign drafts.

Configure the customer experience

  1. Set visibility and appearance

    Open Settings → Portal. Set a title and description, choose Public, Unlisted or Restricted, then Save changes. Configure the theme, accent colour and hosted HTTPS logo URL. Turn Boards, Roadmap and Changelog on as needed. The permanent portal address uses your workspace ID and survives workspace renaming.

  2. Restrict access when needed

    Restricted requires sign-in. Add Allowed email domains and/or Invited addresses. With both lists empty, anyone who signs in can enter. Unlisted hides the portal from search engines; public portals have a separate indexing switch.

  3. Try it as a customer

    Use View portal, open a board and select Submit feedback. The form suggests similar requests so visitors can vote on an existing idea. Sign in uses Continue with email and a six-digit code valid for ten minutes; demo mode shows the code on the page. Anonymous participation depends on moderation settings.

Bring people to the portal

Share collects the portal QR code, network sharing, board and submission links, roadmap, changelog and RSS links. Submission links can prefill a title. Embed it offers the widget, inline frames, a feedback button, README badge and email signature. Channel tags such as ?ref=docs help the 30-day visit and post report show where people came from.

  • Invite people emails up to 100 addresses at a time. On a restricted portal, owners/admins can also select Let them into the portal to add invited addresses.
  • Email your customers creates an Email campaign draft. Review recipients and content in the Email editor; the draft sends only when you send it there.

Install and identify through the widget

  1. Choose how it opens

    In Settings → Widget, enable the widget. Choose Floating button, Custom selector or None, its left/right position, Sidebar or Popover, theme, sections and starting section. Add Allowed hosts if you want to limit which sites may embed the key, then Save changes.

  2. Use your installation snippet

    In Install, select HTML or React and copy the generated code into your site. HTML goes before the closing body tag. Open your site and test the launcher, voting and navigation. Rotating the widget key requires updating installed snippets.

  3. Identify signed-in customers

    Set the widget's user before loading it, or call identify after it loads. Supply a stable user ID and optionally email, name, company and attributes. In Moderation → Identity verification, enable the required hash and have your server compute lowercase HMAC-SHA256 of that ID with the identity secret; pass it as hash. Keep the secret on your server. This widget identification is available; a separate SSO integration is not included.

Open an installed widget from your own button

window.EnoughStackFeedback.open("feedback");
// Other sections: "roadmap" and "changelog"
window.EnoughStackFeedback.close();

Use a custom subdomain

  1. Connect the address

    In Portal settings → Custom domain, enter a subdomain such as feedback.example.com without https:// or a path, then Connect domain. Copy every displayed CNAME/TXT record exactly into your DNS provider and select Verify domain.

  2. Wait for Active

    The portal activates after ownership, hosting DNS and HTTPS checks pass. While the settings page is visible, pending checks repeat every 30 seconds. Active makes the portal available at /, roadmap at /roadmap and changelog at /changelog on your subdomain. The permanent address remains available.

Your checkpoint

A customer can reach the intended portal sections, your website opens the widget, and you have tested the visibility rules you chose.

Product & support12 min

Publish updates and close the feedback loop

Write a release note, link the requests it solves, publish it, and inspect reader engagement.

Access: Feedback Edit to author and publish. Workspace owner or admin for labels and portal/email settings; Email Edit for campaign drafts.

Write an update customers can use

  1. Start an entry

    Select Changelog → New entry. Title it “Export your filtered results as CSV” and write Markdown explaining the change, who benefits and how to try it. Drafts autosave; Preview renders the content.

  2. Add publication details

    Choose labels and an author in Publish settings. Summary & cover adds an introduction and hosted cover image. Pin to top keeps it first in the portal/widget. Owners/admins manage labels in Settings → Labels.

  3. Link customer requests

    In Linked posts, find the requests this release solves. Publication shows “Shipped in” on their pages. Set each request to Complete separately to update the roadmap and completion reports.

Review, then publish

  1. Check notifications

    Choose Notify subscribers and Send me a test email to review it. Real delivery requires a mail provider; default sends are simulated. Settings → Emails controls customer delivery and the default voter notification choice.

  2. Publish or schedule

    Select Publish and confirm, or More publish options → Schedule… to choose a future date/time in your displayed timezone. Scheduled entries go live automatically. Cancel schedule returns to draft; published entries can be unpublished or archived.

  3. Inspect the live page

    Enable Changelog in Portal settings and View public page. Check the content, linked posts and reactions. Share the published link, or Email it to customers to create a separate campaign draft for your Email list.

Grow and inspect the audience

  • Subscribe to updates requires guest email confirmation; signed-in visitors manage their subscription in the portal. RSS lets readers follow updates in a feed reader.
  • Subscribers lists Confirmed, Pending and Unsubscribed people. Data → Import subscribers adds up to 500 addresses as confirmed, for people who already requested updates.
  • Performance shows views, reactions and emails sent. Reports includes changelog engagement. Settings → Emails → Outbox lists Sent, Skipped and Failed with reasons. Simulated Sent does not prove inbox delivery.

Your checkpoint

Your release note is published or scheduled, links to the request it resolves, and has a deliberate subscriber notification choice.

Connections & operations9 min

Connect Stripe and understand revenue

Connect a restricted Stripe key, follow the first read and interpret the time range.

Access: Revenue: View to read figures; Edit to connect or disconnect Stripe, including from Settings.

Connect your account

The demo's revenue is sample data. A new workspace starts without revenue until Stripe is connected. The connection reads your Stripe account for analytics; EnoughStack has no charging, refunding or plan-changing controls.

  1. Create a restricted Stripe key

    In Stripe's API keys area, create a restricted key. Give Subscriptions, Charges and Customers Read access. Products Read supplies plan names; Events Read enables reading only changes. Those last two permissions are optional. Leave other permissions at None.

  2. Paste the restricted key

    Open Revenue → Overview, enter the rk_live_… or rk_test_… key in Restricted key and choose Connect. Full secret keys beginning sk_ and publishable keys beginning pk_ are rejected. Use a test key if you want test-account figures.

  3. Wait for the first account read

    The page shows subscriptions and payments read so far. Large accounts can take several minutes. Once complete, check the Live mode or Test mode badge and the figures-as-of time.

Read the figures in context

  • Choose 30 days, 90 days, 6 months or 12 months. The selection stays in the page URL, so you can reload or share that view.
  • Monthly recurring revenue, active subscriptions and revenue per account describe the current subscription position. Net new MRR, net revenue, churn and period charts use the selected horizon.
  • MRR movements shows what new and ended subscriptions added or removed. Net revenue is payments received minus refunds.
  • Use Payment health, Churn risk, Trials, Plan mix and Top customers to investigate changes, then inspect the recent records under Payments or Subscriptions.

Understand freshness and disconnecting

The first read includes the past year's relevant subscriptions and charges. Later page requests normally trigger a refresh about every five minutes; Events permission allows incremental reads, with periodic whole-account checks. While refreshing, the page serves the last completed figures. If a refresh fails, read the error and the last successful timestamp before interpreting the numbers.

Disconnect removes the saved key and the copied Stripe account from EnoughStack. It does not cancel Stripe subscriptions or change the Stripe account. The demo returns to its sample figures; an empty workspace returns to its disconnected state.

Your checkpoint

You can identify the connection's mode, latest successful read and time horizon, and distinguish current MRR from revenue earned during the selected period.

Connections & operations10 min

Use API keys and explore webhooks

Make your first API requests and understand the current webhook delivery limit.

Access: Developers: View to inspect; Edit to create or revoke keys and change or test endpoints. Public API calls use the key's scopes.

Create a key for your integration

  1. Choose Create key

    Give the key a recognizable Name. Read only permits reads; Read and write also permits supported mutations. Copy the full key immediately, then select I've saved it. The full key is shown once; only its hash is retained.

  2. Prepare your environment

    Load the key into ENOUGHSTACK_API_KEY from your secret manager. Set ENOUGHSTACK_API_BASE to the API host followed by /api/public/v1, for example http://127.0.0.1:8000/api/public/v1 locally. Keep the key in server-side code.

Read your lists first

Run this request and copy a list ID from data. Use that real ID for subsequent contact requests.

Get lists using your environment variables

curl "$ENOUGHSTACK_API_BASE/lists" \
  -H "Authorization: Bearer $ENOUGHSTACK_API_KEY"

Create or update a contact

With a write-capable key, replace the list ID below and use a contact who consented to your email list. Public API fields use snake_case. Posting the same email again updates the contact and merges tags; status defaults to subscribed, so supply the intended status explicitly.

  • Paged responses contain data and paging.next. Pass a non-null cursor back as starting_after; contact pages allow limit up to 100.
  • Errors have an error object with code and message. Check invalid_key or unauthenticated for 401, insufficient_scope for 403, and validation_error for 422.
  • Reference and interactive docs cover contacts, campaign reports, automation enrollment, task cards, feedback and changelog endpoints. Interactive writes change workspace data.

Upsert a contact in your resolved list

ENOUGHSTACK_LIST_ID="REPLACE_WITH_AN_ID_FROM_GET_LISTS"

curl -X POST "$ENOUGHSTACK_API_BASE/lists/$ENOUGHSTACK_LIST_ID/contacts" \
  -H "Authorization: Bearer $ENOUGHSTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email_address":"maya@example.com","fields":{"FirstName":"Maya"},"tags":["customer"],"status":"subscribed"}'

Explore the webhook configuration

  1. Add endpoint

    Give it a Name and HTTPS URL, select event groups and optionally exclude contact events caused by imports or API requests. Leave Enabled selected and save.

  2. Inspect a test event

    Use Send test event from the endpoint's menu, then expand its payload in Recent deliveries. The menu also offers Edit, View signing secret, Enable/Disable and Delete.

Your checkpoint

You have read the real list IDs with a key, understand how scopes and revocation work, and know that recorded webhook tests do not reach an external receiver.

Connections & operations8 min

Practice a complete release workflow

Connect the tools with a worked example: take an export request from customer conversation to release announcement.

Access: Edit access to the tools you change, plus owner/admin access for new feedback settings.

Example: ship CSV export

  1. Capture the request

    A customer asks for CSV export in a conversation. Review their context in Inbox and add an internal note with the use case. Search Feedback for an existing request before creating a new post titled Export results as CSV. Add the customer vote when appropriate.

  2. Decide what comes next

    Review votes, comments and customer context. Give the post an owner and a clear status, such as Planned. If the status is configured for the roadmap, the request appears in that roadmap column. Use a post status update with Notify voters when you want to communicate the decision.

  3. Create the delivery work

    In Tasks, create a card with the same title. Put the feedback post URL in its description or link attachments. Assign an owner, add a due date and a checklist: implement export, test a sample file, write the release note. This link is manual; a feedback post does not automatically create a task.

  4. Ship and record completion

    Move the card through your board. Mark it complete when the work is shipped, then update the feedback post to your completed status. Task completion and feedback status are separate actions; changing one does not synchronize the other.

  5. Tell customers

    Create a changelog entry explaining the benefit and how to use CSV export. Link the feedback post, preview the entry and publish. If customer email is enabled with a real provider, eligible subscribers can receive the first-publication email. Check the outbox for the actual result.

  6. Prepare the broader announcement

    Open the published changelog entry's Share… menu and choose Email it to customers, or start a campaign in Email. The sharing action requires Email Edit and Feedback Edit. Review the audience, sender, content and checks before sending. Creating a campaign does not send it. Changelog subscribers and Email contacts are separate audiences; avoid sending two announcements to the same people unintentionally.

Your weekly routine

  • Daily: check Inbox, new feedback and My tasks.
  • Before a release: review blockers, complete cards and write a changelog draft.
  • After a release: check notification results and campaign reports; follow up on the original request.
  • Weekly: review Revenue for trends and Tasks reports for workload. Treat simulated reports as practice data.

Your checkpoint

You can follow one request through a feedback post, linked task, published changelog and reviewed email draft.

Connections & operations7 min

Run EnoughStack locally

For developers and administrators: prepare the database, start both apps and enable the integrations you need.

Access: Access to the source checkout, local tools and your own service credentials.

Prepare and start

  1. Install the prerequisites

    Use Python 3.11+, pnpm, and a supported Node release: 22.22.2+, 24.15.0+, or 26+. Work from the repository root.

  2. Configure shared settings

    Copy .env.example to .env only if you do not already have one. Set ENOUGHSTACK_SESSION_SECRET to a long random value. Current API startup requires configured MySQL, including demo mode. Create a database and user with permission to create and update the application's tables, and set MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER and MYSQL_PASSWORD. These API-only settings can live in api/.env.

  3. Choose database TLS

    MYSQL_SSL=required is the default. Supply MYSQL_SSL_CA when you need to verify the database server certificate. For a database confined to your local machine that has no TLS, explicitly use MYSQL_SSL=disabled in your local configuration.

  4. Install and run

    Run make install, then make dev. Open http://localhost:3000 for the web app, /app for the dashboard and http://127.0.0.1:8000/api/docs for the internal API docs. Stop the development command with Ctrl+C when finished.

From the repository root, after configuring .env

make install
make dev

# Run either app separately
make api
make web

# Validate changes
make test
make check

# Refresh generated types after API schema changes
make types

Enable real integrations deliberately

  • Accounts: configure FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN and FIREBASE_PROJECT_ID, and enable the sign-in methods you offer in Firebase. Restart the apps after environment changes.
  • Stripe: set ENOUGHSTACK_ENCRYPTION_KEY before connecting a real restricted key. Preserve this secret; changing it prevents existing stored Stripe keys from being decrypted.
  • Email: configure Resend or SMTP. Set ENOUGHSTACK_PUBLIC_API_URL for email links, ENOUGHSTACK_PUBLIC_WEB_URL for portal links and ENOUGHSTACK_NOTIFY_FROM for feedback notification emails.
  • Custom feedback domains: the API needs ENOUGHSTACK_VERCEL_TOKEN and ENOUGHSTACK_VERCEL_PROJECT_ID, plus ENOUGHSTACK_VERCEL_TEAM_ID for a team project. These are server credentials.
  • Hosting: use HTTPS, secure session cookies and the transport key configuration described in the repository README. Public API bearer requests use their own API surface. Never put server secrets into NEXT_PUBLIC_* variables.

Your checkpoint

Both development servers are running, the dashboard loads, and you know which providers your installation actually uses.

Connections & operations4 min

Troubleshooting and key terms

Resolve the common surprises and learn the distinctions that keep your workflows predictable.

Access: Everyone; some fixes require a workspace owner or installation administrator.

When something does not behave as expected

  • A feature is missing or a control is disabled: check your workspace, feature access and task board role. Owners/admins manage feedback settings and the team.
  • Your workspace is empty: new signed-in workspaces start with an empty audience and curated templates. The sample business belongs to the separate demo workspace.
  • A campaign says it sent but no email arrives: check whether MAIL_PROVIDER is simulated, and inspect the sender/provider checks. Simulated events are not proof of delivery.
  • A contact import did not read your file: Import contacts is a simulation in this build. Use Add contact or the public API for real records.
  • A reply never reaches a customer: Inbox saves conversation replies but has no outbound mailbox. Its Messenger installation example is not a working live-chat script.
  • A feedback post is missing publicly: review its board visibility, hidden/deleted/merged flags, approval state and portal restrictions. A merged post redirects to the retained post.
  • A status change sent no email: roadmap dragging changes status without notifying voters. Use the post status-update dialog and its notification option, then inspect the feedback email outbox.
  • A custom domain is pending: copy every required DNS record, use Verify domain and allow DNS and HTTPS provisioning to finish. Keep using the permanent portal address. A failed disconnect needs Finish disconnecting.
  • Stripe is still loading: allow the first read to finish and review the connection status. Check Read permissions for Subscriptions, Charges and Customers. Historical trends use the selected time range; current MRR is today's figure.
  • A webhook test says 200 but your endpoint saw nothing: developer webhook deliveries are recorded simulations; this build does not POST to your endpoint.
  • The API will not start: configure MySQL and ENOUGHSTACK_SESSION_SECRET. A database outage can also return 503. Check server logs and connectivity; repeatedly clicking a write action is not a database fix.

A few useful distinctions

  • Customer: a record in the shared directory. Email contact: a subscriber or other record in an audience list. Portal user: an identity participating in feedback. These are separate records; matching emails can provide customer context.
  • Tag: a label you assign. Segment: saved conditions evaluated against current records. List: the audience containing Email contacts.
  • Campaign: an email send and its report. Template: a reusable design. Brand kit: default email identity and design choices.
  • Feedback board: a place for requests and votes. Task board: a place for delivery work. A task list is a board column; a task status describes the card and can differ from that column.
  • Public comment: visible to portal visitors when approved. Internal note: team context. Changelog subscriber: a reader who signed up for release emails, with confirmation required for public sign-ups.
  • MRR: normalized monthly recurring subscription value. ARPU: current MRR divided by the number of distinct paying customer accounts. Net revenue: charge amounts after refunds in the selected reporting period; it is not your bank balance.

Your checkpoint

You can distinguish a permissions issue, a provider configuration issue and a feature that is still simulated.