# ailog ATProto-based blog platform built on at-browser. ## Concept **Data lives in ATProto, not on this server.** This is not a traditional blog generator. It's a **viewer (client)** for ATProto records. ``` Traditional blog: Server DB ← article data ← user ATProto blog: User's PDS ← article data (ai.syui.log.post) ↓ at-browser (this site) → displays records ``` ## Architecture ``` ┌─────────────────────────────────────────┐ │ at-browser │ │ (ATProto record viewer/editor) │ ├─────────────────────────────────────────┤ │ │ │ / → admin (config.json) │ │ /@alice → user page │ │ /@bob.bsky → user page │ │ │ └─────────────────────────────────────────┘ ``` ## Roles | Role | Path | Data Source | |------|------|-------------| | **admin** | `/` (root) | local + remote | | **user** | `/@handle` | remote only | ### Admin (Site Owner) - Defined in `config.json` - Has root (`/`) access - Can reference **local files** (static assets, custom styles) - Can reference **remote** (ATProto records) ### User (Any ATProto User) - Accessed via `/@handle` path - **Remote only** (ATProto records from their PDS) - No registration required - Anyone with an ATProto account can be displayed ## Features ### 1. at-browser (Core) - Search by handle/DID - Browse PDS collections - Navigate ATProto records ### 2. ai.syui.log.post View - Markdown rendering - Syntax highlighting - Blog-style display ### 3. OAuth - Login with ATProto - Post to ai.syui.log.post collection ## Use Cases ### Personal Blog ```json // config.json { "did": "did:plc:xxxxx", "handle": "syui.syui.ai" } ``` - Deploy to `syui.ai` - Root shows your profile + posts - You are the admin (local + remote) - Others can view via `/@handle` ### Blog Service ```json // config.json { "admin": "service.example.com", "handle": null } ``` - Deploy to `blog.example.com` - Root shows landing/search - All users via `/@handle` (remote only) - Platform for any ATProto user ## Data Flow ``` ┌──────────────┐ ┌──────────────┐ │ User's PDS │────→│ at-browser │ │ (ATProto) │←────│ (this site) │ └──────────────┘ └──────────────┘ ↑ │ │ ↓ ai.syui.log.post ┌──────────┐ collection │ Display │ │ - Profile│ │ - Posts │ └──────────┘ ``` ## Local = Remote (Same Format) **Critical design principle: local files use the exact same format as ATProto API responses.** This allows the same code to handle both data sources. ### Remote (ATProto API) ```bash curl "https://syu.is/xrpc/com.atproto.repo.listRecords?repo=did:plc:xxx&collection=ai.syui.log.post" ``` ```json { "records": [ { "uri": "at://did:plc:xxx/ai.syui.log.post/3xxx", "cid": "bafyrei...", "value": { "title": "Hello World", "content": "# Hello\n\nThis is my post.", "createdAt": "2025-01-01T00:00:00Z" } } ] } ``` ### Local (Static File) ``` public/records/ai.syui.log.post/3xxx.json ``` ```json { "uri": "at://did:plc:xxx/ai.syui.log.post/3xxx", "cid": "local", "value": { "title": "Hello World", "content": "# Hello\n\nThis is my post.", "createdAt": "2025-01-01T00:00:00Z" } } ``` ### Resolution Strategy ``` at-browser │ ├── admin (config.json user) │ ├── 1. Check local: /records/{collection}/{rkey}.json │ └── 2. Fallback to remote: PDS API │ └── user (/@handle) └── remote only: PDS API ``` ### Why Same Format? - **One codebase**: No branching logic for local vs remote - **Easy testing**: Copy API response to local file - **Offline support**: Admin can work with local files - **Migration**: Local → Remote (just POST to PDS) ## Config ### config.json ```json { "did": "did:plc:xxxxx", "handle": "syui.syui.ai", "pds": "syu.is", "collection": "ai.syui.log.post" } ``` ## Tech Stack - **Frontend**: Vite + TypeScript - **ATProto**: @atproto/api - **OAuth**: @atproto/oauth-client-browser - **Markdown**: marked + highlight.js ## Collection Schema ### ai.syui.log.post ```json { "title": "Post Title", "content": "Markdown content...", "createdAt": "2025-01-01T00:00:00Z" } ``` ## License MIT