devsnack
Documentation

Coachly documentation

Run it, point it at your own accounts, ship it under your own brand. Written against version 1.1.0 of the download you get on CodeCanyon.

$40 on CodeCanyon
On this page
01

Overview

Run a complete coaching institute — courses, mock tests, batches, analytics, and an AI tutoring layer — on one modern stack. Two Flutter apps + one Next.js project (storefront + admin + backend).

Coachly is a coaching & test-prep LMS sold as source code — a coaching institute runs its whole test-prep business (courses, mock-test series, batches, analytics) on one modern codebase, with four AI features (question generation, answer explanations, adaptive practice, and a doubt-solving tutor) built in. It ships as a 4-surface bundle delivered in 3 apps:

  • Student app — Flutter (Android + iOS)
  • Instructor app — Flutter (Android + iOS)
  • One Next.js app — the public storefront (/) + the institute admin panel (/admin) + the sole backend (/api/v1)

The wedge over Laravel incumbents: four AI features (not a bolt-on chatbot) with a mandatory instructor review queue, on a modern TypeScript + Flutter stack. Portable: deploy on Docker, Railway, or Vercel, backed by any Postgres (Neon is easiest).

Note
What you buy — and what you don’t. This purchase is the Coachly source code only. The third-party services it can integrate with — a PostgreSQL host (e.g. Neon), Stripe, Razorpay, Bunny Stream, UploadThing, Resend, Firebase/FCM, and OpenAI or Gemini — as well as any hosting, domain, and app-store developer accounts, are not included in the price. You create your own accounts with those providers and pay their fees directly according to your own usage and their pricing. Coachly runs fully keyless for local development and demos, so you only sign up for a service when you switch on the feature that needs it.
02

What’s included

  • Full source for all three apps — 2 Flutter apps + 1 Next.js project (with the sole backend)
  • Drizzle ORM schema (21 tables) + 7 SQL migrations
  • The “Academic Precision” design system — shared Tailwind theme + Flutter ThemeData
  • Branding pipeline — SVG logo mark → web favicon + Android/iOS launcher icons
  • Rich demo seed — demo institute + accounts, an “IELTS Full Mock Series” (4 tests / ~54 questions with cached explanations), graded attempts, 2 batches + announcements, and pending AI review-queue drafts
  • Buyer documentation (this guide) with a step-by-step setup + deploy walkthrough (Docker / Railway / Vercel / Neon)
  • In-process backend test suites (verify:auth / verify:assessment / verify:ai / verify:seed) + Flutter unit/widget tests
  • 6 months Item Support (per Envato Item Support Policy) + free future updates
03

Features

Student app (Flutter)

  • Email/password auth (JWT Bearer); dashboard with enrolled courses + performance rank
  • Course list & player — secure Bunny Stream video (signed playback) + notes/PDFs + lesson-progress tracking
  • Mock-test series — timed exams with a countdown + auto-submit, instant scoring, results + solutions
  • AI answer explanations, adaptive / weak-area practice, and an AI doubt-solving chatbot (a tutor, never a cheat engine)
  • Batches & announcements, bookmarks (“Saved”), paywall/enrolment (free enrol + Stripe/Razorpay checkout)

Instructor app (Flutter)

  • Dashboard, course builder + lesson editor, test & question-bank builder
  • AI question generator + review queue — approve/reject drafts before students ever see them
  • Batch management, student performance, earnings, settings

Institute admin (web, /admin)

  • Dashboard (enrollments, revenue, KPIs); manage courses/lessons, test series/questions, batches, students, instructors, categories, coupons, payments
  • The AI review queue, reports/analytics, and settings (institute branding, payment/AI provider config, course owner + revenue-share)

Public storefront (web, /)

  • SSR/SEO catalog, course + batch detail, checkout/enrol, blog, about/contact, sitemap + OpenGraph metadata (canonical origin = APP_URL)

