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
12 changes: 2 additions & 10 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
# Exclude other apps
apps/web
apps/admin

# Exclude large seed data
db/seed
db/migrations/*.down.sql

# Exclude unnecessary directories
# Exclude unnecessary directories
deployment
docs
tools
Expand All @@ -19,4 +11,4 @@ README.md
# Exclude build artifacts
**/dist/
**/node_modules/
*.log
*.log
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ dist/
.data
tsconfig.tsbuildinfo
storybook-static

.astro
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Important: there are **no builds** for the main apps during dev (both frontend a

- `apps/backend/api`: Hono server, Better Auth, oRPC router, services (user + todo), Vitest tests
- `apps/frontend/web`: Vite + React app (home page is the TODO CRUD demo)
- `apps/frontend/landing`: Astro static landing site (this repo’s “front door”)
- `packages/backend/core`: shared backend core (DB, config, auth helpers, validation, test helpers, generated schema types)
- `packages/frontend/web`: shared UI/components library (shadcn components)
- `packages/shared/*`: shared configs + tiny example package (`hello`)
Expand Down Expand Up @@ -95,6 +96,7 @@ Then run the same steps (`pnpm install`, `just setup`, `pnpm dev`).

- `pnpm dev` / `pnpm typecheck` / `pnpm lint:check` / `pnpm format:check` / `pnpm test`
- `pnpm -C apps/backend/api test`
- `pnpm -C apps/frontend/landing dev`
- `just setup` (docker + migrate), `just db-migrate` (schema “push”), `just db-schema`, `just db-psql`
- Versioned migrations (Atlas, still based on `db/schema.sql`):
- `just db-migration-new add_todos`
Expand Down
6 changes: 6 additions & 0 deletions apps/frontend/landing/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from "astro/config";

export default defineConfig({
output: "static",
trailingSlash: "never",
});
25 changes: 25 additions & 0 deletions apps/frontend/landing/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@yourcompany/landing",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"typecheck": "astro check",
"lint": "biome lint --fix --files-ignore-unknown=true ./src",
"lint:check": "biome lint --files-ignore-unknown=true ./src",
"format": "biome format --write --files-ignore-unknown=true .",
"format:check": "biome format --files-ignore-unknown=true ."
},
"dependencies": {
"astro": "^5.16.5"
},
"devDependencies": {
"@astrojs/check": "^0.9.6",
"@biomejs/biome": "catalog:",
"@types/node": "catalog:",
"typescript": "catalog:"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
11 changes: 11 additions & 0 deletions apps/frontend/landing/public/favicon/site.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "",
"short_name": "",
"icons": [
{ "src": "/favicon/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/favicon/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
Binary file added apps/frontend/landing/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions apps/frontend/landing/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="astro/client" />

40 changes: 40 additions & 0 deletions apps/frontend/landing/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
import "../styles/global.css";
import { LINKS, SITE } from "../lib/site";

type Props = {
title?: string;
description?: string;
};

const { title = SITE.title, description = SITE.description } = Astro.props;
---

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content={description} />
<meta name="theme-color" content="#0b1020" />
<meta name="color-scheme" content="light dark" />
<meta name="generator" content={Astro.generator} />

<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />

<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
<link rel="icon" href="/favicon/favicon.ico" />
<link rel="manifest" href="/favicon/site.webmanifest" />
<link rel="preconnect" href={new URL(LINKS.github).origin} />

<title>{title}</title>
</head>
<body>
<a class="skip-link" href="#content">Skip to content</a>
<slot />
</body>
</html>
16 changes: 16 additions & 0 deletions apps/frontend/landing/src/lib/site.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const SITE = {
title: "FRM Stack",
description:
"A modern TypeScript monorepo template (Turbo + pnpm) with a clean backend/frontend split and pragmatic defaults.",
};

export const LINKS = {
github: "https://github.com/Nikola-Milovic/frm-stack",
twitter: "https://x.com/nikolamilovic5",
email: "nikola@frmlabz.com",
} as const;

export const GET_STARTED = {
cloneSsh: "git@github.com:Nikola-Milovic/frm-stack.git",
cloneHttps: "https://github.com/Nikola-Milovic/frm-stack.git",
} as const;
154 changes: 154 additions & 0 deletions apps/frontend/landing/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
import { GET_STARTED, LINKS, SITE } from "../lib/site";

const mailto = `mailto:${LINKS.email}?subject=${encodeURIComponent("FRM Stack — Hello")}`;
---

<BaseLayout title={`${SITE.title} — Landing`} description={SITE.description}>
<header class="container site-header">
<div class="site-header__inner">
<a href="/" style="display:flex; align-items:center; gap: 10px;">
<img src="/logo.png" alt="FRM Stack" width="28" height="28" />
<span style="font-weight: 800; letter-spacing: -0.03em;">FRM Stack</span>
</a>

<nav aria-label="Primary" class="btn-row">
<a class="btn ghost" href="#get-started">Get started</a>
<a class="btn ghost" href="#contact">Contact</a>
<a class="btn" href={LINKS.github} target="_blank" rel="noreferrer">GitHub</a>
</nav>
</div>
</header>

<main id="content" class="container">
<section class="section hero">
<div class="hero-content">
<h1 class="hero-title">Build fast with a clean, pragmatic stack.</h1>

<p class="hero-lead">
A modern TypeScript monorepo template that gets you to "shipping" quickly: predictable structure, sane tooling, and a backend/frontend split that scales without getting in your way.
</p>

<div class="btn-row hero-cta">
<a class="btn primary" href={LINKS.github} target="_blank" rel="noreferrer">View repo</a>
<a class="btn" href="#get-started">Quick start</a>
</div>
</div>

<div class="card card--terminal hero-terminal">
<div class="terminal-bar" aria-hidden="true">
<span class="terminal-dot dot-red"></span>
<span class="terminal-dot dot-yellow"></span>
<span class="terminal-dot dot-green"></span>
<span class="terminal-title">repo preview</span>
</div>
<pre><code>frm-stack/
apps/
backend/api # API service
frontend/web # product app
frontend/landing # Astro landing
packages/
backend/core # backend libs
frontend/web # web libs
shared/config # shared tooling

# get started with
> just setup
> pnpm dev</code></pre>
</div>
</section>

<section class="section">
<h2>Why this template</h2>
<p class="lead">A baseline that stays tidy as you add apps, packages, and teams.</p>

<div class="grid cols-3">
<div class="card">
<h3>Monorepo that stays tidy</h3>
<p>Turbo + pnpm workspaces/catalog for consistent versions and fast tasks across apps and packages.</p>
</div>
<div class="card">
<h3>Backend + DB workflow</h3>
<p>Postgres-ready, schema-first approach, and a structure that keeps service boundaries clear.</p>
</div>
<div class="card">
<h3>Frontend ready to grow</h3>
<p>Composable UI patterns and tooling that keeps DX high while still being maintainable long-term.</p>
</div>
</div>
</section>

<section id="get-started" class="section">
<h2>Get started</h2>
<p class="lead">Clone the template, install deps, and start the dev servers. Then tweak what you need.</p>

<div class="grid cols-2">
<div class="card">
<h3>1. Clone + install</h3>
<pre><code>git clone {GET_STARTED.cloneHttps}
cd frm-stack
pnpm install</code></pre>
</div>

<div class="card">
<h3>2. Setup + run dev</h3>
<pre><code># from the repo root
just setup
pnpm dev</code></pre>
</div>
</div>
</section>

<section class="section">
<h2>What you get</h2>
<p class="lead">A clean baseline you can adapt: swap libraries, keep the structure, and move quickly.</p>

<div class="grid cols-3">
<div class="card card--soft">
<h3>Clear boundaries</h3>
<p>Apps are separate from shared packages, so shared code stays intentional and easy to maintain.</p>
</div>
<div class="card card--soft">
<h3>Fast feedback loops</h3>
<p>JIT dev setup and task orchestration keep iteration fast, even as the repo grows.</p>
</div>
<div class="card card--soft">
<h3>Sane defaults</h3>
<p>Formatting and linting are centralized; TypeScript and modern tooling are first-class.</p>
</div>
</div>
</section>

<section id="contact" class="section section--end">
<h2>Contact</h2>
<p class="lead">Questions, feedback, or PRs welcome.</p>

<div class="grid cols-3">
<div class="card card--soft">
<h3>Email</h3>
<p><a href={mailto}>{LINKS.email}</a></p>
</div>
<div class="card card--soft">
<h3>Twitter</h3>
<p><a href={LINKS.twitter} target="_blank" rel="noreferrer">{LINKS.twitter}</a></p>
</div>
<div class="card card--soft">
<h3>GitHub</h3>
<p><a href={LINKS.github} target="_blank" rel="noreferrer">{LINKS.github}</a></p>
</div>
</div>
</section>
</main>

<footer class="container site-footer">
<div class="site-footer__inner">
<span>© {new Date().getFullYear()} FRM Stack • Built with Astro</span>
<span>
<a href={LINKS.github} target="_blank" rel="noreferrer">Repo</a>
<span aria-hidden="true"> · </span>
<a href={mailto}>Email</a>
</span>
</div>
</footer>
</BaseLayout>
Loading