11# Zenao - Zen Autonomous Organizations
22
3- An event management and community platform featuring event creation, community management, and social feeds.
3+ An events management and communities platform featuring event creation, community management, and social feeds.
44
55> ** Note:** Zenao is currently a Web2 application, with plans to transition to Web3 using [ base] ( https://www.base.org/ ) .
66
@@ -38,6 +38,7 @@ An event management and community platform featuring event creation, community m
3838- ** Go 1.25+** ([ download] ( https://go.dev/doc/install ) )
3939
4040> ** ⚠️ Important:** This project uses ** Node.js 20.13.1** (see ` .nvmrc ` ), which is not the latest version. Using a different Node version may cause package-lock.json conflicts and CI failures. We strongly recommend using a Node version manager like [ nvm] ( https://github.com/nvm-sh/nvm ) or [ fnm] ( https://github.com/Schniz/fnm ) to switch to the correct version:
41+ >
4142> ``` bash
4243> nvm use # or: fnm use
4344> ` ` `
@@ -47,6 +48,7 @@ An event management and community platform featuring event creation, community m
4748Follow these steps to run the complete stack locally (frontend + backend + database):
4849
4950** Before you start:** You may need to configure these services:
51+
5052- [Clerk Authentication Setup](# clerk-authentication-setup) - If the default test keys have expired
5153- [File Uploads with Pinata](# file-uploads-with-pinata) - Required to upload images (e.g., create events)
5254
@@ -65,10 +67,12 @@ make dev
6567` ` `
6668
6769That' s it! The app will be running at:
70+
6871- **Frontend**: [http://localhost:3000](http://localhost:3000)
6972- **Backend**: [http://localhost:4242](http://localhost:4242)
7073
7174> **⚠️ Note:** The Go backend reads environment variables from your shell, not from `.env.local`. Export the Clerk secret key before running `make dev` if you modified the default key:
75+ >
7276> ```bash
7377> export ZENAO_CLERK_SECRET_KEY=sk_test_... # Must match CLERK_SECRET_KEY in .env.local
7478> ```
@@ -104,6 +108,7 @@ This creates a `dev.db` file in the project root.
104108### 4. Start Backend
105109
106110In a dedicated terminal, export the Clerk secret key (if you modified the default) and start the backend:
111+
107112```bash
108113export ZENAO_CLERK_SECRET_KEY=sk_test_... # Must match CLERK_SECRET_KEY in .env.local
109114go run ./backend start
@@ -112,13 +117,15 @@ go run ./backend start
112117The backend will run on http://localhost:4242
113118
114119**Optional:** Generate fake data for development:
120+
115121```bash
116122go run ./backend fakegen
117123```
118124
119125### 5. Start Frontend
120126
121127In a new terminal:
128+
122129```bash
123130npm run dev
124131```
@@ -130,6 +137,7 @@ npm run dev
130137- **Database**: `dev.db` (SQLite file in project root)
131138
132139You can inspect the database using any SQLite client:
140+
133141```bash
134142sqlite3 dev.db
135143# Or use a GUI like DB Browser for SQLite
@@ -191,54 +199,63 @@ DISCORD_TOKEN= # Default: empty (Discord
191199# ## Unit Tests
192200
193201Run Go backend tests:
202+
194203` ` ` bash
195204make test
196205` ` `
197206
198207# ## E2E Tests
199208
200209Run E2E tests in headless mode (automated):
210+
201211` ` ` bash
202212make test-e2e
203213` ` `
204214
205215Or run manually with the Cypress UI:
206216
207217** 1. Setup environment:**
218+
208219` ` ` bash
209220cp .env.example .env.local
210221` ` `
211222
212223** 2. Start E2E infrastructure:**
224+
213225` ` ` bash
214226go run ./backend e2e-infra
215227` ` `
216228
217229This command sets up the E2E local environment:
230+
218231- Applies Atlas migrations on a temporary SQLite DB (` e2e.db` )
219232- Generates fake data (users, events, posts, communities, etc.)
220233- Starts the backend
221234- Exposes ` http://localhost:4243/reset` endpoint for test automation (deduplicates/queues concurrent reset requests)
222235- Prints logs from all services
223236
224237** Optional:** Use the ` --ci` flag to also build and start the Next.js frontend in the background (used for CI):
238+
225239` ` ` bash
226240go run ./backend e2e-infra --ci
227241` ` `
228242
229243See ` backend/e2e_infra.go` for implementation details.
230244
231245** 3. Wait for stack readiness:**
246+
232247` ` `
233248READY | ----------------------------
234249` ` `
235250
236251** 4. Start frontend (new terminal):**
252+
237253` ` ` bash
238254npm run dev
239255` ` `
240256
241257** 5. Open Cypress (new terminal):**
258+
242259` ` ` bash
243260npm run cypress:e2e
244261` ` `
@@ -256,6 +273,7 @@ The project includes default Clerk test keys that work out of the box. If you en
256273** 2. Create a new application** in the Clerk dashboard
257274
258275** 3. Get your API keys:**
276+
259277- Dashboard → ** API Keys**
260278- Copy ` NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` (starts with ` pk_test_...` )
261279- Copy ` CLERK_SECRET_KEY` (starts with ` sk_test_...` )
@@ -282,15 +300,18 @@ export ZENAO_CLERK_SECRET_KEY=sk_test_your_key_here
282300** 1. Create a free Pinata account:** [app.pinata.cloud/register](https://app.pinata.cloud/register)
283301
284302** 2. Create an API Key:**
303+
285304- Dashboard → ** API Keys** → ** + New Key**
286305- Grant ** Files** write permission and ** Group** read permission
287306- Copy the JWT (shown only once! )
288307
289308** 3. Create a Gateway:**
309+
290310- Dashboard → ** Gateways** → ** + New Gateway**
291311- Copy your gateway domain (e.g., ` your-name.mypinata.cloud` )
292312
293313** 4. (Optional) Create a Group:**
314+
294315- Dashboard → ** Groups** → ** + Create Group**
295316- Copy the Group ID (used to organize uploaded files)
296317
@@ -307,6 +328,7 @@ PINATA_GROUP=your-group-id # Optional
307328# ## Common Issues
308329
309330** Upload fails:**
331+
310332- Check you haven' t exceeded 1GB free tier limit
311333- Restart dev server after changing `.env.local`
312334
@@ -317,13 +339,15 @@ Zenao supports paid events with Stripe checkout. This feature is behind a featur
317339### Enabling Paid Events
318340
319341**1. Set the backend feature flag** (as environment variable, not from `.env.local`):
342+
320343```bash
321344export ZENAO_PAID_EVENTS_ENABLED=true
322345```
323346
324347> **Note:** The frontend always renders price fields when price groups exist in event data. No frontend flag is needed.
325348
326349**2. Configure Stripe test keys:**
350+
327351```bash
328352# In .env.local
329353ZENAO_STRIPE_SECRET_KEY=sk_test_your_stripe_test_key
@@ -333,6 +357,7 @@ NEXT_PUBLIC_STRIPE_DASHBOARD_URL=https://dashboard.stripe.com/test
333357Get test keys from [Stripe Dashboard → Developers → API keys](https://dashboard.stripe.com/test/apikeys).
334358
335359**3. (For payment confirmation) Start the Stripe webhook listener:**
360+
336361```bash
337362# Install the Stripe CLI: https://stripe.com/docs/stripe-cli
338363stripe listen --forward-to localhost:4242/webhook/stripe
@@ -372,6 +397,7 @@ make generate
372397```
373398
374399This will:
400+
375401- Run protobuf code generation
376402- Build email templates
377403- Format Go code
@@ -381,11 +407,13 @@ This will:
381407**1. Edit GORM models** in `./backend/gzdb` (domain-split files: `db_events.go`, `db_communities.go`, `db_users.go`, `db_tickets.go`, `db_feeds.go`, `db_pricing.go`, `db_roles.go`)
382408
383409**2. Update Atlas schema:**
410+
384411```bash
385412make update-schema
386413```
387414
388415**3. Create migration:**
416+
389417```bash
390418atlas migrate diff $MIGRATION_NAME \
391419 --dir "file://migrations" \
@@ -394,11 +422,13 @@ atlas migrate diff $MIGRATION_NAME \
394422```
395423
396424**4. Apply migration locally:**
425+
397426```bash
398427make migrate-local
399428```
400429
401430**5. Apply to staging/production:**
431+
402432```bash
403433# For staging or prod, set TURSO_TOKEN with a write-enabled token
404434export TURSO_TOKEN=<your-token>
@@ -414,11 +444,13 @@ For debugging and tracing requests across the stack, you can run an OpenTelemetr
414444### Quick Start (Recommended)
415445
416446Start the full stack with OTEL enabled:
447+
417448```bash
418449make dev-otel
419450```
420451
421452This starts everything together:
453+
422454- **Frontend** on [http://localhost:3000](http://localhost:3000)
423455- **Backend** on [http://localhost:4242](http://localhost:4242)
424456- **OTEL Collector** on port 4318
@@ -427,17 +459,20 @@ This starts everything together:
427459### Manual Setup
428460
429461**1. Start the OTEL stack:**
462+
430463```bash
431464docker compose -f dev.docker-compose.yml up
432465```
433466
434467This starts:
468+
435469- **OTEL Collector** on port 4318 - receives traces from the app
436470- **Jaeger UI** on [http://localhost:16686](http://localhost:16686) - visualize traces
437471
438472**2. Enable OTEL in your environment:**
439473
440474Set the OTEL endpoint in `.env.local`:
475+
441476```bash
442477OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
443478```
@@ -447,6 +482,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
447482**4. Open Jaeger UI** at [http://localhost:16686](http://localhost:16686) to view request traces.
448483
449484This is useful for:
485+
450486- Debugging slow requests
451487- Understanding request flow between frontend and backend
452488- Performance optimization
@@ -464,6 +500,7 @@ Copy the staging environment variables from your deployment platform's dashboard
464500> ** Note:** You need to be a team member to access staging environment variables. Contact a team admin if you don' t have access.
465501
466502**2. Start only the frontend:**
503+
467504```bash
468505npm run dev
469506```
@@ -473,6 +510,7 @@ Now your local frontend will connect to the staging backend and use real staging
473510### Accessing Staging/Production Data
474511
475512When using staging environment variables:
513+
476514- You' ll see ** real user data** from staging
477515- Authentication uses the ** staging Clerk instance**
478516- Any changes affect the ** staging database**
@@ -482,27 +520,30 @@ When using staging environment variables:
482520# # Troubleshooting
483521
484522# ## Database connection errors
523+
485524Ensure you' ve run migrations:
525+
486526```bash
487527make migrate-local
488528```
489529
490530### Cannot access database file
531+
491532The database is created at `dev.db` in the project root after running `make migrate-local`.
492533
493534## Make Commands
494535
495- | Command | Description |
496- |---------| -------------|
497- | `make setup-dev` | Install dependencies, configure environment, run migrations, and generate fake data |
498- | `make dev` | Start backend and frontend servers together |
499- | `make dev-otel` | Start backend, frontend, and OTEL stack (Jaeger UI at localhost:16686) |
500- | `make test` | Run Go backend unit tests |
501- | `make test-e2e` | Run Cypress E2E tests in headless mode |
502- | `make generate` | Regenerate protobuf code and email templates |
503- | `make migrate-local` | Apply database migrations to local dev.db |
504- | `make update-schema` | Update Atlas schema from GORM models |
505- | `make lint-fix` | Run ESLint with auto-fix |
536+ | Command | Description |
537+ | -------------------- | ----------------------------------------------------------------------------------- |
538+ | `make setup-dev` | Install dependencies, configure environment, run migrations, and generate fake data |
539+ | `make dev` | Start backend and frontend servers together |
540+ | `make dev-otel` | Start backend, frontend, and OTEL stack (Jaeger UI at localhost:16686) |
541+ | `make test` | Run Go backend unit tests |
542+ | `make test-e2e` | Run Cypress E2E tests in headless mode |
543+ | `make generate` | Regenerate protobuf code and email templates |
544+ | `make migrate-local` | Apply database migrations to local dev.db |
545+ | `make update-schema` | Update Atlas schema from GORM models |
546+ | `make lint-fix` | Run ESLint with auto-fix |
506547
507548## Project Structure
508549
0 commit comments