Backend (Next.js /api/v1)

  • REST: auth, courses/tests/attempts, batches, me/*, bookmarks, rank/leaderboard, AI (explanations, weak-areas, doubt-chat)
  • The instructor surface /api/v1/instructor/** (courses/tests/questions/AI drafts/batches/earnings), webhooks/{stripe,razorpay}, uploadthing, and an Inngest scaffold
04

Architecture

coachly/
coachly/
  apps/
    web/             Next.js 16 — storefront (/) + admin (/admin) + backend (/api/v1)
      app/(storefront)/   public SSR storefront + blog
      app/admin/          institute admin panel
      app/api/            the backend (/api/v1, webhooks, uploadthing, inngest)
    student-app/     Flutter (Riverpod 2 + GoRouter + Dio + freezed)
    instructor-app/  Flutter (same stack)
  packages/
    db/              Drizzle schema + migrations (@coachly/db)
    core/            services + Zod DTOs + AI + payments + seed (@coachly/core)
  brand/             SVG logo sources (single source of truth)
  docs/              PRD.md, DESIGN.md, DEPLOYMENT.md, codecanyon/
Web + backend
Next.js 16 (App Router), React, TypeScript, Tailwind
Data
Drizzle ORM + PostgreSQL (Neon or any Postgres)
Auth
Auth.js v5 session (web /admin) + JWT Bearer (mobile, /api/v1)
Payments
Stripe + Razorpay (+ keyless stub gateway)
Media
UploadThing (files/images) · Bunny Stream (signed video)
Email / Push
Resend · FCM (firebase-admin, real server send)
AI
OpenAI + Gemini (server-side only, via AI_PROVIDER)
Mobile
Flutter 3.x / Dart 3, Riverpod 2.x, GoRouter, Dio, freezed, flutter_secure_storage, flutter_svg

Design invariants: a single backend/DB, thin JWT mobile clients on the /api/v1 contract, all business logic in @coachly/core, money as integer cents server-side, and AI keys server-side only.

05

API contract (/api/v1)

The Flutter apps talk to the backend over one versioned REST contract. Every response is a { data } | { error } JSON envelope (apps/web/lib/http.ts).

Obtain a token from POST /api/v1/auth/login and send it as Authorization: Bearer <token>. Public catalog reads need no token; me/** routes need a student token; instructor/** routes need an instructor token; webhooks are called by the payment provider, not the apps. Path params are shown as [id].

Auth and profile

MethodEndpointPurpose
POST
/api/v1/auth/login
Email + password → signed JWT (public)
GET
/api/v1/auth/me
Current user from the token
GET
/api/v1/me/enrollments
My enrolled courses
GET
/api/v1/me/batches
My batches
GET
/api/v1/me/announcements
Announcements across my batches
GET
/api/v1/me/rank
My performance rank
GET · POST · DELETE
/api/v1/me/bookmarks
List / add / remove bookmarks

Catalog, enrolment and learning

MethodEndpointPurpose
GET
/api/v1/courses
Published course catalog (public)
GET
/api/v1/courses/[id]
Course detail (public)
POST
/api/v1/courses/[id]/quote
Price quote (applies a coupon)
POST
/api/v1/courses/[id]/enroll
Enrol / checkout
GET
/api/v1/courses/[id]/progress
My progress in a course
GET
/api/v1/lessons/[id]/playback
Signed video playback URL (enrolment-checked)
POST · DELETE
/api/v1/lessons/[id]/complete
Mark / unmark a lesson complete

Tests, attempts and practice

MethodEndpointPurpose
GET
/api/v1/tests
Test series / tests (published)
GET
/api/v1/tests/[id]
Test detail
POST
/api/v1/tests/[id]/attempts
Start an attempt
GET
/api/v1/attempts/[id]
Attempt state
POST
/api/v1/attempts/[id]/submit
Submit + auto-grade
GET
/api/v1/leaderboard
Test / series leaderboard
GET
/api/v1/practice/weak-areas
Weak-area analysis → targeted practice
GET
/api/v1/questions/[id]/explanation
AI answer explanation (grounded)
POST
/api/v1/doubt-chat
Doubt-solving tutor chat
GET
/api/v1/batches/[id]/announcements
Announcements for a batch

Instructor (instructor token)

MethodEndpointPurpose
GET · POST
/api/v1/instructor/courses
List / create courses
GET · PATCH
/api/v1/instructor/courses/[id]
Get / update a course
GET · POST
/api/v1/instructor/courses/[id]/lessons
List / add lessons
PATCH · DELETE
/api/v1/instructor/lessons/[lessonId]
Update / delete a lesson
GET · POST
/api/v1/instructor/test-series
List / create test series
GET · PATCH
/api/v1/instructor/test-series/[id]
Get / update a series
GET · POST
/api/v1/instructor/test-series/[id]/tests
List / add tests to a series
GET · PATCH · DELETE
/api/v1/instructor/tests/[id]
Get / update / delete a test
GET · POST
/api/v1/instructor/tests/[id]/questions
List / add questions
GET
/api/v1/instructor/tests/[id]/stats
Per-test analytics
GET · PATCH · DELETE
/api/v1/instructor/questions/[id]
Get / update / delete a question
POST
/api/v1/instructor/ai/generate
Generate question drafts → review queue
GET
/api/v1/instructor/ai/drafts
Pending AI drafts (review queue)
POST
/api/v1/instructor/ai/drafts/[id]/approve
Approve a draft → live question bank
POST
/api/v1/instructor/ai/drafts/[id]/reject
Reject a draft (discarded)
GET · POST
/api/v1/instructor/batches
List / create batches
GET · PATCH · DELETE
/api/v1/instructor/batches/[id]
Get / update / delete a batch
POST · DELETE
/api/v1/instructor/batches/[id]/members
Add / remove batch members
GET · POST
/api/v1/instructor/batches/[id]/announcements
List / post announcements
GET
/api/v1/instructor/students
My students
GET
/api/v1/instructor/earnings
Earnings summary

Webhooks and health

MethodEndpointPurpose
POST
/api/v1/webhooks/stripe
Stripe payment confirmation (provider → server)
POST
/api/v1/webhooks/razorpay
Razorpay payment confirmation (provider → server)
GET
/api/v1/health
Health / readiness probe
Note
This table mirrors the route handlers under apps/web/app/api/v1/**. Full request/response shapes are the Zod DTOs in @coachly/core. Auth.js also mounts /api/auth/* (web sessions), and /api/uploadthing + /api/inngest serve uploads and background jobs.
06

Database setup

  1. 01
    Create a Postgres database (Neon free tier recommended).
  2. 02
    Copy .env.example apps/web/.env.local and set DATABASE_URL + AUTH_SECRET.
  3. 03
    Apply migrations: npm run db:migrate
  4. 04
    Load the demo data: npm run db:seed (institute, demo accounts, mock-test series, batches, graded attempts, AI drafts).
Note
The seeded demo accounts work immediately — no manual admin promotion needed. For a clean production DB, run db:migrate and skip db:seed. Deployment steps are in the Deployment section below.
07

Database backup and restore

Coachly stores everything in one PostgreSQL database, so a backup is a single logical dump. This uses the standard Postgres client tools — pg_dump and pg_restore (or psql) — no Coachly-specific script needed.

Install them with brew install libpq (macOS) or apt-get install postgresql-client (Debian/Ubuntu). Run every command against your direct (non-pooled) connection string — not the pooler.

  1. 01

    Create a backup

    A compressed, portable dump file you own:

    terminal
    # custom-format dump (recommended — compact, restores selectively):
    pg_dump "$DATABASE_URL" -Fc -f coachly-backup.dump
    
    # or a plain-SQL dump you can open and read:
    pg_dump "$DATABASE_URL" --no-owner --no-privileges -f coachly-backup.sql
  2. 02

    Restore

    Into a fresh, empty database (or over the existing one; --clean drops objects first):

    terminal
    # restore a custom-format (.dump) backup:
    pg_restore --clean --if-exists --no-owner -d "$DATABASE_URL" coachly-backup.dump
    
    # restore a plain-SQL (.sql) backup:
    psql "$DATABASE_URL" -f coachly-backup.sql
Tip
Keep dumps off-site and automate them with a scheduled job (e.g. a nightly cron running the pg_dump above). Restore into an empty database when migrating hosts. On Neon you also get point-in-time restore and branching from the dashboard, but a pg_dump file is a portable, provider-independent backup you keep yourself. Take a fresh backup before running npm run db:migrate on a production database.
08

Environment variables

All config is server-side. Copy .env.example apps/web/.env.local — the web runtime, drizzle-kit, db:migrate and db:seed all read that one file. Everything is optional except where noted: the app boots keyless and each integration degrades gracefully until its key is set. Server env only — never ship AI / payment / DB keys to the Flutter apps.

VariableUsed forRequired?
DATABASE_URL
Postgres connection (Neon, Supabase, Railway, RDS, self-hosted)
For every DB-backed feature
AUTH_SECRET
Signs / verifies web sessions + mobile JWTs
For login (web + mobile)
APP_URL
Canonical origin for SEO / OpenGraph metadata
Recommended (default coachly.devsnack.dev)
AI_PROVIDER
Selects the AI backend: openai | gemini
Default openai
OPENAI_API_KEY · OPENAI_MODEL
OpenAI features (model is an optional override)
For AI via OpenAI
GEMINI_API_KEY · GEMINI_MODEL
Gemini features (model is an optional override)
For AI via Gemini
STRIPE_SECRET_KEY · STRIPE_WEBHOOK_SECRET
Stripe checkout + webhook signature verify
Optional (stub gateway runs keyless)
RAZORPAY_KEY_ID · RAZORPAY_KEY_SECRET · RAZORPAY_WEBHOOK_SECRET
Razorpay checkout + webhook verify
Optional
UPLOADTHING_TOKEN
Notes / PDF + image uploads
Optional (paste-URL still works)
BUNNY_STREAM_LIBRARY_ID · BUNNY_STREAM_TOKEN_KEY · BUNNY_STREAM_API_KEY
Signed secure video (playback URL signing + management API)
Optional (embeds still work)
RESEND_API_KEY · RESEND_FROM
Enrolment / receipt / results email
Optional (no-ops when unset)
FCM_PROJECT_ID · FCM_CLIENT_EMAIL · FCM_PRIVATE_KEY
Push notifications (Firebase service account)
Optional
INNGEST_EVENT_KEY · INNGEST_SIGNING_KEY
Background jobs (bulk AI gen, grading, rollups)
Optional (inline fallback)
Note
This mirrors .env.example and the validated schema in apps/web/lib/env.ts. FCM_PRIVATE_KEY is a PEM — escape its newlines as \n in the value (the push helper unescapes them at read time). See Deployment → Production hurdles for DATABASE_URL pooling and SSL.
09

Deployment

The Next.js app (storefront + admin + backend) is one deployable. Any Node host + any Postgres works; three common paths:

Docker

A multi-stage Dockerfile ships at the repo root (Node 20, next start). It includes packages/db so migrations/seed can run from the image.

terminal
docker build -t coachly .
docker run -p 3000:3000 --env-file apps/web/.env.local coachly
# one-time (against your DB):
docker run --env-file apps/web/.env.local coachly npm run db:migrate
# optional demo data:
docker run --env-file apps/web/.env.local coachly npm run db:seed

Railway

New project → deploy from repo (the root Dockerfile is detected) → add a PostgreSQL plugin → set the env vars (at minimum DATABASE_URL, AUTH_SECRET, APP_URL). Run npm run db:migrate once from the service shell (or a one-off command).

Vercel

Import the repo; set the build to the @coachly/web workspace (npm run build) and add the env vars. Migrations run manually, not in the Vercel build — run npm run db:migrate against your database once (locally or via a one-off), then redeploy.

Postgres (Neon)

Create a Neon project and use its connection string as DATABASE_URL (the pooled URL is fine for the app). Run npm run db:migrate to create the schema; optionally npm run db:seed for demo data.

Warning
Set APP_URL to your public origin so OpenGraph/canonical URLs resolve correctly. Payment redirect URLs derive from the live request origin automatically.

Production hurdles — connection pooling, SSL and limits

Coachly uses the postgres.js driver (packages/db/src/client.ts), which works with any Postgres. Three things trip up most first deploys:

  • Connection pooling. Serverless / edge hosts (Vercel, Lambda) open a fresh connection per invocation and quickly exhaust a small Postgres max_connections. Point DATABASE_URL at your provider’s transaction-pooling endpoint — Neon’s pooled host (the -pooler hostname), Supabase’s pooler (port 6543), or PgBouncer in transaction mode. The client already sets prepare: false, exactly what transaction poolers require (no server-side prepared statements), so the pooled URL works out of the box. On a long-lived Node host (Docker / Railway) the direct URL is fine.
  • Run migrations on the direct connection. Always run npm run db:migrate against the non-pooled connection string — the migrator uses a single connection (max: 1) and DDL should not go through a transaction pooler. On Neon: migrate on the plain host, run the app on the -pooler host. To cap the app’s own pool size, add max to the postgres(...) options in packages/db/src/client.ts.
  • SSL for PostgreSQL. Managed hosts require TLS. Append ?sslmode=require to DATABASE_URL (postgres.js reads it — it is already in .env.example). If your host uses a self-signed or private CA and you hit self-signed certificate in certificate chain, use ?sslmode=no-verify (still encrypted, skips CA verification) or supply the CA. A self-hosted Postgres without TLS: omit sslmode — not recommended for production.
Warning
FCM private key. FCM_PRIVATE_KEY is a multi-line PEM. In a single-line env value, escape the newlines as \n — the push helper (packages/core/src/notify/push.ts) unescapes them at read time.
10

Optional integrations

Everything runs keyless for dev/demo and gracefully no-ops until you add keys. Each integration below is a separate third-party account you provide and pay for yourself — none is bundled with this item, and each has its own pricing (most offer a free tier to start).

IntegrationUnlocksEnv varsKeyless behavior
Stripe
Card checkout + refunds
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
stub gateway enrols inline
Razorpay
India/MENA checkout + refunds
RAZORPAY_KEY_ID/KEY_SECRET/WEBHOOK_SECRET
stub gateway enrols inline
UploadThing
Notes/PDF + image uploads
UPLOADTHING_TOKEN
upload returns 501; paste-URL still works
Bunny Stream
Tokenized secure video
BUNNY_STREAM_LIBRARY_ID/TOKEN_KEY/API_KEY
video_not_configured; embeds still work
Resend
Enrolment/receipt/results email
RESEND_API_KEY (+ RESEND_FROM)
logs a no-op
FCM
Push notifications
FCM_PROJECT_ID/CLIENT_EMAIL/PRIVATE_KEY
returns sent: 0
OpenAI / Gemini
The 4 AI features
AI_PROVIDER + OPENAI_API_KEY/GEMINI_API_KEY
safe mock (ai_not_configured)
11

AI provider setup

Pick a provider via AI_PROVIDER=openai|gemini and set OPENAI_API_KEY or GEMINI_API_KEY (optional model overrides OPENAI_MODEL / GEMINI_MODEL). These are server env only — never in a Flutter build. The four features live behind /api/v1 and call @coachly/core/src/ai/*.

How AI questions reach students — the review queue

AI-generated questions are never auto-published. Every draft passes through a mandatory human review before any student can see it:

  1. 01

    Draft generated

    An instructor asks the assistant to draft questions from a topic or uploaded notes.
  2. 02

    Held in the review queue

    Every draft is stored in aiQuestionDrafts students never see it.
  3. 03

    A human reviews

    An instructor opens each draft and checks the question and its correct answer.
  4. 04

    Approve or reject

    • Approve → joins the live question bank
    • Reject → discarded, never published
  5. 05

    Student sees

    Only approved questions ever appear in a test.

Guardrails (server-enforced):

  • AI-generated questions never auto-publish — they land in aiQuestionDrafts for instructor review; approval is the only path into the live question bank.
  • The doubt chatbot and explanations refuse to serve answers while the student has an in-progress attempt on that test (ai/guards.ts).
  • System prompts are centralized and server-enforced (not client-editable).
Warning
Add a rate cap before going public. There is no per-user AI rate-limiter yet (roadmap) — wire a daily cap around the AI routes before exposing real keys, so a user can’t run up your OpenAI/Gemini bill.
12

Payments setup

  1. 01

    Stripe

    Set STRIPE_SECRET_KEY; add a webhook at https://<deploy>/api/v1/webhooks/stripe and paste STRIPE_WEBHOOK_SECRET. Checkout returns a hosted-redirect URL; the webhook confirms and creates the enrolment.
  2. 02

    Razorpay

    Set RAZORPAY_KEY_ID + RAZORPAY_KEY_SECRET (+ RAZORPAY_WEBHOOK_SECRET); uses Payment Links (hosted redirect) + /api/v1/webhooks/razorpay.
  3. 03

    Keyless stub

    With no gateway keys, enrolment completes inline (great for demo/dev). Free (or fully coupon-discounted) courses always enrol without payment.

Refunds are real: an admin refund issues the Stripe/Razorpay refund. Money is integer cents, computed server-side only.

13

Secure video, uploads and push

Secure video (Bunny Stream)

Set BUNNY_STREAM_LIBRARY_ID + BUNNY_STREAM_TOKEN_KEY (+ BUNNY_STREAM_API_KEY). Upload videos in the Bunny dashboard, then paste the playback URL into a lesson’s Video URL (admin → course → lesson). The backend mints a short-lived signed playback URL and checks the student’s enrolment before handing it out (media/video.ts). Free fallback: paste a YouTube / Vimeo / HLS embed URL (no signing needed).

Uploads (UploadThing)

Set UPLOADTHING_TOKEN to enable in-app upload buttons on the admin course/lesson/resource forms (with a paste-URL fallback that keeps working keyless). Notes/PDFs + images, staff-gated.

Push (FCM)

Set FCM_PROJECT_ID + FCM_CLIENT_EMAIL + FCM_PRIVATE_KEY (service-account creds; the private key is \n-escaped). The backend actually sends via firebase-admin (notify/push.ts); the apps only hold FCM tokens.

Note
Background jobs: Inngest is a scaffold (the inngest package is intentionally not a dependency yet; jobs run inline). Wiring it at go-live via INNGEST_* is the documented path (roadmap).
14

Branding and customization

  • Logo (source of truth): brand/*.svg. Edit, regenerate the PNGs per brand/README.md (macOS qlmanage + sips), then run dart run flutter_launcher_icons in each Flutter app. The web favicon apps/web/app/icon.svg is served directly.
  • Theme tokens: web — apps/web/tailwind.config.ts + apps/web/app/globals.css; Flutter — apps/*/lib/ theme. Keep values identical (one system). Institute branding is also editable at runtime in admin Settings.
  • App name + ids: each pubspec.yaml, android/app/build.gradle.kts (applicationId + namespace), AndroidManifest.xml (android:label), ios/Runner/Info.plist (CFBundleDisplayName), and the pbxproj PRODUCT_BUNDLE_IDENTIFIER. Defaults: com.devsnack.coachly.student / com.devsnack.coachly.instructor, names “Coachly” / “Coachly Instructor”.
  • Multi-language / RTL: not wired today (roadmap, PRD §12).
