Tilaukset ja laskutus — yleiskuvaus
Tehtävä
VeraFrame Cloudin kontrollitaso: se muuttaa laskutustapahtuman tuoteoikeudeksi. Asiakas ostaa itse verkosta, tenantti syntyy automaattisesti, ja tilauksen tila ratkaisee mitä hän saa tehdä — ilman että oikeuslogiikkaa toistetaan sovelluksen muissa osissa.
Moduuli on tuotteen ainoa itsepalvelumyyntikanava ja samalla se paikka, jossa päätetään mitä peruutetulle asiakkaalle tapahtuu.
Teknologia
- Kieli/alusta: Python 3, AWS Lambda -runtime
- Kehys: ei mitään. Stripe-integraatio on tehty
urllib.requestilla suoraan Stripen REST-rajapintaan — ei Stripen SDK:ta, eirequests-kirjastoa - Rajapinta: seitsemän HTTP-reittiä integraatio-API:ssa + yksi oma lambda (Stripe-webhook). Muut sisääntulot ovat funktiokutsuja
- Tietokanta: yksi DynamoDB-taulu (webhookin idempotenssilukko). Tenantin tila elää objektitallennuksessa JSON-dokumenttina, ei tietokannassa
- Keskeiset riippuvuudet: ulos Stripe (REST) ja AWS Cognito (käyttäjät,
boto3suoraan); sisäänlahdeaineisto(load_customer_config),tallennus(storage_provider),data_sources(save_customer_config)
Kaksi poikkeusta projektin pilvineutraaliin sääntöön. Muu koodi kulkee
*_provider.py-abstraktioiden läpi, mutta tässä moduulissa on suoria
boto3-kutsuja: Cognito-käyttäjähallinta (saas_onboarding.py:237),
tenanttisäiliön luonti (saas_onboarding.py:1004) ja webhookin lukkotaulu
(stripe_webhook/handler.py:186). Nämä kolme kohtaa eivät toimi
Azure-asennuksessa sellaisenaan.
Sisääntulopisteet
HTTP-reitit
Kaikki reitit ovat POST. Reittitaulu on deployment/template.yamlin
Events-lohkoissa; koodin reititys on merkkijonovertailua.
| Reitti | Autentikointi | Prosessi |
|---|---|---|
/api/v1/saas/plans |
ei mitään | pakettikatalogi (public_plan_catalog, saas_onboarding.py:621; handler_api.py:367) |
/api/v1/saas/checkout |
ei mitään | Itsepalvelutilauksen aloitus (ei näytteessä) |
/api/v1/saas/activate-account |
ei mitään (token) | Tilin aktivointi (ei näytteessä) |
/api/v1/saas/billing-portal |
admin + admin_dashboard |
Laskutusportaali ja tilauksen lopetus (ei näytteessä) |
/api/v1/saas/users · /users/save · /users/delete |
admin + admin_dashboard + saas-lohko |
Tenantin käyttäjähallinta (ei näytteessä) |
/api/v1/billing/stripe/webhook |
Stripe-allekirjoitus (oma lambda) | Stripe-tapahtuman käsittely |
Kolme autentikoimatonta reittiä ovat välttämättömiä (ostaja ei vielä ole
asiakas), mutta ne ovat samalla moduulin hyökkäyspinta. /saas/checkout on
suojattu vain sillä, että olemassa oleva tenantti tai sähköposti torjutaan;
pyyntörajaa siinä ei ole.
Funktiokutsut muista moduuleista
| Funktio | Prosessi | Kutsujat |
|---|---|---|
sync_saas_subscription_from_stripe(customer_id, force) |
Tilauksen täsmäytys Stripestä | auth_provider.py:415, auth_provider.py:513; scripts/list-saas-tenant-lifecycle.py:30, scripts/list-veraframe-cloud-tenants.py:28 |
load_email_index(email) |
Tenantin käyttäjähallinta (ei näytteessä) | auth_provider.py:391, auth_provider.py:488 (tenantin päättely sähköpostista) |
list_saas_users(customer_id) |
Tenantin käyttäjähallinta (ei näytteessä) | auth_provider.py:402, auth_provider.py:500 (roolin päättely); account_data.py:19 |
cancel_stripe_subscription_for_tenant, delete_saas_tenant_account |
Laskutusportaali ja tilauksen lopetus (ei näytteessä) | account_data.py:19 (tilin poisto) |
provision_saas_tenant, update_saas_subscription, verify_stripe_signature, find_customer_config_by_stripe_customer_id |
Provisiointi (ei näytteessä), Tilan päivitys (ei näytteessä) | stripe_webhook/handler.py:22 |
normalize_customer_features, normalize_customer_compliance, is_feature_enabled, get_required_feature_for_mode |
Tuoteominaisuuksien ratkaisu (ei näytteessä) | handler.py:22, handler_api.py:65, auth_provider.py:43, compliance_controls.py:9, document_templates.py:17 |
feature_flags.py on moduulin eniten kutsuttu osa ja käytännössä jokaisen
pyynnön polulla.
Dokumentit
- Prosessit: Itsepalvelutilauksen aloitus (ei näytteessä) · Stripe-tapahtuman käsittely · Tenantin provisiointi (ei näytteessä) · Tilin aktivointi (ei näytteessä) · Tilauksen tilan päivitys (ei näytteessä) · Tilauksen täsmäytys Stripestä · Tenantin käyttäjähallinta (ei näytteessä) · Laskutusportaali ja tilauksen lopetus (ei näytteessä) · Tuoteominaisuuksien ratkaisu (ei näytteessä)
- Datavirrat: Stripe-tapahtumasta tuoteoikeuksiksi · Ilmoittautumisesta aktivoituun tiliin (ei näytteessä)
- Datarakenteet: Tenantin saas-lohko (ei näytteessä) · Tuoteominaisuudet ja compliance (ei näytteessä) · SaaS-käyttäjätietue ja sähköpostihakemisto (ei näytteessä) · Stripe-tapahtumalukko
- Datamallit (jaetut): Tenanttikonfiguraatio (ei näytteessä)
- Liiketoimintaprosessit: Cloud-tilauksen elinkaari
- Järjestelmäprosessit: ei vielä kuvattu
Koodin kartta
Kolme tiedostoa, 1 808 riviä. Rajaus on tila/rekisteri.yaml:n
tiedostot-listassa — hakemistossa backend/lambdas/generate/ on 40 muuta versioitua
Python-tiedostoa, jotka kuuluvat yhteentoista muuhun moduuliin.
| Tiedosto | Rivejä | Vastuu |
|---|---|---|
backend/lambdas/generate/saas_onboarding.py |
1 405 | Kaikki elinkaarisäännöt: checkout, aktivointitoken, Cognito-käyttäjät, sähköpostihakemisto, provisiointi, tilan päivitys, täsmäytys, portaali, lopetus, poisto |
backend/lambdas/stripe_webhook/handler.py |
266 | Webhookin vastaanotto: allekirjoitus, idempotenssi, tapahtumatyypin haarautus, DLQ |
backend/lambdas/generate/feature_flags.py |
137 | Konfiguraatiosta tuoteoikeuksiksi: kaksi normalisointifunktiota ja moodikuvaus |
Riippuvuudet ovat yksisuuntaisia: webhook-lambda importoi
saas_onboardingin sys.path-tempulla (stripe_webhook/handler.py:17–20,
koska se on eri hakemistossa mutta samassa deployattavassa paketissa —
CodeUri: ../backend/lambdas/). saas_onboarding ei importoi
feature_flagsia, vaan kirjoittaa features-lohkon suoraan sanakirjana. Sama
lippujoukko on siis määritelty kahdessa paikassa: feature_flags.DEFAULT_FEATURES
(14 lippua) ja build_tenant_configin oletukset (14 lippua) — arvot poikkeavat
tarkoituksella, ks. Tuoteominaisuuksien ratkaisu, vaihe 1 (ei näytteessä).
flowchart TD
S["Stripe"] -->|webhook| WH["stripe_webhook/handler.py"]
WH --> ONB["saas_onboarding.py"]
API["handler_api.py<br/>6 reittiä"] --> ONB
AUTH["auth_provider.py<br/>kirjautuminen"] --> ONB
ACC["account_data.py<br/>tilin poisto"] --> ONB
SCR["operointiskriptit"] --> ONB
ONB -->|"REST"| S
ONB -->|"boto3"| COG["Cognito"]
ONB --> CFG["config.json<br/>objektitallennus"]
CFG --> FF["feature_flags.py"]
FF --> ALL["kaikki pyyntöpolut<br/>portitus"]
Ajaminen ja testaus
- Testit:
cd backend && python -m pytest tests/test_saas_onboarding.py tests/test_stripe_webhook_idempotency.py tests/test_feature_flags.py -v(45 + 5 + 4 testiä). Osa moduulin käytöksestä testataan myöstests/test_auth_surfaces.py:ssä (täsmäytys kirjautumisessa, roolikartta). - Koko testijoukko:
cd backend && python -m pytest tests/ -v - Build:
cd frontend && npm run build(ajaa trust-benchmarkit ensin)
Testikattavuus on epätasainen. test_saas_onboarding.py on 1 878 riviä ja
kattaa checkout-portit, elinkaarikentät, täsmäytyksen tilausvalinnan,
aktivoinnin uusinnan ja käyttäjähallinnan hyvin. Kattamatta jäävät:
provision_saas_tenant päästä päähän (mockattu joka testissä),
delete_saas_tenant_accountin virhepolut ja ensure_tenant_bucketin
kovennusasetukset (vain CORS testataan).
Havainnot, jotka kannattaa tietää ennen muutoksia
Kuusi asiaa, jotka on todennettu koodista ja jotka vaikuttavat muutoksen suunnitteluun. Ensimmäiset kolme ovat toiminnallisia puutteita, kolme viimeistä suunnitteluvalintoja, joiden seuraukset yllättävät.
- Webhook-lambdalta puuttuu Cognito-oikeus → jokainen itsepalveluosto
päätyy DLQ:hun vaikka tenantti syntyy.
Provisiointi, vaihe 5 (ei näytteessä).
> TODO: varmistettava ajossa. - Poiston
continue-ketju jättää sähköpostihakemistoja orvoiksi, ja orpo hakemisto estää saman osoitteen käytön uudelleen. Laskurit eivät paljasta epäonnistumista. Laskutusportaali ja lopetus, virhetilanteet (ei näytteessä). config["features"]indeksoidaan ilman tarkistusta (saas_onboarding.py:1236) →features-lohkoton konfiguraatio kaataa jokaisen laskutustapahtuman. Tilan päivitys, virhetilanteet (ei näytteessä).- Aktivointitokenin allekirjoitusavaimella on koodiin kirjoitettu
varafallback (
saas_onboarding.py:176). SAM-asennuksessaAUTH_SECRETon aina asetettu, mutta muissa asennuksissa tokeneita voi väärentää. Itsepalvelutilauksen aloitus, vaihe 4 (ei näytteessä). - Provisiointi ylikirjoittaa koko konfiguraation.
checkout.session.completed-tapahtuman uusinta pyyhkii tenantin lähdekatalogin, lähderyhmät ja compliance-asetukset oletuksiin. Provisiointi, yhteenveto (ei näytteessä). - Armonaika ei ole automaatio —
scheduled_deletion_aton merkintä, jonka toteuttaa vain käsin ajettava skripti. Laskutusportaali ja lopetus, vaihe 5 (ei näytteessä).
Lisäksi kaksi kuollutta kohtaa: is_stripe_billing_enabled
(saas_onboarding.py:605) ja is_review_required_for_mode
(feature_flags.py:124) — kummallakaan ei ole kutsujaa, ei myöskään testeissä.
Avoimet kysymykset
> TODO: varmistettava ajossa— havainto 1 (Cognito-oikeus webhook-lambdalla). Pääteltävissä SAM-mallista, mutta ei todennettu ajamalla.> TODO: substanssiosaajan vahvistus— onko hyväksytyn käyttöehtoversion tallentaminen vaatimus? Nytaccepted_terms_versionkatoaa.> TODO: substanssiosaajan vahvistus— onko haluttu, että maksuhäiriö (past_due) sulkee myös laskutusportaalin?> TODO: varmistettava— täsmäytyksen kaksinkertainen tallennus (saas_onboarding.py:1331–1334): onko toisellasave_customer_configilla tarkoitus, jota koodista ei näe?> TODO: varmistettava— tenanttikonfiguraationuse_mode- jadescription-kentille ei löytynyt lukijaa koodista.