Add monorepo README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
138
README.md
Normal file
138
README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Rose Ash
|
||||
|
||||
Monorepo for the Rose Ash cooperative platform — six Quart microservices sharing a common infrastructure layer, a single PostgreSQL database, and an ActivityPub federation layer.
|
||||
|
||||
## Services
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **blog** | blog.rose-ash.com | Content management, Ghost sync, navigation, editor |
|
||||
| **market** | market.rose-ash.com | Product listings, scraping, market pages |
|
||||
| **cart** | cart.rose-ash.com | Shopping cart, checkout, orders, SumUp payments |
|
||||
| **events** | events.rose-ash.com | Calendar, event entries, container widgets |
|
||||
| **federation** | federation.rose-ash.com | OAuth2 authorization server, ActivityPub hub, social features |
|
||||
| **account** | account.rose-ash.com | User dashboard, newsletters, tickets, bookings |
|
||||
|
||||
All services are Python 3.11 / Quart apps served by Hypercorn, deployed as a Docker Swarm stack.
|
||||
|
||||
## Repository structure
|
||||
|
||||
```
|
||||
rose-ash/
|
||||
├── shared/ # Common code: models, services, infrastructure, templates
|
||||
│ ├── models/ # Canonical SQLAlchemy ORM models (all domains)
|
||||
│ ├── services/ # Domain service implementations + registry
|
||||
│ ├── contracts/ # DTOs, protocols, widget contracts
|
||||
│ ├── infrastructure/ # App factory, OAuth, ActivityPub, fragments, Jinja setup
|
||||
│ ├── templates/ # Shared base templates and partials
|
||||
│ ├── static/ # Shared CSS, JS, images
|
||||
│ ├── editor/ # Prose editor (Node build, blog only)
|
||||
│ └── alembic/ # Database migrations
|
||||
├── blog/ # Blog app
|
||||
├── market/ # Market app
|
||||
├── cart/ # Cart app
|
||||
├── events/ # Events app
|
||||
├── federation/ # Federation app
|
||||
├── account/ # Account app
|
||||
├── docker-compose.yml # Swarm stack definition
|
||||
├── deploy.sh # Local build + restart script
|
||||
├── .gitea/workflows/ # CI: build changed apps + deploy
|
||||
├── _config/ # Runtime config (app-config.yaml)
|
||||
├── schema.sql # Reference schema snapshot
|
||||
└── .env # Environment variables (not committed)
|
||||
```
|
||||
|
||||
Each app follows the same layout:
|
||||
|
||||
```
|
||||
{app}/
|
||||
├── app.py # App entry point (creates Quart app)
|
||||
├── path_setup.py # Adds project root + app dir to sys.path
|
||||
├── entrypoint.sh # Container entrypoint (wait for DB, run migrations, start)
|
||||
├── Dockerfile # Build instructions (monorepo context)
|
||||
├── bp/ # Blueprints (routes, handlers)
|
||||
│ └── fragments/ # Fragment endpoints for cross-app composition
|
||||
├── models/ # Re-export stubs pointing to shared/models/
|
||||
├── services/ # App-specific service wiring
|
||||
├── templates/ # App-specific templates (override shared/)
|
||||
└── config/ # App-specific config
|
||||
```
|
||||
|
||||
## Key architecture patterns
|
||||
|
||||
**Shared models** — All ORM models live in `shared/models/`. Each app's `models/` directory contains thin re-export stubs. `factory.py` imports all six apps' models at startup so SQLAlchemy relationship references resolve across domains.
|
||||
|
||||
**Service contracts** — Apps communicate through typed protocols (`shared/contracts/protocols.py`) and frozen dataclass DTOs (`shared/contracts/dtos.py`), wired via a singleton registry (`shared/services/registry.py`). No direct HTTP calls between apps for domain logic.
|
||||
|
||||
**Fragment composition** — Apps expose HTML fragments at `/internal/fragments/<type>` for cross-app UI composition. The blog fetches cart, account, navigation, and event fragments to compose its pages. Fragments are cached in Redis with short TTLs.
|
||||
|
||||
**OAuth SSO** — Federation is the OAuth2 authorization server. All other apps are OAuth clients with per-app first-party session cookies (Safari ITP compatible). Login/callback/logout routes are auto-registered via `shared/infrastructure/oauth.py`.
|
||||
|
||||
**ActivityPub** — Each app has its own AP actor (virtual projection of the same keypair). The federation app is the social hub (timeline, compose, follow, notifications). Activities are emitted to `ap_activities` table and processed by `EventProcessor`.
|
||||
|
||||
## Development
|
||||
|
||||
### Quick deploy (skip CI)
|
||||
|
||||
```bash
|
||||
# Rebuild + restart one app
|
||||
./deploy.sh blog
|
||||
|
||||
# Rebuild + restart multiple apps
|
||||
./deploy.sh blog market
|
||||
|
||||
# Rebuild all
|
||||
./deploy.sh --all
|
||||
|
||||
# Auto-detect changes from git
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### Full stack deploy
|
||||
|
||||
```bash
|
||||
source .env
|
||||
docker stack deploy -c docker-compose.yml coop
|
||||
```
|
||||
|
||||
### Build a single app image
|
||||
|
||||
```bash
|
||||
docker build -f blog/Dockerfile -t registry.rose-ash.com:5000/blog:latest .
|
||||
```
|
||||
|
||||
### Run migrations
|
||||
|
||||
Migrations run automatically on the **blog** service startup when `RUN_MIGRATIONS=true` is set (only blog runs migrations; all other apps skip them).
|
||||
|
||||
```bash
|
||||
# Manual migration
|
||||
docker exec -it $(docker ps -qf name=coop_blog) bash -c "cd shared && alembic upgrade head"
|
||||
```
|
||||
|
||||
## CI/CD
|
||||
|
||||
A single Gitea Actions workflow (`.gitea/workflows/ci.yml`) handles all six apps:
|
||||
|
||||
1. Detects which files changed since the last deploy
|
||||
2. If `shared/` or `docker-compose.yml` changed, rebuilds all apps
|
||||
3. Otherwise rebuilds only apps with changes (or missing images)
|
||||
4. Pushes images to the private registry
|
||||
5. Runs `docker stack deploy` to update the swarm
|
||||
|
||||
### Required secrets
|
||||
|
||||
| Secret | Value |
|
||||
|--------|-------|
|
||||
| `DEPLOY_SSH_KEY` | Private SSH key for root access to the deploy host |
|
||||
| `DEPLOY_HOST` | Hostname or IP of the deploy server |
|
||||
|
||||
## Infrastructure
|
||||
|
||||
- **Runtime**: Python 3.11, Quart (async Flask), Hypercorn
|
||||
- **Database**: PostgreSQL 16 (shared by all apps)
|
||||
- **Cache**: Redis 7 (page cache, fragment cache, sessions)
|
||||
- **Orchestration**: Docker Swarm
|
||||
- **Registry**: `registry.rose-ash.com:5000`
|
||||
- **CI**: Gitea Actions
|
||||
- **Reverse proxy**: Caddy (external, not in this repo)
|
||||
Reference in New Issue
Block a user