Tip
Prefer a no-code walkthrough? Your institute name, tagline, description, logo and contact email are editable at runtime in Admin → Settings — no rebuild needed. The Institute Owner’s Guide (admin-guide.html) → Branding shows exactly where each field lives, with a screenshot and step-by-step instructions for uploading your logo.
15

Production checklist

  1. 01
    Branding: edit brand/*.svg → regenerate → dart run flutter_launcher_icons in each app.
  2. 02
    Theme tokens: tailwind.config.ts + globals.css + Flutter theme.
  3. 03
    App names + ids in the Flutter pubspecs + native config.
  4. 04
    Provision Postgres (Neon recommended).
  5. 05
    npm installnpm run db:migrate (→ optional npm run db:seed).
  6. 06
    Set env: DATABASE_URL, AUTH_SECRET, APP_URL + any integrations.
  7. 07
    Deploy the web (Docker / Railway / Vercel — see the Deployment section).
  8. 08
    Add Stripe/Razorpay webhooks; set Bunny / UploadThing / FCM keys.
  9. 09
    Add a per-user AI rate cap before exposing AI publicly.
  10. 10
    Build Flutter releases with --dart-define=API_BASE_URL=<your api>.
  11. 11
    Change the demo passwords.
16

Changelog

Every version published so far. Updates are free for the life of the item.

v1.1.0 · Sep 2026
Student self sign-up (app, web and API), in-app purchase history, and web sign-in now returns students to checkout instead of the admin panel. No database migration required.
v1.0.0 · Jul 2026
Initial release.

Version 1.0.0 · July 7, 2026

  • Initial release: student + instructor Flutter apps, Next.js storefront + admin + backend, four AI features with the instructor review queue, Stripe + Razorpay, Bunny video, UploadThing, Resend, FCM, and a rich demo seed.
17

Support and licensing

Preferred contact method: email is the primary channel. For quick questions you can also message WhatsApp.

Preferred channel
Email — devsnack26@gmail.com (WhatsApp for quick questions)
Expected response time
Within 24–48 hours on business days (Mon–Fri), often the same day
Support hours
Monday–Friday, excluding public holidays (Indochina Time, UTC+7)
Support window
6 months of Item Support bundled per the Envato Item Support Policy
Note
Support covers installation, configuration, and help with defects in the item as delivered. It does not include setting up your third-party accounts beyond the walkthroughs in this guide, custom development, or hosting. You supply your own Postgres / Stripe / Razorpay / Bunny / UploadThing / Resend / FCM / AI accounts — we provide the setup walkthroughs, not accounts or hosting. Coachly ships as source code; hosting and domains are yours.

What support covers

  • Six months of support from purchase, extendable at checkout
  • Support covers bugs in the template and questions about how it is put together
  • It does not cover custom feature work, third-party API changes or store review outcomes
  • The Regular licence covers one free end product. Charging users for the app itself needs the Extended licence