Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# AsyncUp
<p align="center">
<img src="docs/public/logo.svg" alt="AsyncUp" width="96" height="96">
</p>

[![CI](https://github.com/asyncup-dev/asyncup/actions/workflows/ci.yml/badge.svg)](https://github.com/asyncup-dev/asyncup/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
<h1 align="center">AsyncUp</h1>

<p align="center">
<a href="https://github.com/asyncup-dev/asyncup/actions/workflows/ci.yml"><img src="https://github.com/asyncup-dev/asyncup/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
<a href="https://asyncup-dev.github.io/asyncup/"><img src="https://img.shields.io/badge/docs-asyncup--dev.github.io-15435f" alt="Docs"></a>
</p>

**Open-source, self-hosted async daily standups for Google Chat.**
No meetings, no SaaS, no telemetry — one small container you run yourself, forever free.
Expand Down
13 changes: 13 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ export default defineConfig({
title: 'AsyncUp',
description: 'Open-source, self-hosted async daily standups for Google Chat',
base: process.env.DOCS_BASE || '/',
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: `${process.env.DOCS_BASE || '/'}favicon.svg` }],
['meta', { name: 'theme-color', content: '#15435f' }],
['meta', { property: 'og:title', content: 'AsyncUp — async daily standups for Google Chat' }],
[
'meta',
{
property: 'og:description',
content: 'Open source and self-hosted: standup prompts, date threads, blocker tracking, AI summaries with your own key.',
},
],
],
themeConfig: {
logo: '/logo.svg',
search: {
provider: 'local',
},
Expand Down
4 changes: 4 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import DefaultTheme from 'vitepress/theme';
import './style.css';

export default DefaultTheme;
188 changes: 188 additions & 0 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/**
* AsyncUp brand theme
* Ink ocean blues + sunrise amber, matching the logo.
*/
:root {
--au-ink: #15435f;
--au-ink-deep: #0e2f44;
--au-amber: #ff8a3d;
--au-amber-soft: #ffae52;
--au-sand: #fff4e6;

--vp-c-brand-1: #176d94;
--vp-c-brand-2: #1d83b2;
--vp-c-brand-3: #15435f;
--vp-c-brand-soft: rgba(23, 109, 148, 0.14);

--vp-button-brand-bg: var(--au-amber);
--vp-button-brand-border: var(--au-amber);
--vp-button-brand-text: #3b2204;
--vp-button-brand-hover-bg: var(--au-amber-soft);
--vp-button-brand-hover-border: var(--au-amber-soft);
--vp-button-brand-hover-text: #3b2204;
--vp-button-brand-active-bg: #f07b2e;
--vp-button-brand-active-border: #f07b2e;

--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(115deg, #15435f 30%, #ff8a3d);
--vp-home-hero-image-background-image: radial-gradient(
circle at 50% 45%,
rgba(255, 174, 82, 0.55) 0%,
rgba(23, 109, 148, 0.35) 55%,
transparent 72%
);
--vp-home-hero-image-filter: blur(56px);
}

.dark {
--vp-c-brand-1: #5cb6dd;
--vp-c-brand-2: #7cc6e6;
--vp-c-brand-3: #1d83b2;
--vp-c-brand-soft: rgba(92, 182, 221, 0.16);
--vp-home-hero-name-background: linear-gradient(115deg, #7cc6e6 25%, #ffae52);
}

.VPHero .VPImage {
border-radius: 22%;
box-shadow: 0 18px 50px rgba(21, 67, 95, 0.35);
}

.VPNavBarTitle .title {
font-weight: 700;
letter-spacing: -0.01em;
}

.VPFeature {
border: 1px solid transparent;
transition: border-color 0.25s, transform 0.25s;
}
.VPFeature:hover {
border-color: var(--vp-c-brand-1);
transform: translateY(-2px);
}

/* ---------- landing-page sections ---------- */

.au-section {
max-width: 1152px;
margin: 0 auto;
padding: 48px 24px 8px;
}
.au-section h2 {
border-top: none;
font-size: 26px;
text-align: center;
margin-bottom: 8px;
}
.au-section > p.au-sub {
text-align: center;
color: var(--vp-c-text-2);
margin: 0 auto 32px;
max-width: 560px;
}

.au-steps {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@media (max-width: 720px) {
.au-steps { grid-template-columns: 1fr; }
}
.au-step {
background: var(--vp-c-bg-soft);
border-radius: 14px;
padding: 22px 22px 18px;
position: relative;
}
.au-step .num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 10px;
background: linear-gradient(135deg, var(--au-amber-soft), var(--au-amber));
color: #3b2204;
font-weight: 800;
margin-bottom: 12px;
}
.au-step h3 { margin: 0 0 6px; font-size: 17px; }
.au-step p { margin: 0; color: var(--vp-c-text-2); font-size: 14px; line-height: 1.55; }

/* chat thread mockup */
.au-thread {
max-width: 660px;
margin: 0 auto;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 16px;
padding: 22px 26px;
font-size: 14px;
line-height: 1.5;
}
.au-thread .day {
font-weight: 700;
color: var(--vp-c-text-1);
padding-bottom: 10px;
border-bottom: 1px solid var(--vp-c-divider);
margin-bottom: 14px;
}
.au-msg {
display: flex;
gap: 12px;
margin: 14px 0;
}
.au-msg .avatar {
flex: none;
width: 34px;
height: 34px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 17px;
background: var(--au-sand);
}
.dark .au-msg .avatar { background: #3a3022; }
.au-msg .bubble {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
padding: 10px 14px;
flex: 1;
}
.au-msg .who { font-weight: 600; margin-bottom: 4px; }
.au-msg .q { color: var(--vp-c-text-3); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 8px; }
.au-msg .q:first-of-type { margin-top: 0; }
.au-msg .blocked { color: #c2410c; }
.dark .au-msg .blocked { color: var(--au-amber-soft); }
.au-wrapup {
margin-top: 16px;
background: linear-gradient(135deg, rgba(255, 174, 82, 0.16), rgba(23, 109, 148, 0.12));
border-radius: 12px;
padding: 12px 16px;
font-weight: 500;
}

/* comparison table */
.au-compare table { width: 100%; display: table; }
.au-compare th:first-child { width: 38%; }
.au-compare td:nth-child(2) { font-weight: 600; }

.au-cta {
text-align: center;
padding: 40px 24px 72px;
}
.au-cta a.button {
display: inline-block;
background: var(--au-amber);
color: #3b2204;
font-weight: 700;
border-radius: 24px;
padding: 11px 26px;
transition: background 0.2s;
text-decoration: none;
}
.au-cta a.button:hover { background: var(--au-amber-soft); }
.au-cta .alt { display: block; margin-top: 14px; color: var(--vp-c-text-2); font-size: 14px; }
108 changes: 97 additions & 11 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ layout: home
hero:
name: AsyncUp
text: Async daily standups for Google Chat
tagline: Open source. Self-hosted. No meeting required.
tagline: Open source. Self-hosted. Your data, your keys, your database — no meeting required.
image:
src: /logo.svg
alt: AsyncUp
actions:
- theme: brand
text: Get started
text: Get started
link: /guide/getting-started
- theme: alt
text: View on GitHub
Expand All @@ -16,20 +19,103 @@ hero:
features:
- icon: 💬
title: One-tap standups
details: A DM card opens a four-question form — yesterday, today, blockers, mood. No chat interrogation.
details: A DM card opens a four-question form — yesterday, today, blockers, mood. Edit until the deadline; the posted card updates in place.
- icon: 🧵
title: Tidy date threads
details: Every answer lands as one card per person under the day's thread in your team space.
details: Every answer lands as one card per person under the day's thread. The wrap-up posts the count and exactly who's missing.
- icon: 🏖️
title: Away-aware
details: Skip-today button, vacation mode, and automatic Google Calendar OOO sync — away people are never nagged or counted as missing.
- icon: ⚠️
title: Blockers that follow up
details: Blockers open from answers, auto-resolve on the next clean submission, and escalate to a contact when they go stale.
- icon: 📊
title: Accountability built in
details: Choose whose updates are mandatory — the wrap-up posts the count and exactly who's missing.
- icon: 🌍
title: Timezone-aware
details: Prompts go out at the configured time in each participant's own timezone, with a reminder nudge before the deadline.
title: Insights built in
details: Mood trends, weekly digests, anonymous team-mood mode, CSV export, and a token-gated web dashboard for config and history.
- icon: 🤖
title: AI summaries, your key
details: Opt-in daily TL;DR and week-in-review via your own Anthropic or OpenAI key. Nothing leaves your infra otherwise.
- icon: 🪶
title: Lightweight forever
details: One small container with SQLite inside. Scale-to-zero friendly, no telemetry, MIT licensed — never SaaS.
details: One ~300 MB container on 1 vCPU / 512 MB. Embedded SQLite by default — or bring your own PostgreSQL with one env var.
- icon: 🔌
title: Platform-agnostic core
details: Google Chat today. Slack and Microsoft Teams adapters are on the roadmap, plus bring-your-own-key AI summaries.
details: Google Chat today; Slack and Microsoft Teams adapters are next on the roadmap. MIT licensed, never SaaS.
---

<div class="au-section">
<h2>How a morning works</h2>
<p class="au-sub">No meeting, no interrogation bot — one card, one form, one thread.</p>
<div class="au-steps">
<div class="au-step">
<span class="num">1</span>
<h3>The bot DMs your team</h3>
<p>At 09:30 in <em>each person's own timezone</em>, everyone gets a card with a <b>Fill standup</b> button — yesterday pre-filled from their last "today". One gentle reminder before the deadline.</p>
</div>
<div class="au-step">
<span class="num">2</span>
<h3>Answers thread up neatly</h3>
<p>Each submission posts as a card under the day's thread in your team space. Re-submit to edit in place. Skips, vacations, and calendar OOO show as away — never as missing.</p>
</div>
<div class="au-step">
<span class="num">3</span>
<h3>The wrap-up holds the line</h3>
<p>At the deadline: who submitted, who didn't, open blockers, team mood — plus an optional AI TL;DR and a weekly digest with trends.</p>
</div>
</div>
</div>

<div class="au-section">
<h2>What your team space sees</h2>
<p class="au-sub">A real thread from a Wednesday.</p>
<div class="au-thread">
<div class="day">📅 Daily Standup — Wed, 11 Jun</div>
<div class="au-msg">
<div class="avatar">😄</div>
<div class="bubble">
<div class="who">Asha</div>
<div class="q">Yesterday</div>
Shipped the payments retry queue
<div class="q">Today</div>
Start on the invoice exports
<div class="q">Blockers</div>
✅ None
</div>
</div>
<div class="au-msg">
<div class="avatar">😐</div>
<div class="bubble">
<div class="who">Rohit <small>· edited</small></div>
<div class="q">Yesterday</div>
Auth refactor review rounds
<div class="q">Today</div>
Land it, then pick up the flaky e2e
<div class="q">Blockers</div>
<span class="blocked">⚠️ Waiting on staging API keys (2d)</span>
</div>
</div>
<div class="au-wrapup">
📊 Wrap-up &nbsp;·&nbsp; ✅ 7/8 submitted &nbsp;·&nbsp; ❌ Missing: Dev &nbsp;·&nbsp; 🏖️ Away: Mei &nbsp;·&nbsp; ⚠️ 1 open blocker
</div>
</div>
</div>

<div class="au-section au-compare">
<h2>Why self-host AsyncUp?</h2>
<p class="au-sub">Hosted standup bots charge per user per month and hold your team's daily history.</p>

| | **AsyncUp** | Hosted standup bots |
|---|---|---|
| Cost | $0 forever — MIT licensed | Per user, per month |
| Your standup history | In **your** SQLite file or Postgres | On their servers |
| AI features | Bring your own key, opt-in per standup | Their model, their terms |
| Infrastructure | One small container, scale-to-zero friendly | — |
| Customization | Questions, schedules, escalation, dashboard — and the source code | What the plan allows |

</div>

<div class="au-cta">
<h2>Up and running in 15 minutes</h2>
<a class="button" href="/guide/getting-started">Read the guide</a>
<span class="alt"><code>docker compose up -d</code> — amd64 &amp; arm64 images on GHCR</span>
</div>
11 changes: 11 additions & 0 deletions docs/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions docs/public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading