Compare commits
4 Commits
reduce-prices
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fa380ac76 | |||
| 591da5dd7b | |||
| b08cb796d7 | |||
| 2919cb12b2 |
@@ -0,0 +1,7 @@
|
|||||||
|
# Flowy.llink
|
||||||
|
|
||||||
|
This project was a radical experiment to transform how teams communicate. The experience revolves around async voice and video clips, with the playback experience being somewhat like Instagram stories that auto-play.
|
||||||
|
|
||||||
|
The goal was to replace live Zoom-style meetings, which are draining, and bring relief to teams by making more conversations async, while retaining natural and high-fidelity with pitch, tone, facial expressions.
|
||||||
|
|
||||||
|
Due to changing conditions in the environment with regards to AI and data sovereignty (and lack of desire to maintain and market this product), we have decided to open source it. Now you can clone, modify, and host it in your own cloud.
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
vars:
|
|
||||||
DEV_REPO: us-west2-docker.pkg.dev/flowy-dev-440017/deployments
|
|
||||||
PROD_REPO: us-west2-docker.pkg.dev/flowy-prod-440017/deployments
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
generate:
|
|
||||||
desc: Generate protobuf code and run go generate
|
|
||||||
cmds:
|
|
||||||
- task: genproto
|
|
||||||
- go generate ./...
|
|
||||||
|
|
||||||
format:
|
|
||||||
desc: Format go files
|
|
||||||
cmds:
|
|
||||||
- go fmt ./...
|
|
||||||
|
|
||||||
genproto:
|
|
||||||
desc: Generate Go code from .proto files via docker
|
|
||||||
vars:
|
|
||||||
PROTO_DIR: '{{.PROTO_DIR | default "./protocol"}}'
|
|
||||||
OUT_DIR: '{{.OUT_DIR | default "./genproto"}}'
|
|
||||||
cmds:
|
|
||||||
- 'echo "Proto directory: {{.PROTO_DIR}}"'
|
|
||||||
- 'echo "Output directory: {{.OUT_DIR}}"'
|
|
||||||
- rm -rf {{.OUT_DIR}}
|
|
||||||
- mkdir -p {{.OUT_DIR}}
|
|
||||||
- |
|
|
||||||
docker run --rm \
|
|
||||||
-v "{{.PROTO_DIR}}/":/protocol \
|
|
||||||
-v "{{.OUT_DIR}}":/genproto \
|
|
||||||
--workdir / \
|
|
||||||
talksik/golang-protoc:latest \
|
|
||||||
sh -c 'protoc --proto_path=./protocol \
|
|
||||||
--go_out=./genproto \
|
|
||||||
--go_opt=paths=source_relative \
|
|
||||||
--go-grpc_out=./genproto \
|
|
||||||
--go-grpc_opt=paths=source_relative \
|
|
||||||
$(find ./protocol -name "*.proto")'
|
|
||||||
|
|
||||||
test:
|
|
||||||
desc: Run tests with pretty output via gotestfmt
|
|
||||||
cmds:
|
|
||||||
- go test -json ./... | docker run -i ghcr.io/gotesttools/gotestfmt:latest
|
|
||||||
|
|
||||||
create-migration:
|
|
||||||
desc: 'Create new migration (usage: task create-migration ARG=create_users_table)'
|
|
||||||
cmds:
|
|
||||||
- 'echo "Creating migration with name {{.ARG}}"'
|
|
||||||
- docker run -v ./migrations:/migrations --network host migrate/migrate create -ext sql -seq -dir /migrations {{.ARG}}
|
|
||||||
|
|
||||||
dev-database:
|
|
||||||
desc: Open psql shell against the dev database
|
|
||||||
interactive: true
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
kubectl run postgres-client \
|
|
||||||
--rm -it --image=postgres:latest \
|
|
||||||
--env="LLINK_POSTGRES_CONNECTION_URL=$(kubectl get secret shared-secrets -o jsonpath='{.data.LLINK_POSTGRES_CONNECTION_URL}' --context dev | base64 --decode)" \
|
|
||||||
--context dev \
|
|
||||||
--command -- /bin/bash -c "psql \$LLINK_POSTGRES_CONNECTION_URL"
|
|
||||||
|
|
||||||
prod-database:
|
|
||||||
desc: Open psql shell against the prod database
|
|
||||||
interactive: true
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
kubectl run postgres-client \
|
|
||||||
--rm -it --image=postgres:latest \
|
|
||||||
--env="LLINK_POSTGRES_CONNECTION_URL=$(kubectl get secret shared-secrets -o jsonpath='{.data.LLINK_POSTGRES_CONNECTION_URL}' --context prod | base64 --decode)" \
|
|
||||||
--context prod \
|
|
||||||
--command -- /bin/bash -c "psql \$LLINK_POSTGRES_CONNECTION_URL"
|
|
||||||
|
|
||||||
migrate-dev:
|
|
||||||
desc: Run migrations against dev cluster
|
|
||||||
cmds:
|
|
||||||
- kubectl delete job migrations --ignore-not-found --context=dev
|
|
||||||
- SKAFFOLD_DEFAULT_REPO={{.DEV_REPO}} skaffold run -p migrations --kube-context dev --tail
|
|
||||||
|
|
||||||
migrate-prod:
|
|
||||||
desc: Run migrations against prod cluster
|
|
||||||
cmds:
|
|
||||||
- kubectl delete job migrations --ignore-not-found --context=prod
|
|
||||||
- SKAFFOLD_DEFAULT_REPO={{.PROD_REPO}} skaffold run -p migrations --kube-context prod --tail
|
|
||||||
|
|
||||||
deploy-dev:
|
|
||||||
desc: 'Deploy to dev (optionally MODULE=orion to deploy a single service)'
|
|
||||||
cmds:
|
|
||||||
- task: generate
|
|
||||||
- task: test
|
|
||||||
- SKAFFOLD_DEFAULT_REPO={{.DEV_REPO}} skaffold run -p dev {{if .MODULE}}-m {{.MODULE}}{{end}} --kube-context dev --port-forward --tail
|
|
||||||
|
|
||||||
deploy-prod:
|
|
||||||
desc: 'Deploy to prod (optionally MODULE=orion to deploy a single service)'
|
|
||||||
cmds:
|
|
||||||
- task: generate
|
|
||||||
- task: test
|
|
||||||
- SKAFFOLD_DEFAULT_REPO={{.PROD_REPO}} skaffold run -p prod {{if .MODULE}}-m {{.MODULE}}{{end}} --kube-context prod --port-forward --tail
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
rules_version = '2';
|
||||||
|
service cloud.firestore {
|
||||||
|
match /databases/{database}/documents {
|
||||||
|
|
||||||
|
// Per-human membership mirror maintained by Orion's service account.
|
||||||
|
// Locked from clients so the membership list cannot leak or be mutated.
|
||||||
|
match /humans/{humanId} {
|
||||||
|
allow read, write: if false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Particles: caller must be a current member of the network in the path.
|
||||||
|
// get() on the mirror is cached across rule evaluations within a single
|
||||||
|
// request, so this costs 1 billed read per request regardless of query size.
|
||||||
|
match /networks/{networkId}/children/{particleId=**} {
|
||||||
|
allow read, write: if request.auth != null
|
||||||
|
&& networkId in get(/databases/$(database)/documents/humans/$(request.auth.uid)).data.networks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
resource "google_firebase_project" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.project_id
|
||||||
|
|
||||||
|
depends_on = [module.project-services]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provisions the Firestore database instance.
|
||||||
|
resource "google_firestore_database" "firestore" {
|
||||||
|
provider = google-beta
|
||||||
|
project = google_firebase_project.default.project
|
||||||
|
name = "(default)"
|
||||||
|
# See available locations: https://firebase.google.com/docs/firestore/locations
|
||||||
|
location_id = var.location
|
||||||
|
# "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs, authentication, and Firebase Security Rules.
|
||||||
|
type = "FIRESTORE_NATIVE"
|
||||||
|
concurrency_mode = "OPTIMISTIC"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_firebaserules_ruleset" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = google_firestore_database.firestore.project
|
||||||
|
source {
|
||||||
|
files {
|
||||||
|
name = "firestore.rules"
|
||||||
|
# Write security rules in a local file named "firestore.rules".
|
||||||
|
# Learn more: https://firebase.google.com/docs/firestore/security/get-started
|
||||||
|
content = file("firestore.rules")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_firebaserules_release" "firestore" {
|
||||||
|
provider = google-beta
|
||||||
|
name = "cloud.firestore"
|
||||||
|
ruleset_name = google_firebaserules_ruleset.default.name
|
||||||
|
project = google_firestore_database.firestore.project
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_firebase_web_app" "llink" {
|
||||||
|
provider = google-beta
|
||||||
|
project = google_firebase_project.default.project
|
||||||
|
display_name = "Llink app"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "google_firebase_web_app_config" "llink" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.project_id
|
||||||
|
web_app_id = google_firebase_web_app.llink.app_id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Below indices support the new structure where all subcollections (including network root particles) live under a collection of name "children"
|
||||||
|
// instead of having `network/n_xxx/particles/p_yyy/children` where the top level subcollection of particles has a distinct name
|
||||||
|
|
||||||
|
// Collection index for particles in a single subcollection
|
||||||
|
resource "google_firestore_index" "list_particles_index" {
|
||||||
|
project = var.project_id
|
||||||
|
collection = "children"
|
||||||
|
query_scope = "COLLECTION"
|
||||||
|
|
||||||
|
fields {
|
||||||
|
field_path = "visible_to"
|
||||||
|
array_config = "CONTAINS"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields {
|
||||||
|
field_path = "status"
|
||||||
|
order = "ASCENDING"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields {
|
||||||
|
field_path = "last_child_created_at"
|
||||||
|
order = "DESCENDING"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields {
|
||||||
|
field_path = "__name__"
|
||||||
|
order = "DESCENDING"
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [google_firestore_database.firestore]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collection group index for particles across all subcollections
|
||||||
|
resource "google_firestore_field" "particle_children_created_at" {
|
||||||
|
database = google_firestore_database.firestore.name
|
||||||
|
project = var.project_id
|
||||||
|
collection = "children"
|
||||||
|
field = "created_at"
|
||||||
|
|
||||||
|
index_config {
|
||||||
|
indexes {
|
||||||
|
order = "DESCENDING"
|
||||||
|
query_scope = "COLLECTION_GROUP"
|
||||||
|
}
|
||||||
|
indexes {
|
||||||
|
order = "ASCENDING"
|
||||||
|
query_scope = "COLLECTION_GROUP"
|
||||||
|
}
|
||||||
|
indexes {
|
||||||
|
order = "DESCENDING"
|
||||||
|
query_scope = "COLLECTION"
|
||||||
|
}
|
||||||
|
indexes {
|
||||||
|
order = "ASCENDING"
|
||||||
|
query_scope = "COLLECTION"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,9 +69,9 @@ spec:
|
|||||||
name: shared-secrets
|
name: shared-secrets
|
||||||
key: STRIPE_WEBHOOK_SECRET
|
key: STRIPE_WEBHOOK_SECRET
|
||||||
- name: "STRIPE_PRICE_PRO_MONTHLY"
|
- name: "STRIPE_PRICE_PRO_MONTHLY"
|
||||||
value: "price_1TMBElJu6RWBXAm2pPthUoh6"
|
value: "price_1ToweOJu6RWBXAm2w2wTo8VL"
|
||||||
- name: "STRIPE_PRICE_PRO_ANNUAL"
|
- name: "STRIPE_PRICE_PRO_ANNUAL"
|
||||||
value: "price_1TMBElJu6RWBXAm2TOpzdXk5"
|
value: "price_1TowexJu6RWBXAm2G9M0WJBK"
|
||||||
- name: "BILLING_SUCCESS_URL"
|
- name: "BILLING_SUCCESS_URL"
|
||||||
value: "llink://billing/success"
|
value: "llink://billing/success"
|
||||||
- name: "BILLING_CANCEL_URL"
|
- name: "BILLING_CANCEL_URL"
|
||||||
|
|||||||
Reference in New Issue
Block a user