create-githat-app 1.2.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -18
- package/dist/cli.js +1161 -114
- package/package.json +34 -9
- package/templates/agent/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/agent/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/agent/app/admin/agent/page.tsx.hbs +127 -0
- package/templates/agent/app/globals.css.hbs +87 -0
- package/templates/agent/app/layout.tsx.hbs +41 -0
- package/templates/agent/app/page.tsx.hbs +100 -0
- package/templates/agent/next.config.ts.hbs +8 -0
- package/templates/agent/postcss.config.mjs.hbs +14 -0
- package/templates/agent/proxy.ts.hbs +10 -0
- package/templates/agent/tsconfig.json.hbs +21 -0
- package/templates/base/.env.example.hbs +2 -2
- package/templates/base/.env.local.example.hbs +20 -0
- package/templates/base/.env.local.hbs +13 -2
- package/templates/base/.github/CODEOWNERS.hbs +1 -0
- package/templates/base/.github/SECURITY.md +10 -0
- package/templates/base/.github/dependabot.yml +19 -0
- package/templates/base/.github/workflows/ci.yml.hbs +77 -0
- package/templates/base/.github/workflows/githat-policy.yml +51 -0
- package/templates/base/.gitignore.hbs +17 -2
- package/templates/base/README.md.hbs +31 -52
- package/templates/classroom/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/classroom/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/classroom/app/globals.css.hbs +87 -0
- package/templates/classroom/app/layout.tsx.hbs +41 -0
- package/templates/classroom/app/page.tsx.hbs +103 -0
- package/templates/classroom/app/projects/[id]/feedback/page.tsx.hbs +159 -0
- package/templates/classroom/app/projects/[id]/present/page.tsx.hbs +113 -0
- package/templates/classroom/next.config.ts.hbs +8 -0
- package/templates/classroom/postcss.config.mjs.hbs +14 -0
- package/templates/classroom/proxy.ts.hbs +10 -0
- package/templates/classroom/tsconfig.json.hbs +21 -0
- package/templates/content/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/content/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/content/app/globals.css.hbs +87 -0
- package/templates/content/app/layout.tsx.hbs +41 -0
- package/templates/content/app/newsletter/page.tsx.hbs +90 -0
- package/templates/content/app/page.tsx.hbs +105 -0
- package/templates/content/app/posts/[slug]/page.tsx.hbs +119 -0
- package/templates/content/next.config.ts.hbs +8 -0
- package/templates/content/postcss.config.mjs.hbs +14 -0
- package/templates/content/proxy.ts.hbs +10 -0
- package/templates/content/tsconfig.json.hbs +21 -0
- package/templates/dashboard/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/dashboard/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +68 -0
- package/templates/dashboard/app/admin/page.tsx.hbs +59 -0
- package/templates/dashboard/app/globals.css.hbs +87 -0
- package/templates/dashboard/app/layout.tsx.hbs +41 -0
- package/templates/dashboard/app/page.tsx.hbs +57 -0
- package/templates/dashboard/next.config.ts.hbs +8 -0
- package/templates/dashboard/postcss.config.mjs.hbs +14 -0
- package/templates/dashboard/proxy.ts.hbs +10 -0
- package/templates/dashboard/src/lib/db.ts.hbs +39 -0
- package/templates/dashboard/tsconfig.json.hbs +21 -0
- package/templates/fullstack/apps-api-express/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-express/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-express/package.json.hbs +24 -0
- package/templates/fullstack/apps-api-express/src/index.ts.hbs +41 -0
- package/templates/fullstack/apps-api-express/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-express/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-express/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-api-fastify/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-fastify/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-fastify/package.json.hbs +22 -0
- package/templates/fullstack/apps-api-fastify/src/index.ts.hbs +28 -0
- package/templates/fullstack/apps-api-fastify/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-fastify/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-fastify/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-api-hono/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-hono/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-hono/package.json.hbs +22 -0
- package/templates/fullstack/apps-api-hono/src/index.ts.hbs +35 -0
- package/templates/fullstack/apps-api-hono/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-hono/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-hono/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-web-nextjs/.env.example.hbs +5 -0
- package/templates/fullstack/apps-web-nextjs/.env.local.hbs +5 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/forgot-password/page.tsx.hbs +11 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/reset-password/page.tsx.hbs +39 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/verify-email/page.tsx.hbs +11 -0
- package/templates/fullstack/apps-web-nextjs/app/dashboard/layout.tsx.hbs +15 -0
- package/templates/fullstack/apps-web-nextjs/app/dashboard/page.tsx.hbs +27 -0
- package/templates/fullstack/apps-web-nextjs/app/globals.css.hbs +21 -0
- package/templates/fullstack/apps-web-nextjs/app/layout.tsx.hbs +30 -0
- package/templates/fullstack/apps-web-nextjs/app/page.tsx.hbs +17 -0
- package/templates/fullstack/apps-web-nextjs/next.config.ts.hbs +16 -0
- package/templates/fullstack/apps-web-nextjs/package.json.hbs +34 -0
- package/templates/fullstack/apps-web-nextjs/postcss.config.mjs.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/tsconfig.json.hbs +21 -0
- package/templates/fullstack/root/.gitignore.hbs +42 -0
- package/templates/fullstack/root/githat.yaml.hbs +17 -0
- package/templates/fullstack/root/package.json.hbs +15 -0
- package/templates/fullstack/root/turbo.json.hbs +20 -0
- package/templates/marketplace/CULTURE.md +74 -0
- package/templates/marketplace/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +99 -0
- package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +90 -0
- package/templates/marketplace/app/admin/page.tsx.hbs +95 -0
- package/templates/marketplace/app/cart/page.tsx.hbs +157 -0
- package/templates/marketplace/app/globals.css.hbs +87 -0
- package/templates/marketplace/app/layout.tsx.hbs +77 -0
- package/templates/marketplace/app/page.tsx.hbs +178 -0
- package/templates/marketplace/app/sell/page.tsx.hbs +78 -0
- package/templates/marketplace/next.config.ts.hbs +8 -0
- package/templates/marketplace/postcss.config.mjs.hbs +14 -0
- package/templates/marketplace/proxy.ts.hbs +10 -0
- package/templates/marketplace/src/lib/anon-session.ts.hbs +117 -0
- package/templates/marketplace/src/lib/categories.ts.hbs +35 -0
- package/templates/marketplace/tsconfig.json.hbs +21 -0
- package/templates/nextjs/.github/workflows/deploy.yml.hbs +107 -0
- package/templates/nextjs/app/(auth)/reset-password/page.tsx.hbs +106 -0
- package/templates/nextjs/app/globals.css.hbs +4 -3
- package/templates/nextjs/app/layout.tsx.hbs +5 -1
- package/templates/nextjs/app/page.tsx.hbs +3 -6
- package/templates/nextjs/next.config.ts.hbs +5 -2
- package/templates/nextjs/proxy.ts.hbs +10 -0
- package/templates/plain/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/plain/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/plain/app/globals.css.hbs +87 -0
- package/templates/plain/app/layout.tsx.hbs +41 -0
- package/templates/plain/app/page.tsx.hbs +123 -0
- package/templates/plain/next.config.ts.hbs +8 -0
- package/templates/plain/postcss.config.mjs.hbs +14 -0
- package/templates/plain/proxy.ts.hbs +10 -0
- package/templates/plain/tsconfig.json.hbs +21 -0
- package/templates/portfolio/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/portfolio/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/portfolio/app/globals.css.hbs +87 -0
- package/templates/portfolio/app/layout.tsx.hbs +41 -0
- package/templates/portfolio/app/page.tsx.hbs +86 -0
- package/templates/portfolio/next.config.ts.hbs +8 -0
- package/templates/portfolio/postcss.config.mjs.hbs +14 -0
- package/templates/portfolio/proxy.ts.hbs +10 -0
- package/templates/portfolio/tsconfig.json.hbs +21 -0
- package/templates/react-vite/src/App.tsx.hbs +11 -9
- package/templates/react-vite/src/index.css.hbs +4 -3
- package/templates/react-vite/src/pages/Home.tsx.hbs +3 -6
- package/templates/saas/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/saas/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/saas/app/admin/billing/page.tsx.hbs +145 -0
- package/templates/saas/app/admin/page.tsx.hbs +106 -0
- package/templates/saas/app/admin/team/page.tsx.hbs +134 -0
- package/templates/saas/app/globals.css.hbs +87 -0
- package/templates/saas/app/layout.tsx.hbs +41 -0
- package/templates/saas/app/page.tsx.hbs +108 -0
- package/templates/saas/app/pricing/page.tsx.hbs +131 -0
- package/templates/saas/next.config.ts.hbs +8 -0
- package/templates/saas/postcss.config.mjs.hbs +14 -0
- package/templates/saas/proxy.ts.hbs +10 -0
- package/templates/saas/tsconfig.json.hbs +21 -0
- package/templates/nextjs/middleware.ts.hbs +0 -10
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main", "master"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
issues: write
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: "20"
|
|
23
|
+
cache: "npm"
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm install
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: npm test --if-present
|
|
30
|
+
|
|
31
|
+
- name: Build
|
|
32
|
+
run: npm run build --if-present
|
|
33
|
+
|
|
34
|
+
- name: Notify on failure
|
|
35
|
+
if: failure()
|
|
36
|
+
uses: actions/github-script@v7
|
|
37
|
+
with:
|
|
38
|
+
script: |
|
|
39
|
+
const workflowName = context.workflow;
|
|
40
|
+
const sha = context.sha.slice(0, 7);
|
|
41
|
+
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
42
|
+
const marker = `<!-- workflow:${workflowName} -->`;
|
|
43
|
+
const title = `CI failure: ${workflowName} on ${sha}`;
|
|
44
|
+
const body = [
|
|
45
|
+
marker,
|
|
46
|
+
`**Workflow:** ${workflowName}`,
|
|
47
|
+
`**Commit:** ${context.sha}`,
|
|
48
|
+
`**Branch:** ${context.ref}`,
|
|
49
|
+
`**Run:** ${runUrl}`,
|
|
50
|
+
].join('\n');
|
|
51
|
+
|
|
52
|
+
// Search for an existing open ci-failure issue for this workflow
|
|
53
|
+
const { data: issues } = await github.rest.issues.listForRepo({
|
|
54
|
+
owner: context.repo.owner,
|
|
55
|
+
repo: context.repo.repo,
|
|
56
|
+
labels: 'ci-failure',
|
|
57
|
+
state: 'open',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const existing = issues.find(i => i.body && i.body.includes(marker));
|
|
61
|
+
|
|
62
|
+
if (existing) {
|
|
63
|
+
await github.rest.issues.createComment({
|
|
64
|
+
owner: context.repo.owner,
|
|
65
|
+
repo: context.repo.repo,
|
|
66
|
+
issue_number: existing.number,
|
|
67
|
+
body: `New failure on run [${context.runId}](${runUrl}) at \`${sha}\``,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
await github.rest.issues.create({
|
|
71
|
+
owner: context.repo.owner,
|
|
72
|
+
repo: context.repo.repo,
|
|
73
|
+
title,
|
|
74
|
+
body,
|
|
75
|
+
labels: ['ci-failure'],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: GitHat Platform Policy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, edited, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
enforce-auth-policy:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Close alt-auth PRs
|
|
16
|
+
uses: actions/github-script@v7
|
|
17
|
+
with:
|
|
18
|
+
script: |
|
|
19
|
+
const title = context.payload.pull_request.title;
|
|
20
|
+
const altAuthPattern = /(?i)(cognito|hand-rolled oauth|auth0|clerk|firebase auth)/;
|
|
21
|
+
|
|
22
|
+
// JavaScript RegExp — use the 'i' flag directly
|
|
23
|
+
const pattern = /(cognito|hand-rolled oauth|auth0|clerk|firebase auth)/i;
|
|
24
|
+
|
|
25
|
+
if (!pattern.test(title)) {
|
|
26
|
+
return; // Nothing to do
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const prNumber = context.payload.pull_request.number;
|
|
30
|
+
|
|
31
|
+
// Post the policy explanation comment
|
|
32
|
+
await github.rest.issues.createComment({
|
|
33
|
+
owner: context.repo.owner,
|
|
34
|
+
repo: context.repo.repo,
|
|
35
|
+
issue_number: prNumber,
|
|
36
|
+
body: [
|
|
37
|
+
'GitHat is the auth platform for every app in this portfolio.',
|
|
38
|
+
'Hand-rolled OAuth, Cognito, Auth0, Clerk, and Firebase Auth proposals are not the direction.',
|
|
39
|
+
'Auth flows through `@githat/nextjs` and `api.githat.io` for human users,',
|
|
40
|
+
'autonomous agents, and MCP servers.',
|
|
41
|
+
'Closing per platform policy.',
|
|
42
|
+
].join(' '),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Close the PR
|
|
46
|
+
await github.rest.pulls.update({
|
|
47
|
+
owner: context.repo.owner,
|
|
48
|
+
repo: context.repo.repo,
|
|
49
|
+
pull_number: prNumber,
|
|
50
|
+
state: 'closed',
|
|
51
|
+
});
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
node_modules
|
|
2
|
-
{{#
|
|
2
|
+
{{#ifNext framework}}
|
|
3
3
|
.next
|
|
4
4
|
out
|
|
5
5
|
{{else}}
|
|
6
6
|
dist
|
|
7
|
-
{{/
|
|
7
|
+
{{/ifNext}}
|
|
8
|
+
|
|
9
|
+
# Environment files — NEVER commit these. Real keys live here.
|
|
10
|
+
# `.env.local`, `.env.development.local`, `.env.production.local`,
|
|
11
|
+
# and any per-package `.env*.local` are matched by the patterns below.
|
|
8
12
|
.env
|
|
13
|
+
.env.local
|
|
9
14
|
.env*.local
|
|
15
|
+
.env.*.local
|
|
16
|
+
|
|
17
|
+
# OS / editor
|
|
10
18
|
.DS_Store
|
|
11
19
|
*.tgz
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
|
|
23
|
+
# Logs / coverage
|
|
24
|
+
*.log
|
|
25
|
+
.turbo/
|
|
26
|
+
coverage/
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
# {{projectName}}
|
|
2
2
|
|
|
3
|
-
Built with [GitHat](https://githat.io) —
|
|
3
|
+
Built with [GitHat](https://githat.io) — auth, teams, orgs, API keys, MCP verification, and AI agent identity are handled by GitHat's hosted platform.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
7
|
-
1.
|
|
7
|
+
1. Copy the env file and fill in your GitHat key:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
cp .env.local.example .env.local
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
2.
|
|
13
|
+
2. Install dependencies:
|
|
14
14
|
|
|
15
|
-
```
|
|
16
|
-
{{#ifEquals
|
|
15
|
+
```bash
|
|
16
|
+
{{#ifEquals packageManager "yarn"}}yarn{{else}}{{packageManager}} install{{/ifEquals}}
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Get your key at [githat.io/dashboard/apps](https://githat.io/dashboard/apps).
|
|
20
|
-
|
|
21
19
|
3. Start the dev server:
|
|
22
20
|
|
|
23
21
|
```bash
|
|
@@ -26,36 +24,11 @@ Get your key at [githat.io/dashboard/apps](https://githat.io/dashboard/apps).
|
|
|
26
24
|
|
|
27
25
|
4. Open [http://localhost:{{#ifEquals framework "nextjs"}}3000{{else}}5173{{/ifEquals}}](http://localhost:{{#ifEquals framework "nextjs"}}3000{{else}}5173{{/ifEquals}})
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
All API calls go to `api.githat.io`. Your data is stored in GitHat's database. **No backend to deploy.**
|
|
32
|
-
|
|
33
|
-
GitHat handles:
|
|
34
|
-
|
|
35
|
-
- User auth (sign-up, sign-in, email verification, password reset)
|
|
36
|
-
- Organizations (create, switch, branding)
|
|
37
|
-
- Team management (invite members, assign roles)
|
|
38
|
-
- API key management (publishable + secret keys)
|
|
39
|
-
{{#if includeMcpModule}}- MCP server registration and domain verification
|
|
40
|
-
{{/if}}{{#if includeAgentModule}}- AI agent registration and wallet verification
|
|
41
|
-
{{/if}}- Email delivery (verification, invitations, password resets)
|
|
42
|
-
|
|
43
|
-
The `githat/` folder in your project is a typed API client that talks to `api.githat.io`. You write frontend code, GitHat handles the rest.
|
|
44
|
-
|
|
45
|
-
Manage everything at [githat.io/dashboard](https://githat.io/dashboard).
|
|
46
|
-
|
|
47
|
-
## Pages
|
|
48
|
-
|
|
49
|
-
- `/sign-in` — Sign in
|
|
50
|
-
- `/sign-up` — Create account
|
|
51
|
-
{{#if includeForgotPassword}}- `/forgot-password` — Password recovery
|
|
52
|
-
{{/if}}{{#if includeDashboard}}- `/dashboard` — Protected dashboard
|
|
53
|
-
{{/if}}{{#if includeOrgManagement}}- `/dashboard/members` — Invite members, manage roles
|
|
54
|
-
{{/if}}
|
|
27
|
+
Your `NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY` is required — get it at [githat.io/dashboard/apps](https://githat.io/dashboard/apps) or re-run `create-githat-app` after running `githat login` to have it auto-registered.
|
|
55
28
|
|
|
56
29
|
## GitHat SDK
|
|
57
30
|
|
|
58
|
-
This project uses [`@githat/nextjs`](https://www.npmjs.com/package/@githat/nextjs)
|
|
31
|
+
This project uses [`@githat/nextjs`](https://www.npmjs.com/package/@githat/nextjs):
|
|
59
32
|
|
|
60
33
|
```{{#if typescript}}tsx{{else}}jsx{{/if}}
|
|
61
34
|
import { useAuth, UserButton, OrgSwitcher } from '@githat/nextjs';
|
|
@@ -63,32 +36,38 @@ import { useAuth, UserButton, OrgSwitcher } from '@githat/nextjs';
|
|
|
63
36
|
const { user, org, signIn, signUp, signOut } = useAuth();
|
|
64
37
|
```
|
|
65
38
|
|
|
66
|
-
## Deploy
|
|
39
|
+
## Deploy to EC2 via GitHub Actions
|
|
67
40
|
|
|
68
|
-
|
|
41
|
+
The scaffolded `.github/workflows/deploy.yml` deploys the Next.js standalone bundle to an EC2 instance on every push to `main`.
|
|
69
42
|
|
|
70
|
-
|
|
71
|
-
npx vercel
|
|
72
|
-
```
|
|
43
|
+
**Required GitHub repo secrets:**
|
|
73
44
|
|
|
74
|
-
|
|
75
|
-
|
|
45
|
+
| Secret | Description |
|
|
46
|
+
|--------|-------------|
|
|
47
|
+
| `SSH_PRIVATE_KEY` | Private key whose public key is in the EC2 instance's `~/.ssh/authorized_keys` |
|
|
48
|
+
| `EC2_HOST` | `ubuntu@<ec2-ip-or-hostname>` |
|
|
49
|
+
| `PROD_ENV` | Full contents of your production `.env` file (set via `gh secret set PROD_ENV < .env.local`) |
|
|
50
|
+
| `GITHAT_PUBLISHABLE_KEY` | Your GitHat publishable key (baked into the client bundle at build time) |
|
|
76
51
|
|
|
77
|
-
|
|
78
|
-
npx vercel
|
|
79
|
-
```
|
|
52
|
+
**One-time EC2 setup:**
|
|
80
53
|
|
|
81
|
-
|
|
54
|
+
1. Create a systemd service at `/etc/systemd/system/{{projectName}}.service` that runs `node /opt/{{projectName}}/server.js` with `PORT=3000`.
|
|
55
|
+
2. Create `/opt/{{projectName}}/` owned by your deploy user.
|
|
56
|
+
3. Enable the service: `sudo systemctl enable {{projectName}}`.
|
|
82
57
|
|
|
83
|
-
|
|
84
|
-
npx netlify deploy
|
|
85
|
-
```
|
|
58
|
+
After that, every `git push origin main` triggers a build + rsync + restart. The workflow smoke-tests `/api/health` before reporting success.
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
|
|
60
|
+
## Pages
|
|
61
|
+
|
|
62
|
+
- `/sign-in` — Sign in
|
|
63
|
+
- `/sign-up` — Create account
|
|
64
|
+
{{#if includeForgotPassword}}- `/forgot-password` — Password recovery
|
|
65
|
+
{{/if}}{{#if includeDashboard}}- `/dashboard` — Protected dashboard
|
|
66
|
+
{{/if}}{{#if includeOrgManagement}}- `/dashboard/members` — Invite members, manage roles
|
|
67
|
+
{{/if}}
|
|
89
68
|
|
|
90
69
|
## Learn More
|
|
91
70
|
|
|
92
71
|
- [GitHat Documentation](https://githat.io/docs)
|
|
93
72
|
- [SDK Reference](https://www.npmjs.com/package/@githat/nextjs)
|
|
94
|
-
- [API Reference
|
|
73
|
+
- [API Reference](https://githat.io/docs/api)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignInForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignInPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignInForm signUpUrl="/sign-up" {{#if includeForgotPassword}}forgotPasswordUrl="/forgot-password"{{/if}} />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignUpForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignUpPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignUpForm signInUrl="/sign-in" />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tailwind v4 — required because @githat/nextjs/styles is processed
|
|
3
|
+
* through @tailwindcss/postcss. Plain doesn't ship utility classes,
|
|
4
|
+
* but the import is needed for the auth pages to render styled.
|
|
5
|
+
*/
|
|
6
|
+
@import "tailwindcss";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Plain template — self-contained globals.
|
|
10
|
+
*
|
|
11
|
+
* Defines the minimum CSS variables a GitHat app uses for layout and
|
|
12
|
+
* the auth-page styling that ships with @githat/nextjs/styles.
|
|
13
|
+
* Override these in your own files when you want a real theme.
|
|
14
|
+
*
|
|
15
|
+
* Light theme by default; flip --bg/--fg for dark.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
/* Surface */
|
|
20
|
+
--bg: #ffffff;
|
|
21
|
+
--surface: #fafafa;
|
|
22
|
+
--surface-sub: #f4f4f5;
|
|
23
|
+
|
|
24
|
+
/* Borders */
|
|
25
|
+
--border: #e5e7eb;
|
|
26
|
+
|
|
27
|
+
/* Foreground */
|
|
28
|
+
--fg: #0a0a0a;
|
|
29
|
+
--fg-muted: #525252;
|
|
30
|
+
--fg-subtle: #737373;
|
|
31
|
+
|
|
32
|
+
/* Brand — change these two to re-skin the whole auth flow */
|
|
33
|
+
--primary: #6366f1;
|
|
34
|
+
--accent: #f59e0b;
|
|
35
|
+
|
|
36
|
+
/* Semantic */
|
|
37
|
+
--success: #16a34a;
|
|
38
|
+
--warn: #d97706;
|
|
39
|
+
--danger: #dc2626;
|
|
40
|
+
|
|
41
|
+
/* Spacing — used by @githat/nextjs/styles */
|
|
42
|
+
--space-1: 0.25rem;
|
|
43
|
+
--space-2: 0.5rem;
|
|
44
|
+
--space-3: 0.75rem;
|
|
45
|
+
--space-4: 1rem;
|
|
46
|
+
--space-6: 1.5rem;
|
|
47
|
+
--space-8: 2rem;
|
|
48
|
+
|
|
49
|
+
/* Radius */
|
|
50
|
+
--radius: 0.5rem;
|
|
51
|
+
--radius-md: 0.5rem;
|
|
52
|
+
--radius-lg: 0.75rem;
|
|
53
|
+
|
|
54
|
+
/* Fonts */
|
|
55
|
+
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
56
|
+
--font-wordmark: 'Instrument Serif', Georgia, serif;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (prefers-color-scheme: dark) {
|
|
60
|
+
:root {
|
|
61
|
+
--bg: #0a0a0a;
|
|
62
|
+
--surface: #18181b;
|
|
63
|
+
--surface-sub: #27272a;
|
|
64
|
+
--border: #3f3f46;
|
|
65
|
+
--fg: #fafafa;
|
|
66
|
+
--fg-muted: #a1a1aa;
|
|
67
|
+
--fg-subtle: #71717a;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
* {
|
|
72
|
+
box-sizing: border-box;
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
body {
|
|
78
|
+
font-family: var(--font-sans);
|
|
79
|
+
background: var(--bg);
|
|
80
|
+
color: var(--fg);
|
|
81
|
+
line-height: 1.5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
a {
|
|
85
|
+
color: inherit;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { GitHatProvider } from '@githat/nextjs';
|
|
2
|
+
import '@githat/nextjs/styles';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
title: '{{businessName}}',
|
|
7
|
+
description: '{{description}}',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function RootLayout({ children }{{#if typescript}}: { children: React.ReactNode }{{/if}}) {
|
|
11
|
+
return (
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<body>
|
|
14
|
+
{/*
|
|
15
|
+
Plain template: no @githat/ui dep, no Wordmark. The
|
|
16
|
+
full-kit (`nextjs`) template uses @githat/ui for the
|
|
17
|
+
shared design system; the plain scaffold is the smallest
|
|
18
|
+
working app, so we avoid extra deps.
|
|
19
|
+
*/}
|
|
20
|
+
<GitHatProvider config=\{{
|
|
21
|
+
publishableKey: process.env.NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY || '',
|
|
22
|
+
signInUrl: '/sign-in',
|
|
23
|
+
signUpUrl: '/sign-up',
|
|
24
|
+
afterSignInUrl: '/',
|
|
25
|
+
afterSignOutUrl: '/',
|
|
26
|
+
}}>
|
|
27
|
+
<header style=\{{
|
|
28
|
+
padding: '1rem 1.5rem',
|
|
29
|
+
borderBottom: '1px solid var(--border, #e5e7eb)',
|
|
30
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
31
|
+
}}>
|
|
32
|
+
<a href="/" style=\{{ textDecoration: 'none', color: 'inherit', fontWeight: 600 }}>
|
|
33
|
+
{{businessName}}
|
|
34
|
+
</a>
|
|
35
|
+
</header>
|
|
36
|
+
<main>{children}</main>
|
|
37
|
+
</GitHatProvider>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { useAuth, SignInButton } from '@githat/nextjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Classroom — projects with real-world feedback.
|
|
8
|
+
*
|
|
9
|
+
* Built for students (and anyone presenting work-in-progress) to
|
|
10
|
+
* replace the dead-end PDF. You upload a project, share a link,
|
|
11
|
+
* and audience feedback streams in as you present. The work
|
|
12
|
+
* iterates — every cohort that hits the same project sees the
|
|
13
|
+
* latest version and adds to it.
|
|
14
|
+
*
|
|
15
|
+
* The flagship feature is /projects/[id]/present + /projects/[id]/feedback —
|
|
16
|
+
* presenter sees responses live, audience submits without an account.
|
|
17
|
+
*
|
|
18
|
+
* Why this matters: a portfolio of dead PDFs is worth less than
|
|
19
|
+
* a single project with a year of audience feedback layered on top.
|
|
20
|
+
*/
|
|
21
|
+
const SAMPLE_PROJECTS = [
|
|
22
|
+
{ id: 'sustainable-bodega', title: 'Sustainable bodega supply chain', author: 'Maria L.', cohort: 'Spring 2026', responses: 47 },
|
|
23
|
+
{ id: 'after-school-tutor', title: 'After-school tutor matching app', author: 'Devon R.', cohort: 'Spring 2026', responses: 12 },
|
|
24
|
+
{ id: 'community-fridge', title: 'Community fridge tracker', author: 'Aisha M.', cohort: 'Fall 2025', responses: 89 },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export default function Home() {
|
|
28
|
+
const { isSignedIn } = useAuth();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div style=\{{ background: 'var(--bg)', color: 'var(--fg)' }}>
|
|
32
|
+
<section style=\{{
|
|
33
|
+
padding: 'var(--space-12) var(--space-4)',
|
|
34
|
+
textAlign: 'center',
|
|
35
|
+
maxWidth: '40rem',
|
|
36
|
+
margin: '0 auto',
|
|
37
|
+
}}>
|
|
38
|
+
<h1 style=\{{
|
|
39
|
+
fontFamily: 'var(--font-wordmark, Georgia, serif)',
|
|
40
|
+
fontSize: 'clamp(2rem, 5vw, 3rem)',
|
|
41
|
+
lineHeight: 1.1,
|
|
42
|
+
marginBottom: 'var(--space-3)',
|
|
43
|
+
}}>
|
|
44
|
+
{{businessName}}
|
|
45
|
+
</h1>
|
|
46
|
+
<p style=\{{ color: 'var(--fg-muted)', fontSize: '1.125rem', lineHeight: 1.6, marginBottom: 'var(--space-6)' }}>
|
|
47
|
+
Show your work. Get real feedback as you present. Watch
|
|
48
|
+
your project iterate over time — each cohort that visits
|
|
49
|
+
adds to it.
|
|
50
|
+
<br />
|
|
51
|
+
<em style=\{{ fontSize: '0.875rem' }}>The PDF is dead. Long live the living project.</em>
|
|
52
|
+
</p>
|
|
53
|
+
{!isSignedIn ? (
|
|
54
|
+
<SignInButton />
|
|
55
|
+
) : (
|
|
56
|
+
<Link href="/admin" style=\{{
|
|
57
|
+
display: 'inline-block',
|
|
58
|
+
padding: 'var(--space-3) var(--space-6)',
|
|
59
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
60
|
+
background: 'var(--primary)',
|
|
61
|
+
color: 'var(--bg)',
|
|
62
|
+
fontWeight: 600,
|
|
63
|
+
textDecoration: 'none',
|
|
64
|
+
}}>
|
|
65
|
+
New project →
|
|
66
|
+
</Link>
|
|
67
|
+
)}
|
|
68
|
+
</section>
|
|
69
|
+
|
|
70
|
+
<section style=\{{ padding: 'var(--space-8) var(--space-4)', maxWidth: '48rem', margin: '0 auto' }}>
|
|
71
|
+
<h2 style=\{{ fontSize: '1.5rem', marginBottom: 'var(--space-4)' }}>Live projects</h2>
|
|
72
|
+
<p style=\{{ color: 'var(--fg-muted)', fontSize: '0.875rem', marginBottom: 'var(--space-4)' }}>
|
|
73
|
+
Anyone can submit feedback — no account required. Authors
|
|
74
|
+
see responses streaming in as they present.
|
|
75
|
+
</p>
|
|
76
|
+
<ul style=\{{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 'var(--space-3)' }}>
|
|
77
|
+
{SAMPLE_PROJECTS.map((p) => (
|
|
78
|
+
<li key={p.id}>
|
|
79
|
+
<Link href={`/projects/${p.id}`} style=\{{
|
|
80
|
+
display: 'block',
|
|
81
|
+
padding: 'var(--space-5)',
|
|
82
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
83
|
+
border: '1px solid var(--border)',
|
|
84
|
+
background: 'var(--surface)',
|
|
85
|
+
color: 'var(--fg)',
|
|
86
|
+
textDecoration: 'none',
|
|
87
|
+
}}>
|
|
88
|
+
<h3 style=\{{ fontSize: '1.125rem', fontWeight: 600, marginBottom: 'var(--space-1)' }}>{p.title}</h3>
|
|
89
|
+
<div style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)', display: 'flex', gap: 'var(--space-3)', flexWrap: 'wrap' }}>
|
|
90
|
+
<span>{p.author}</span>
|
|
91
|
+
<span>·</span>
|
|
92
|
+
<span>{p.cohort}</span>
|
|
93
|
+
<span>·</span>
|
|
94
|
+
<span><strong>{p.responses}</strong> responses</span>
|
|
95
|
+
</div>
|
|
96
|
+
</Link>
|
|
97
|
+
</li>
|
|
98
|
+
))}
|
|
99
|
+
</ul>
|
|
100
|
+
</section>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|