diff --git a/README.md b/README.md
index e69de29..b7d3a60 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,111 @@
+# atproto(at protocol)
+
+- @
+- [at]mosphere
+- at://domain
+
+## account
+
+[@ai.syu.is](https://web.syu.is/profile/ai.syu.is)
+
+- https://plc.syu.is/did:plc:6qyecktefllvenje24fcxnie
+- https://plc.directory/did:plc:ytvoptig4ddshmwdsjmhtcym
+
+```sh
+$ curl -sL syu.is/xrpc/_health
+{"version":"0.4.65"}
+
+# latest
+# https://github.com/bluesky-social/atproto/blob/main/packages/pds/package.json
+$ curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/packages/pds/package.json |jq -r .version
+```
+
+```sh
+$ curl -sL "syu.is/xrpc/com.atproto.repo.describeRepo?repo=ai.syu.is" |jq -r .did
+did:plc:6qyecktefllvenje24fcxnie
+
+$ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=ai.syu.is&collection=app.bsky.feed.post&reverse=true&limit=1"
+{"records":[{"uri":"at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.post/3l6s2riuouk2j","cid":"bafyreibjohl7va4upkibw5twaxdd4jg3l6rmfatu4dpjjfd5xkb2ijtlx4","value":{"text":"hello","$type":"app.bsky.feed.post","langs":["ja"],"createdAt":"2024-10-18T13:21:39.809Z"}}],"cursor":"3l6s2riuouk2j"}
+```
+
+## feed
+
+> at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
+
+## link
+
+- https://github.com/bluesky-social/atproto
+- https://github.com/itaru2622/bluesky-selfhost-env
+- https://github.com/bluesky-social/atproto/discussions/2026
+
+## self-host
+
+currently, bsky and bsync require patches to function properly. additionally, social-app is not displaying avatars. for components that are not working, it's recommended to use [itaru2622/bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env). this repository provides an environment for self-hosting bluesky.
+
+- bsky = appview
+- ozone = mod
+
+|name|service|patch|
+|---|---|---|
+|pds|https://github.com/bluesky-social/atproto/blob/main/services/pds/Dockerfile||
+|bsky|https://github.com/bluesky-social/atproto/blob/main/services/bsky/Dockerfile|[itaru2622/bluesky-atproto-bsky](https://hub.docker.com/r/itaru2622/bluesky-atproto-bsky)|
+|bsync|https://github.com/bluesky-social/atproto/blob/main/services/bsync/Dockerfile||
+|ozone|https://github.com/bluesky-social/atproto/blob/main/services/ozone/Dockerfile||
+|plc|https://github.com/did-method-plc/did-method-plc/tree/main/packages/server||
+|bgs|https://github.com/bluesky-social/indigo/tree/main/cmd/bigsky||
+|feed|https://github.com/bluesky-social/feed-generator||
+|web|https://github.com/bluesky-social/social-app|[bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/160-social-app-disable-hackModifyThumbnailPath.diff)|
+
+```sh
+# BSKY_IMG_URI_ENDPOINT, BSKY_BLOB_CACHE_LOC
+# avatar link example
+1. https://appview.${host}/img/avatar/plain/${did}/${cid}@jpeg
+2. https://${host}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}
+```
+
+docker compose will not be published unless you write ports. it is only valid internally. add ports only for what you want to publish.
+
+## api
+
+```sh
+# create account
+url=https://${pds}/xrpc/com.atproto.server.createAccount
+json="{\"email\": \"$email\", \"handle\": \"$handle\", \"password\": \"$password\"}"
+curl -X POST -H "Content-Type: application/json" -d $json -sL $url
+```
+
+change `src/pds/handle` to use a name of 3 characters or less. also, you cannot create an account with a name of 3 characters or less from social-app (web client). please create it from api.
+
+- [/atproto/packages/pds/src/handle/index.ts](https://github.com/bluesky-social/atproto/blame/d4d5a6edba972c0e9976289bde8bc0b42ff547ca/packages/pds/src/handle/index.ts#L86-L88)
+
+```sh
+# invite code
+admin_password=xxx
+url=https://$host/xrpc/com.atproto.server.createInviteCode
+json="{\"useCount\":1}"
+curl -X POST -u admin:${admin_password} -H "Content-Type: application/json" -d "$json" -sL $url
+```
+
+## oauth
+
+```sh
+# https://github.com/bluesky-social/cookbook/tree/main/python-oauth-web-app
+$ cd ./repos/cookbook/python-oauth-web-app
+$ rye sync
+$ rye run python3 -c 'import secrets; print(secrets.token_hex())'|xargs echo FLASK_SECRET_KEY|tr -d ' ' >> .env
+$ rye run python3 generate_jwk.py |xargs echo FLASK_CLIENT_SECRET_JWK|tr -d ' ' >> .env
+$ cat .env
+$ rye run flask run
+```
+
+please access `127.0.0.1:5000`. it may not work if you use localhost.
+
+also, oauth doesn't work on localhost. use [ngrok](https://ngrok.com/), [tailscale](https://tailscale.com/), [cloudflare](https://github.com/cloudflare/cloudflared).
+
+```sh
+$ ngrok http http://localhost:5000
+```
+
+```sh
+$ cloudflared tunnel --url http://localhost:5000
+```
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..8ecc4d0
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,30 @@
+#!/bin/zsh
+
+d=${0:a:h}
+cd $d/repos
+
+t="
+https://github.com/bluesky-social/atproto
+https://github.com/did-method-plc/did-method-plc
+https://github.com/bluesky-social/feed-generator
+https://github.com/bluesky-social/social-app
+https://github.com/bluesky-social/cookbook
+https://github.com/itaru2622/bluesky-selfhost-env
+"
+
+t=`echo $t|grep -v '^$'`
+n=`echo $t|wc -l`
+
+for ((i=1;i<=$n;i++))
+do
+ tt=`echo $t|awk "NR==$i"`
+ dd=$d/repos/$tt:t
+ if [ -d $dd ];then
+ echo ok
+ cd $dd
+ git pull
+ cd $d/repos
+ else
+ git clone $tt
+ fi
+done
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 0000000..4679cad
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,166 @@
+services:
+
+ database:
+ image: postgres:16-alpine
+ restart: always
+ env_file:
+ - ./envs/postgres
+ volumes:
+ - ./configs/postgres/init/:/docker-entrypoint-initdb.d/
+ - ./data/postgres/:/var/lib/postgresql/data/
+ healthcheck:
+ test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
+ interval: 5s
+ retries: 20
+
+ redis:
+ image: redis:alpine
+ restart: always
+ volumes:
+ - ./data/redis/:/data/
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping", "|", "grep", "PONG"]
+ interval: 1s
+ timeout: 5s
+ retries: 5
+
+ pds-fix-permission:
+ image: alpine:latest
+ volumes:
+ - ./data/pds/:/data/
+ command: chown 1000.1000 /data
+
+ bsky-fix-permission:
+ image: alpine:latest
+ volumes:
+ - ./data/bsky/:/data/
+ command: chown 1000.1000 /data
+
+ plc:
+ ports:
+ - 2582:3000
+ build:
+ context: ./repos/did-method-plc/
+ dockerfile: packages/server/Dockerfile
+ restart: always
+ env_file:
+ - ./envs/plc
+ depends_on:
+ database:
+ condition: service_healthy
+
+ pds:
+ ports:
+ - 2583:3000
+ #image: itaru2622/bluesky-atproto-pds
+ #image: ghcr.io/bluesky-social/pds:latest
+ build:
+ context: ./repos/atproto/
+ dockerfile: services/pds/Dockerfile
+ restart: always
+ env_file:
+ - ./envs/pds
+ volumes:
+ - ./data/pds/:/data/
+ depends_on:
+ database:
+ condition: service_healthy
+ pds-fix-permission:
+ condition: service_completed_successfully
+
+ bgs:
+ ports:
+ - 2470:2470
+ build:
+ context: ./repos/indigo/
+ dockerfile: cmd/bigsky/Dockerfile
+ restart: always
+ env_file:
+ - ./envs/bgs
+ volumes:
+ - ./data/bgs/:/data/
+ depends_on:
+ database:
+ condition: service_healthy
+
+ ozone:
+ ports:
+ - 2585:3000
+ build:
+ context: ./repos/atproto/
+ dockerfile: services/ozone/Dockerfile
+ restart: always
+ command: node --enable-source-maps api.js
+ volumes:
+ - ./data/ozone/:/data/
+ - ./repos/ozone.js:/app/services/ozone/api.js:ro
+ env_file:
+ - ./envs/ozone
+ healthcheck:
+ test: "wget -q --spider http://localhost:3000/xrpc/_health"
+ interval: 5s
+ retries: 20
+ depends_on:
+ database:
+ condition: service_healthy
+
+ ozone-daemon:
+ build:
+ context: ./repos/atproto/
+ dockerfile: services/ozone/Dockerfile
+ restart: always
+ command: node --enable-source-maps daemon.js
+ env_file:
+ - ./envs/ozone
+ depends_on:
+ ozone:
+ condition: service_healthy
+ database:
+ condition: service_healthy
+
+ social-app:
+ ports:
+ - 8100:8100
+ #image: itaru2622/bluesky-social-app
+ build:
+ context: ./repos/social-app/
+ dockerfile: Dockerfile
+ restart: always
+ env_file:
+ - ./envs/social-app
+ command: "/usr/bin/bskyweb serve"
+
+ bsky:
+ ports:
+ - 2584:2584
+ image: itaru2622/bluesky-atproto-bsky
+ #build:
+ # context: ./repos/atproto/
+ # dockerfile: services/bsky/Dockerfile
+ restart: always
+ env_file:
+ - ./envs/bsky
+ user: root
+ volumes:
+ - ./data/bsky/:/data/
+ # - ./repos/bsky.js:/app/services/bsky/api.js:ro
+ command: node --enable-source-maps api.js
+ depends_on:
+ database:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ bsky-fix-permission:
+ condition: service_completed_successfully
+
+ feed:
+ ports:
+ - 2586:2586
+ build:
+ context: ./repos/feed-generator/
+ restart: always
+ env_file:
+ - ./envs/feed
+ volumes:
+ - ./data/feed/:/data/
+
diff --git a/configs/postgres/init/init.sql b/configs/postgres/init/init.sql
new file mode 100644
index 0000000..f86b7c9
--- /dev/null
+++ b/configs/postgres/init/init.sql
@@ -0,0 +1,35 @@
+-- PLC
+CREATE DATABASE plc;
+GRANT ALL PRIVILEGES ON DATABASE plc TO postgres;
+
+-- BGS
+CREATE DATABASE bgs;
+CREATE DATABASE carstore;
+GRANT ALL PRIVILEGES ON DATABASE bgs TO postgres;
+GRANT ALL PRIVILEGES ON DATABASE carstore TO postgres;
+
+-- bsky(AppView)
+--CREATE DATABASE appview;
+--GRANT ALL PRIVILEGES ON DATABASE appview TO postgres;
+CREATE DATABASE bsky;
+GRANT ALL PRIVILEGES ON DATABASE bsky TO postgres;
+
+-- ozone(Moderation)
+--CREATE DATABASE moderation;
+--GRANT ALL PRIVILEGES ON DATABASE moderation TO postgres;
+CREATE DATABASE ozone;
+GRANT ALL PRIVILEGES ON DATABASE ozone TO postgres;
+
+-- search(palomar)
+CREATE DATABASE search;
+GRANT ALL PRIVILEGES ON DATABASE search TO postgres;
+--CREATE DATABASE palomar;
+--GRANT ALL PRIVILEGES ON DATABASE palomar TO postgres;
+
+-- PDS
+CREATE DATABASE pds;
+GRANT ALL PRIVILEGES ON DATABASE pds TO postgres;
+
+-- BSYNC
+CREATE DATABASE bsync;
+GRANT ALL PRIVILEGES ON DATABASE bsync TO postgres;
diff --git a/envs/bgs b/envs/bgs
new file mode 100644
index 0000000..fa79239
--- /dev/null
+++ b/envs/bgs
@@ -0,0 +1,6 @@
+DATABASE_URL=postgres://postgres:postgres@database/bgs
+CARSTORE_DATABASE_URL=postgres://postgres:postgres@database/carstore
+DATA_DIR=/data
+ATP_PLC_HOST=https://plc.${host}
+
+BGS_ADMIN_KEY
diff --git a/envs/bsky b/envs/bsky
new file mode 100644
index 0000000..5bebd98
--- /dev/null
+++ b/envs/bsky
@@ -0,0 +1,19 @@
+BSKY_PORT=2584
+BSKY_BLOB_CACHE_LOC=/data/
+BSKY_BSYNC_HTTP_VERSION=1.1
+BSKY_BSYNC_PORT=3002
+BSKY_BSYNC_URL=http://bsky:3002
+BSKY_COURIER_URL=http://fake-courier.example.invalid/
+BSKY_DATAPLANE_HTTP_VERSION=1.1
+BSKY_DATAPLANE_PORT=3001
+BSKY_DATAPLANE_URLS=http://bsky:3001
+BSKY_DB_POSTGRES_URL=postgres://postgres:postgres@database/bsky
+BSKY_DID_PLC_URL=https://plc.${host}
+BSKY_PUBLIC_URL=https://bsky.${host}
+BSKY_REPO_PROVIDER=wss://bgs.${host}
+BSKY_SERVER_DID=did:web:bsky.${host}
+MOD_SERVICE_DID=did:web:ozone.${host}
+
+#BSKY_IMG_URI_ENDPOINT=https://bsky.${host}/img
+BSKY_ADMIN_PASSWORDS
+BSKY_SERVICE_SIGNING_KEY
diff --git a/envs/ozone b/envs/ozone
new file mode 100644
index 0000000..72b0158
--- /dev/null
+++ b/envs/ozone
@@ -0,0 +1,21 @@
+OZONE_SERVER_DID=did:web:ozone.${host}
+OZONE_PUBLIC_URL=https://ozone.${host}
+OZONE_ADMIN_HANDLE=${user}.${host}
+OZONE_MODERATOR_DIDS=${did}
+OZONE_ADMIN_DIDS=${did}
+OZONE_DB_POSTGRES_URL=postgres://postgres:postgres@database/ozone
+OZONE_DID_PLC_URL=https://plc.${host}
+NEXT_PUBLIC_PLC_DIRECTORY_URL=https://plc.${host}
+NEXT_PUBLIC_OZONE_SERVICE_DID=did:web:ozone.${host}
+NEXT_PUBLIC_SOCIAL_APP_DOMAIN=mod.${host}
+NEXT_PUBLIC_SOCIAL_APP_URL=https://mod.${host}
+OZONE_APPVIEW_DID=did:web:bsky.${host}
+OZONE_APPVIEW_URL=https://bsky.${host}
+OZONE_APPVIEW_PUSH_EVENTS=false
+OZONE_PDS_DID=did:web:${host}
+OZONE_PDS_URL=https://${host}
+OZONE_DEV_MODE=true
+OZONE_DB_MIGRATE=1
+
+OZONE_ADMIN_PASSWORD
+OZONE_SIGNING_KEY_HEX
diff --git a/envs/pds b/envs/pds
new file mode 100644
index 0000000..fabc2a4
--- /dev/null
+++ b/envs/pds
@@ -0,0 +1,21 @@
+PDS_HOSTNAME=${host}
+PDS_DB_POSTGRES_URL=postgres://postgres:postgres@database/pds
+PDS_DATA_DIRECTORY=/data
+PDS_BLOBSTORE_DISK_LOCATION=/data/img/static
+#PDS_BLOBSTORE_DISK_TMP_LOCATION=/data/img/tmp
+PDS_BSKY_APP_VIEW_DID=did:web:bsky.${host}
+PDS_BSKY_APP_VIEW_URL=https://bsky.${host}
+PDS_CRAWLERS=https://bgs.${host}
+PDS_DEV_MODE=true
+PDS_DID_PLC_URL=https://plc.${host}
+PDS_ENABLE_DID_DOC_WITH_SESSION=true
+PDS_INVITE_INTERVAL=604800000
+PDS_SERVICE_DID=did:web:${host}
+PDS_EMAIL_FROM_ADDRESS=no-reply@${host}
+
+PDS_INVITE_REQUIRED=true
+PDS_EMAIL_SMTP_URL=smtps://${user}:${app_password}@smtp.gmail.com
+PDS_ADMIN_PASSWORD
+PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX
+PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX
+PDS_JWT_SECRET
diff --git a/envs/plc b/envs/plc
new file mode 100644
index 0000000..f0ccb52
--- /dev/null
+++ b/envs/plc
@@ -0,0 +1,4 @@
+DATABASE_URL=postgres://postgres:postgres@database/plc
+DB_CREDS_JSON='{"username":"postgres","password":"postgres","host":"database","port":"5432","database":"plc"}'
+ENABLE_MIGRATIONS=true
+DB_MIGRATE_CREDS_JSON='{"username":"postgres","password":"postgres","host":"database","port":"5432","database":"plc"}'
diff --git a/envs/postgres b/envs/postgres
new file mode 100644
index 0000000..4184165
--- /dev/null
+++ b/envs/postgres
@@ -0,0 +1,4 @@
+#POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+POSTGRES_DB=healthcheck
diff --git a/envs/social-app b/envs/social-app
new file mode 100644
index 0000000..a6752de
--- /dev/null
+++ b/envs/social-app
@@ -0,0 +1 @@
+ATP_APPVIEW_HOST=https://bsky.${host}
diff --git a/icons/Logotype.tsx b/icons/Logotype.tsx
new file mode 100644
index 0000000..b087a56
--- /dev/null
+++ b/icons/Logotype.tsx
@@ -0,0 +1,52 @@
+import React from 'react'
+import Svg, {Path, SvgProps, PathProps} from 'react-native-svg'
+
+import {usePalette} from '#/lib/hooks/usePalette'
+
+const ratio = 17 / 64
+
+export function Logotype({
+ fill,
+ ...rest
+}: {fill?: PathProps['fill']} & SvgProps) {
+ const pal = usePalette('default')
+ // @ts-ignore it's fiiiiine
+ const size = parseInt(rest.width || 32)
+
+ return (
+
+ )
+}
diff --git a/icons/title.svg b/icons/title.svg
new file mode 100644
index 0000000..73a0b2f
--- /dev/null
+++ b/icons/title.svg
@@ -0,0 +1,32 @@
+
diff --git a/repos/.keep b/repos/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/repos/atproto b/repos/atproto
new file mode 160000
index 0000000..8f2b80a
--- /dev/null
+++ b/repos/atproto
@@ -0,0 +1 @@
+Subproject commit 8f2b80a0dcf118652452ea09764a947b09991e0f
diff --git a/repos/bluesky-selfhost-env b/repos/bluesky-selfhost-env
new file mode 160000
index 0000000..3e384e3
--- /dev/null
+++ b/repos/bluesky-selfhost-env
@@ -0,0 +1 @@
+Subproject commit 3e384e3b58b8284c68e9562d16920867f8905340
diff --git a/repos/cookbook b/repos/cookbook
new file mode 160000
index 0000000..03739f5
--- /dev/null
+++ b/repos/cookbook
@@ -0,0 +1 @@
+Subproject commit 03739f5268d5915e0dc7e8815723575f4b457bda
diff --git a/repos/did-method-plc b/repos/did-method-plc
new file mode 160000
index 0000000..13da315
--- /dev/null
+++ b/repos/did-method-plc
@@ -0,0 +1 @@
+Subproject commit 13da315787e50bd79548d5b695f4f597b43b4015
diff --git a/repos/feed-generator b/repos/feed-generator
new file mode 160000
index 0000000..9a887dd
--- /dev/null
+++ b/repos/feed-generator
@@ -0,0 +1 @@
+Subproject commit 9a887dd8f2ee634c5e524cfa802f754878a91e5a
diff --git a/repos/social-app b/repos/social-app
new file mode 160000
index 0000000..f6649e2
--- /dev/null
+++ b/repos/social-app
@@ -0,0 +1 @@
+Subproject commit f6649e22a762fa8f4d3060da0a274f3b83ecb06f