mirror of
https://github.com/trailbaseio/trailbase.git
synced 2026-01-06 18:00:25 -06:00
Apply changes proposed by @mdb in #37 and use the opportunity to clear out some obsolete cruft.
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
# example.com
|
||||
|
||||
localhost
|
||||
encode gzip zstd
|
||||
reverse_proxy blog:4000
|
||||
|
||||
@@ -18,27 +18,86 @@
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
The main goal of this example is to be easily digestible while show-casing many
|
||||
of TrailBase's capabilities both for web and cross-platform Flutter:
|
||||
The blog example presents some of TrailBase's capabilities in an easily easily
|
||||
digestible fashion:
|
||||
|
||||
* Bootstrapping the database including schemas and dummy content though migration.
|
||||
* End-to-end type-safety through code-generated data models for TypeScript,
|
||||
Dart and many more based on JSON Schema.
|
||||
* Builtin web authentication flow (including OAuth) on web and Flutter as well
|
||||
as a custom password-based login in Flutter.
|
||||
* API authorization: world readable, user editable, and moderator manageable articles.
|
||||
* Building UI Apps both for web and cross-platform using Flutter.
|
||||
* End-to-end type-safe APIs based on JSON schemas and code-generation
|
||||
supporting most popular languages.
|
||||
* Authentication flows with social OAuth and password sign-in for web and Flutter.
|
||||
* Authorization: world readable, user editable, and moderator manageable articles.
|
||||
* Different API types:
|
||||
* Table and View-based APIs for custom user profiles associating users with a
|
||||
username and keep their email addresses private as well as associating
|
||||
articles with usernames.
|
||||
* Virtual-table-based query API to expose `is_editor` authorization.
|
||||
* The web client illustrates two different styles: a consumer SPA and an
|
||||
HTML-only form-based authoring UI.
|
||||
* Table and View-based APIs for custom user profiles associating users with a
|
||||
username to keep their email addresses private as well as associating
|
||||
articles with usernames.
|
||||
* Virtual-table-based query API to expose `is_editor` authorization.
|
||||
* Migrations to bootstrap the database with schemas and dummy content.
|
||||
* The web UI is implemented as a reader-side SPA and static HTML page for blog
|
||||
authors to demonstrate both styles.
|
||||
|
||||
Default users:
|
||||
## Getting Started
|
||||
|
||||
* (email: `admin@localhost`, password: `secret`) - access to admin dash.
|
||||
* (email: `editor@localhost`, password: `secret`) - permission to write and alter blog posts.
|
||||
To get the blog up and running with self-signed SSL certificates in under 2
|
||||
minutes, simply run:
|
||||
|
||||
```bash
|
||||
cd examples/blog
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
Afterwards check out the blog at [http://localhost](http://localhost). You'll
|
||||
be automatically forwarded to HTTPS and will need to accept the self-signed
|
||||
certificate.
|
||||
You can write new blog posts using the predefined user:
|
||||
|
||||
* email: `editor@localhost`
|
||||
* password: `secret`
|
||||
|
||||
You can also check out the admin dashboard at
|
||||
[http://localhost/_/admin](http://localhost/_/admin) using the predefined
|
||||
admin:
|
||||
|
||||
* email: `admin@localhost`
|
||||
* password: `secret`
|
||||
|
||||
For context, the above `docker compose` invocation started two services:
|
||||
|
||||
* TrailBase itself hosting the web UI, and
|
||||
* a [Caddy](https://github.com/caddyserver/caddy) reverse-proxy to
|
||||
automatically terminate TLS using self-signed certificates demonstrating a
|
||||
production-ready setup.
|
||||
|
||||
To shut everything back down, simply run:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## Detailed Instructions
|
||||
|
||||
If you don't want to use the docker compose setup above, build from scratch, or
|
||||
run the the Flutter app, only a few simple steps are needed.
|
||||
If you have `cargo`, `pnpm`, and `flutter` installed, you can simply run:
|
||||
|
||||
```bash
|
||||
# Build the Blog's web UI:
|
||||
$ pnpm --dir web build
|
||||
|
||||
# Build and start TrailBase:
|
||||
$ cargo run --bin trail -- run --public web/dist
|
||||
|
||||
# Build and start the Flutter app:
|
||||
$ cd flutter
|
||||
$ flutter run -d <Device, e.g.: Linux, Chrome, Mobile Emulator, ...>
|
||||
```
|
||||
|
||||
In case you'd like to re-generate the language bindings for the type-safe APIs
|
||||
or generate new bindings for a different language, check out the `Makefile` or
|
||||
run:
|
||||
|
||||
```bash
|
||||
$ make --always-make types
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
@@ -65,39 +124,6 @@ Default users:
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
Generally speaking, there are roughly 2.5 moving parts to run the example, i.e:
|
||||
we have to build the web UI, start the TrailBase server, and optionally start
|
||||
the Flutter app. Once you have `cargo`, `pnpm`, and `flutter` installed, you
|
||||
can simply run:
|
||||
|
||||
```bash
|
||||
# From within the blog examples base directory
|
||||
$ cd $REPO/examples/blog
|
||||
|
||||
# build and bundle the web app:
|
||||
$ pnpm --dir web build
|
||||
|
||||
# Start TrailBase:
|
||||
cargo run --bin trail -- run --public web/dist
|
||||
|
||||
# Start Flutter app:
|
||||
$ cd flutter
|
||||
$ flutter run -d <Device, e.g.: Linux, Chrome, Mobile Emulator, ...>
|
||||
```
|
||||
|
||||
You can also try the code generation:
|
||||
|
||||
```bash
|
||||
# Optionally delete the checked-in JSON schemas and code first
|
||||
$ make clean_types
|
||||
|
||||
# Genarate JSON Schema and codegen types from DB schema (this requires that
|
||||
# you start TrailBase first to initialize the DB)
|
||||
$ make --always-make types
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
* The styling is based on: https://github.com/palmiak/pacamara-astro 🙏
|
||||
* The styling is based on: [palmiak/pacamara-astro](https://github.com/palmiak/pacamara-astro) 🙏
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
services:
|
||||
|
||||
blog:
|
||||
# NOTE: We have to build relative to root to have a build context that
|
||||
# includes both: the trailbase server source and the demo wepapp sources.
|
||||
# build: ../..
|
||||
# TODO: Build from "." once the Dockerfile can pull a base image from
|
||||
# dockerhub. We still need an example Dockerfile to build the UI.
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: examples/blog/Dockerfile
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TRAIL_INITIAL_PASSWORD: secret
|
||||
ADDRESS: 0.0.0.0:4000
|
||||
PUBLIC_DIR: ./public
|
||||
DATA_DIR: ./traildepot
|
||||
volumes:
|
||||
- ./traildepot:/app/traildepot
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
{
|
||||
"$defs": {
|
||||
"image": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"content_type": {
|
||||
"description": "The file's user-provided content type.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"filename": {
|
||||
"description": "The file's original file name.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"description": "The file's inferred mime type. Not user provided.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"title": "FileUpload",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "string"
|
||||
},
|
||||
"created": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"image": {
|
||||
"$ref": "#/$defs/image"
|
||||
},
|
||||
"intro": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"author",
|
||||
"title",
|
||||
"intro",
|
||||
"tag",
|
||||
"body",
|
||||
"created",
|
||||
"username"
|
||||
],
|
||||
"title": "articles_view",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
"nanostores": "^0.11.4",
|
||||
"solid-icons": "^1.1.0",
|
||||
"solid-js": "^1.9.5",
|
||||
"trailbase": "workspace:*"
|
||||
"trailbase": "^0.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/solid-js": "^5.0.5",
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -149,8 +149,8 @@ importers:
|
||||
specifier: ^1.9.5
|
||||
version: 1.9.5
|
||||
trailbase:
|
||||
specifier: workspace:*
|
||||
version: link:../../../trailbase-core/js/client
|
||||
specifier: ^0.3.3
|
||||
version: 0.3.3
|
||||
devDependencies:
|
||||
'@astrojs/solid-js':
|
||||
specifier: ^5.0.5
|
||||
@@ -5221,6 +5221,9 @@ packages:
|
||||
resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
trailbase@0.3.3:
|
||||
resolution: {integrity: sha512-s0GgYMlMbWJKwg3jcu7d9T5AN3rzBlrIeUpOiQhi8ogNX1BoHzRYb0vq3Yy52nEyybCmY+ExnJQvawzm/Yvc0A==}
|
||||
|
||||
trim-lines@3.0.1:
|
||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
||||
|
||||
@@ -11692,6 +11695,11 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
trailbase@0.3.3:
|
||||
dependencies:
|
||||
jwt-decode: 4.0.0
|
||||
uuid: 11.1.0
|
||||
|
||||
trim-lines@3.0.1: {}
|
||||
|
||||
trough@2.2.0: {}
|
||||
|
||||
Reference in New Issue
Block a user